Deep drift audit of the puter.js SDK comparing implementation vs TypeScript types vs documentation. Each finding is reproducible against commit 900b0d7aa6e5af730883b4823da438e1862082a1 (branch claude/exciting-lamport-y8p7nv).
Legend: 🟡 types (impl/docs have it, types don't/wrong) · 🔵 docs (impl/types have it, docs don't/wrong) · 🔴 both · 🐛 impl-bug (code fix, type/doc advertises something impl ignores OR phantom method) · 🆕/🗑 manifest-drift.
Step 0 — manifest tripwire: Disk file set matches the Expected manifest exactly. No 🆕/🗑 manifest-drift (no added/removed modules, types, FS ops, networking, UI components, or doc pages).
AI
| Function |
Item |
Issue |
Tag |
impl ref |
| chat |
option provider |
Impl reads userParams.provider→requestParams.provider, but ChatOptions has no provider field and chat.md never documents it. |
🔴 both |
AI.js:800-802 |
| chat |
option driver |
Typed but undocumented in chat.md. |
🔵 docs |
AI.js:812-814 |
| chat |
option image_config |
Documented + forwarded by impl, missing from ChatOptions. |
🟡 types |
AI.js:817 |
| chat |
option text_verbosity alias |
Docs advertise text/text_verbosity, impl only reads text and a separate verbosity key — text_verbosity never read. |
🐛 impl-bug |
AI.js:817 |
| chat |
option verbosity |
Impl reads + typed; chat.md only mentions text_verbosity. |
🔵 docs |
AI.js:817 |
| chat |
option response |
Forwarded + typed; not documented. |
🔵 docs |
AI.js:817 |
| txt2img |
option service |
Txt2ImgOptions.service declared in types but impl never reads it (phantom). |
🐛 impl-bug |
AI.js:907-913 |
| txt2img |
model aliases nano-banana/nano-banana-pro |
Impl rewrites these to Gemini model ids; not documented or typed as accepted values. |
🔴 both |
AI.js:898-905 |
| txt2img |
option driver |
Read + typed; undocumented. |
🔵 docs |
AI.js:907-910 |
| txt2img |
option input_images |
Documented (array) but Txt2ImgOptions only has input_image. |
🟡 types |
AI.js (passthrough) |
| txt2vid |
option driver |
Read + typed; undocumented. |
🔵 docs |
AI.js:986-990 |
| txt2vid |
option duration alias |
Mapped to seconds, typed; undocumented. |
🔵 docs |
AI.js:977-979 |
| txt2vid |
options input_reference (String)/last_frame |
Docs (Veo) document String input_reference + last_frame; types declare only input_reference?: File, no last_frame. |
🟡 types |
AI.js:996 |
| speech2speech |
aliases voiceId/modelId/outputFormat/voiceSettings/fileFormat/removeBackgroundNoise/optimizeStreamingLatency/enableLogging (+ snake voice_id/model_id) |
Impl normalizes 9 camelCase→snake aliases; none in types or docs (one docs example even uses removeBackgroundNoise). |
🔴 both |
AI.js:416-429 |
| speech2txt |
stream: true rejection |
Docs say stream is rejected when true; impl has no guard, passes it through. |
🐛 impl-bug |
AI.js:584 |
| speech2txt |
provider aliases grok/x-ai |
Mapped to xai-speech2txt; undocumented. |
🔵 docs |
AI.js:575-580 |
| speech2txt |
string-shorthand return |
Docs say shorthand source returns a string; impl returns string only when response_format==='text'. |
🐛 impl-bug |
AI.js:587-591 |
| txt2speech |
engine→provider inference |
Impl infers provider from engine; undocumented, engine typed as plain string. |
🔵 docs |
AI.js:268-282 |
| txt2speech |
alias response_format→output_format (elevenlabs) |
Undocumented mapping. |
🔵 docs |
AI.js:311-313 |
| txt2speech |
MAX_INPUT_SIZE |
Impl hard-caps 3000 chars for all providers; xAI docs claim "15,000 characters". |
🐛 impl-bug |
AI.js:206,353 |
| txt2speech |
provider aliases (eleven/11labs/google/grok/polly/aws…) |
normalizeTTSProvider accepts many aliases; docs list only canonical names. |
🔵 docs |
AI.js:4-15 |
| txt2speech.listEngines |
method declaration |
Exists in impl + docs; entirely absent from ai.d.ts. |
🟡 types |
AI.js:601-640 |
| txt2speech.listVoices |
method declaration |
Exists in impl + docs; entirely absent from ai.d.ts. |
🟡 types |
AI.js:647-689 |
| img2txt |
nested { source: Blob } shape |
Supported by impl; undocumented + untyped. |
🔴 both |
AI.js:158-161 |
| img2txt |
10 MB data-URI limit |
Enforced by impl; undocumented. |
🔵 docs |
AI.js:109,165 |
| ChatResponse |
field choices |
Interface has choices?; chatresponse.md doesn't list it. |
🔵 docs |
ai.d.ts:34 |
| ChatResponse |
message.images/thoughtSignature |
Documented in chat.md (Gemini image gen); absent from chatresponse.md + ChatMessage. |
🔴 both |
chat.md:211-226 |
| ChatResponseChunk |
field reasoning |
Interface has it; chatresponsechunk.md only documents text. |
🔵 docs |
ai.d.ts:39 |
| ChatResponseChunk |
streaming fields type/image/tool_use |
Used in chat.md streaming examples; absent from interface + chatresponsechunk.md. |
🔴 both |
chat.md:255-272 |
| ToolCall |
field type |
chat.md tool-call results include type:"function"; absent from ToolCall + toolcall.md. |
🔴 both |
ai.d.ts:9-12 |
| Speech2TxtResult |
fields duration/words |
xAI example reads them; absent from interface + speech2txtresult.md. |
🔴 both |
speech2txt.md:128-133 |
Apps
| Function |
Item |
Issue |
Tag |
impl ref |
| App (object) |
users() method |
Impl attaches + documented; absent from App interface. |
🟡 types |
Apps.js:24 |
| App (object) |
getUsers() method |
Impl attaches + documented; absent from App interface. |
🟡 types |
Apps.js:20 |
| checkName |
method |
Impl + types have it; no doc page / not in Apps.md. |
🔵 docs |
Apps.js:206 |
| getDeveloperProfile |
method |
Impl + types have it; no doc page / not in Apps.md. |
🔵 docs |
Apps.js:232 |
Auth
| Function |
Item |
Issue |
Tag |
impl ref |
| whoami |
method |
Impl + types have it; no doc page (only getUser documented). |
🔵 docs |
Auth.js:211 |
| getGlobalUsage |
method |
Impl has it; missing from types AND docs. |
🔴 both |
Auth.js:338 |
| getUser |
callback overload |
Impl accepts positional (success, error); types only declare options-object form. |
🟡 types |
Auth.js:187-195 |
| User (object) |
feature_flags / hasDevAccountAccess / otp |
Typed; not in user.md. |
🔵 docs |
auth.d.ts:8-11 |
Perms
The entire documented + implemented request* family (16 methods) is absent from perms.d.ts — TS users get zero typing for the primary documented Perms surface.
| Function |
Item |
Issue |
Tag |
impl ref |
| request, requestEmail, requestRead{Desktop,Documents,Pictures,Videos,Apps,Subdomains}, requestWrite{Desktop,Documents,Pictures,Videos}, requestManage{Apps,Subdomains} |
method |
Impl + docs have all; all missing from types. |
🟡 types |
Perms.js:133-316 |
| requestReadAppRootDir / requestWriteAppRootDir |
method |
Impl only; missing from types AND docs. |
🔴 both |
Perms.js:333,346 |
| grant*/revoke*/group mgmt |
methods |
Present in impl + types; none documented. |
🔵 docs |
Perms.js:37-118 |
| #requestAppRootDir |
access hardcoded |
Fetch body hardcodes access:'read', so requestWriteAppRootDir requests read access. |
🐛 impl-bug |
Perms.js:361 |
| #requestAppRootDir |
undefined var app_or_uuid |
References app_or_uuid (never defined; should be app_uid) → ReferenceError on error path. |
🐛 impl-bug |
Perms.js:367 |
| #requestAppRootDir |
typo |
Error message 'must be a strinkg'. |
🐛 impl-bug |
Perms.js:355 |
FileSystem (FS)
| Function |
Item |
Issue |
Tag |
impl ref |
| readdirSubdomains |
method |
Public method; absent from types AND docs. |
🔴 both |
readdirSubdomains.js:11 |
| revokeReadURL |
method |
Public method; absent from types AND docs. |
🔴 both |
revokeReadUrl.js:10 |
| sign |
method |
Typed; no FS/sign.md. |
🔵 docs |
sign.js:15 |
| space |
namespace |
space.md example calls puter.space(); method is puter.fs.space() (no top-level alias). |
🔵 docs |
space.js:3 |
| getReadURL |
expiresIn units |
Default is string '24h' (typed correctly); docs say expiresIn (Number) = milliseconds. |
🔵 docs |
getReadUrl.js:4,32 |
| copy |
newMetadata/createMissingParents/excludeSocketID |
Read + typed; undocumented. |
🔵 docs |
copy.js:17-19 |
| copy |
dedupeName dropped in positional form |
copy(src,dst,{dedupeName}) never extracts dedupeName/dedupe_name from args[2] → silently dropped. |
🐛 impl-bug |
copy.js:12-23,56 |
| move |
dedupeName phantom |
Docs list dedupeName; move.js never reads/sends dedupe_name. |
🐛 impl-bug |
move.js:48-66 |
| move |
newName/newMetadata/excludeSocketID |
Read + typed; undocumented. |
🔵 docs |
move.js:17-20 |
| mkdir |
rename/recursive aliases, shortcutTo |
Read + typed; undocumented in mkdir.md. |
🔵 docs |
mkdir.js:51-54 |
| delete |
descendants_only snake alias |
Read by impl; only descendantsOnly typed/documented. |
🔴 both |
deleteFSEntry.js:55 |
| read |
cache option |
Read by impl; missing from types AND docs. |
🔴 both |
read.js:46 |
| readdir |
no_subdomains |
Sent by impl; types declare only no_thumbs/no_assocs; docs mention none. |
🔴 both |
readdir.js:59,128 |
| readdir |
consistency |
Supported + typed; undocumented. |
🔵 docs |
readdir.js:29 |
| stat |
returnWorkers alias |
Read by impl (alias of returnSubdomains); missing from types AND docs. |
🔴 both |
stat.js:54,126 |
| upload |
generateThumbnails/thumbnailGenerator/thumbnail |
Read by impl; missing from types; docs list only overwrite/dedupeName/createMissingParents. |
🔴 both |
upload.js:571-573 |
| upload |
progress events (init/start/progress/abort) |
Fired by impl + typed; undocumented. |
🔵 docs |
upload.js:405,632,667,757 |
| upload |
dedupeName default |
Impl defaults true when not overwriting; docs say false. |
🔵 docs |
upload.js:735 |
| FSItem |
is_dir/parent_id/parent_uid/writable |
fsitem.md documents these; impl exposes isDirectory and has none of the others (types correct). |
🔵 docs |
FSItem.js:17 |
| FSItem |
readURL/writeURL/metadataURL |
Impl + types expose; fsitem.md documents none. |
🔵 docs |
FSItem.js:5-7 |
| FSItem.move |
boolean overwrite ignored |
FSItem.move(dest, overwrite, new_name) forwards boolean to fs.move which reads args[2]?.overwrite (expects object) → ignored. |
🐛 impl-bug |
FSItem.js:89; move.js:13 |
| FSItem.copy |
auto_rename/overwrite ignored |
Same positional/object mismatch with fs.copy. |
🐛 impl-bug |
FSItem.js:93; copy.js:12-23 |
KV
| Function |
Item |
Issue |
Tag |
impl ref |
| MAX_VALUE_SIZE |
constant value |
Impl is 399*1024 (~399KB); set.md states 400 KB. |
🔵 docs |
KV.js:36 |
| MAX_VALUE_SIZE/MAX_KEY_SIZE |
units |
Docs say "in bytes"; impl compares .length (char/element count). |
🔵 docs |
KV.js:208,36 |
| get |
missing-key return |
Impl + types resolve undefined; get.md says null. |
🔵 docs |
KV.js:284,288 |
| set |
batch overload |
Impl supports set([{key,value,expireAt}…]) / set({items:[…]}); no batch overload in types or docs. |
🔴 both |
KV.js:124-155 |
| set |
optConfig arg / null expireAt |
set.md never documents optConfig; impl also accepts expireAt===null (typed as number). |
🔵 docs / 🟡 types |
KV.js:166,174-176 |
| add |
default value |
Impl defaults value to 1; add.md never states the default. |
🔵 docs |
KV.js:386 |
| add/incr/decr/del/remove/update/expire/expireAt/list |
optConfig |
Accepted by impl + typed; undocumented across these methods. |
🔵 docs |
KV.js (per method) |
| flush |
clear alias |
Impl + types expose clear; never documented. |
🔵 docs |
KV.js:676 |
Hosting
| Function |
Item |
Issue |
Tag |
impl ref |
| list |
workers filter |
Impl filters out workers.puter.* subdomains; undocumented. |
🔵 docs |
Hosting.js:44 |
| create |
root_dir not absolutized in object form |
Object form create({subdomain,root_dir}) skips getAbsolutePathForApp that the positional dirPath form applies. |
🐛 impl-bug |
Hosting.js:76-77 |
| create/update/get/delete |
*.puter.(site|com) stripping |
Impl strips full domain to bare subdomain; undocumented. |
🔵 docs |
Hosting.js:90,113,129 |
| update (example) |
broken sample |
Cleanup references undefined updatedSite in Hosting.md + Hosting/update.md. |
🔵 docs |
Hosting.md:147 |
Workers
| Function |
Item |
Issue |
Tag |
impl ref |
| create |
3rd param appName |
Impl accepts an options object with sandbox boolean; types declare only appName?: string. |
🟡 types |
Workers.js:21-24 |
| create |
3rd param |
Docs syntax lists only (workerName, filePath) — entire 3rd param undocumented. |
🔵 docs |
Workers.js:10,37 |
| getLoggingHandle |
method |
Impl + types have it; completely undocumented. |
🔵 docs |
Workers.js:137 |
| getLoggingHandle |
start/cancel on returned stream |
Typed handle omits start/cancel (only close typed). |
🟡 types |
Workers.js:146-174 |
| delete |
dead new Error |
new Error("Worker doesn't exist") constructed without throw. |
🐛 impl-bug |
Workers.js:121 |
Peer
| Function |
Item |
Issue |
Tag |
impl ref |
| PuterPeerConnectionErrorEvent |
error payload type |
Impl sets .error to an Error object; types declare error: string (doc example reads event.error?.message). |
🔴 both |
Peer.js:211,306 |
| PuterPeerServer |
message phantom method |
Types declare public message(data); impl has only private #message. |
🐛 impl-bug |
Peer.js:104 |
| PuterPeerConnection.setRemoteDescription |
return |
Impl async (Promise); types declare void. |
🟡 types |
Peer.js:326 |
| PuterPeerConnection.addIceCandidate |
return |
Impl async (Promise); types declare void. |
🟡 types |
Peer.js:330 |
Networking
| Function |
Item |
Issue |
Tag |
impl ref |
| PSocket/PTLSSocket |
'drain' event |
Declared in types + SocketEvent, but never emitted by impl. |
🟡 types |
PSocket.js:16; networking.d.ts:6 |
PSocket on('error') |
payload type |
Impl emits an Error object; types + docs say string. |
🔴 both |
PSocket.js:52 |
PTLSSocket on('error') |
payload type |
Impl emits raw Error objects; types + docs say string. |
🔴 both |
PTLS.js:67,86 |
PTLSSocket on |
tls* event overloads |
Impl accepts tlsopen/tlsdata/tlsclose (docs tell users to use them); PTLSSocket adds no on overloads — TLS usage untyped. |
🟡 types |
PTLS.js:92-98 |
PTLSSocket on |
bare event remapping |
Impl silently remaps open/data/close to tls*; undocumented. |
🔵 docs |
PTLS.js:92-98 |
| puter.net.generateWispV1URL |
method |
Public on puter.net (impl + type); documented nowhere. |
🔵 docs |
index.js:627 |
| PSocket.write |
ArrayBuffer branch |
else if (data.resize) calls data.write(...) (not a method on ArrayBuffer) → throws despite docs/types accepting ArrayBuffer. |
🐛 impl-bug |
PSocket.js:74-75 |
| PWispHandler._continue |
missing streamID |
Called with no arg from PSocket → undefined.queue throws; breaks backpressure drain. |
🐛 impl-bug |
PWispHandler.js:31,51-52 |
| PWispHandler setup |
reconnect timer |
setTimeout(setup(), 1000) invokes immediately + passes undefined; reconnect broken. |
🐛 impl-bug |
PWispHandler.js:23 |
UI
| Function |
Item |
Issue |
Tag |
impl ref |
| exit |
phantom method on UI |
Types declare UI.exit(), but exit lives on the Puter class — puter.ui.exit() doesn't exist. |
🐛 impl-bug |
index.js:1040 |
| exit |
wrong namespace in UI.md |
UI.md lists puter.ui.exit(); correct is puter.exit(). |
🔵 docs |
UI.md:36 |
| on / events |
connection event |
Impl emits 'connection' with {conn,accept,reject}; absent from on() types AND docs. |
🔴 both |
UI.js:251,546-571 |
| showColorPicker |
defaultValue/default aliases |
Impl fallback accepts both; absent from types + docs. |
🔴 both |
UI.js:884 |
| showFontPicker |
default alias |
Impl fallback accepts it; absent from types + docs. |
🔴 both |
UI.js:866 |
| showSaveFilePicker |
3rd param type |
Impl (content, suggestedName, type) selects url/move/copy; omitted from types AND docs. |
🔴 both |
UI.js:898,906-910 |
| showDirectoryPicker |
accept option |
IPC reads options.accept; only multiple typed/documented. |
🔴 both |
IPC.js:567-570 |
| setMenubar/menu item ops |
disableMenuItem/enableMenuItem |
In impl; absent from types AND docs (sibling setMenuItem* are typed but undocumented). |
🔴 both |
UI.js:1113-1119 |
| socialShare |
return type |
Impl returns a Promise; types declare void, docs have no Return section. |
🔴 both |
UI.js:728-732 |
| socialShare |
default left/top |
Docs say default 0; impl defaults to window top-left. |
🔵 docs |
IPC.js:334-343 |
| prompt |
cancel sentinel (standalone) |
Standalone PuterPrompt resolves false on cancel; docs/types say null. |
🐛 impl-bug |
PuterPrompt.js:187,197,205 |
| prompt |
options.defaultValue |
IPC reads it + typed; prompt.md omits the options arg. |
🔵 docs |
IPC.js:253 |
| alert |
return type |
Impl default button returns boolean true; types declare Promise<string>. |
🟡 types |
PuterAlert.js:166 |
| launchApp |
file_paths/items/pseudonym/callback/app_name alias/#(as) syntax |
Read + typed; launchApp.md documents only name+args. |
🔵 docs |
UI.js:1299-1320 |
| parentApp |
gui return |
Returns undefined (not null) in gui env. |
🟡 types |
UI.js:264-266,1357 |
| requestUpgrade |
doc page |
In impl + types; no doc page. |
🔵 docs |
UI.js:892 |
| notify |
type/duration |
Standalone component renders type/duration; missing from NotificationOptions + notify.md (GUI path ignores). |
🔵 docs / 🟡 types |
PuterNotification.js:208,256 |
| toggleWindow/instancesOpen/connectToInstance/requestEmailConfirmation/openDevPaymentsAccount |
methods |
In impl; absent from types + docs (mostly internal; toggleWindow plausibly public). |
🟡 types |
UI.js:692,716,722,1086,1342 |
Utils
| Function |
Item |
Issue |
Tag |
impl ref |
| puter.on / puter.off |
methods |
Public event API (gate puter.auth.reauth_required); absent from puter.d.ts + docs. |
🔴 both |
index.js:972,979 |
| puter.auth.reauth_required |
event |
Emitted {reason,auth_id}; no type surface, undocumented. |
🔴 both |
index.js:846,950-957 |
| print |
option escapeHTML |
Supported by impl + typed; docs document only code. |
🔵 docs |
index.js:1258,1267 |
| env |
enum completeness |
Impl/types also have web-worker/service-worker/nodejs; docs list only app/web/gui. |
🔵 docs |
index.js:357-389 |
| getUser |
positional callbacks |
Impl accepts (success, error); types only model options-object form. |
🟡 types |
index.js:1217-1229 |
| quiet |
property |
puter.quiet toggle (referenced in console); missing from puter.d.ts. |
🟡 types |
index.js:173,1400 |
| exit |
doc page |
Public method; not in Utils.md. |
🔵 docs |
index.js:1040 |
| appName |
doc page |
Typed property; not in Utils.md. |
🔵 docs |
index.js:445 |
Drivers
| Function |
Item |
Issue |
Tag |
impl ref |
| call |
2-arg overload |
Impl supports call(iface, parameters) (method defaults to iface); types declare only 3/4-arg. |
🟡 types |
Drivers.js:262-265 |
| Drivers |
constructor signature |
Impl ctor is constructor(puter); types declare constructor(context:{authToken?;APIOrigin;appID?}). |
🟡 types |
Drivers.js:135 |
OS
| Function |
Item |
Issue |
Tag |
impl ref |
| user / version |
positional callbacks |
Impl accepts variadic (success, error); types model only options-object form. |
🟡 types |
OS.js:41-53,70-83 |
(a) Highest-impact shortlist
- Perms types are essentially empty for the public surface — all 16 documented
request* methods are missing from perms.d.ts. (🟡)
requestWriteAppRootDir is broken — hardcodes access:'read' and the error path throws a ReferenceError (app_or_uuid undefined). (🐛)
puter.ui.exit() is a phantom — typed on UI but only exists on the Puter class; runtime call fails. (🐛)
- UI
'connection' event is emitted by impl but absent from both on() types and docs. (🔴)
- Networking
error payload is an Error object everywhere but typed/documented as string; PTLSSocket has no typed on overloads for its tls* events. (🔴/🟡)
- Peer
error payload typed as string but is an Error; PuterPeerServer.message is a phantom public method. (🔴/🐛)
puter.on/off + auth.reauth_required event — real public reauth API with zero type/doc coverage. (🔴)
- AI alias/param drift — chat
provider undocumented+untyped; 9 speech2speech camelCase aliases in neither types nor docs; streaming ChatResponseChunk shape (type/image/tool_use) and ToolCall.type used in docs examples but missing from interfaces + Object docs.
- KV
MAX_VALUE_SIZE docs say "400 KB" vs impl 399*1024; get missing-key returns undefined not the documented null; batch set overload undocumented + untyped.
- FS positional-vs-object arg bugs —
copy(src,dst,{dedupeName}), FSItem.move/FSItem.copy boolean positionals silently dropped; move docs advertise a dedupeName it never sends.
(b) 🐛 impl-bug bucket (code fixes, not doc/type edits)
| Family |
Location |
Bug |
| AI |
AI.js:817 |
chat text_verbosity advertised but never read |
| AI |
AI.js:907-913 |
txt2img service typed but never read (phantom) |
| AI |
AI.js:584 |
speech2txt stream:true documented as rejected but passed through |
| AI |
AI.js:587-591 |
speech2txt shorthand documented to return string; only does when response_format==='text' |
| AI |
AI.js:206,353 |
txt2speech xAI "15,000 char" limit contradicted by hard 3000-char cap |
| Perms |
Perms.js:361 |
requestWriteAppRootDir hardcodes access:'read' |
| Perms |
Perms.js:367 |
undefined app_or_uuid → ReferenceError |
| Perms |
Perms.js:355 |
typo "strinkg" in error message |
| FS |
copy.js:12-23,56 |
copy(src,dst,{dedupeName}) drops dedupeName in positional form |
| FS |
move.js:48-66 |
docs advertise dedupeName move never sends |
| FS |
FSItem.js:89; move.js:13 |
FSItem.move boolean overwrite ignored (object expected) |
| FS |
FSItem.js:93; copy.js:12-23 |
FSItem.copy auto_rename/overwrite ignored |
| Hosting |
Hosting.js:76-77 |
object-form create({root_dir}) skips getAbsolutePathForApp |
| Workers |
Workers.js:121 |
dead new Error("Worker doesn't exist") never thrown |
| Peer |
Peer.js:104 |
PuterPeerServer.message phantom (only private #message) |
| Networking |
PSocket.js:74-75 |
ArrayBuffer branch calls data.write (not an ArrayBuffer method) |
| Networking |
PWispHandler.js:31,51-52 |
_continue() called with no streamID → throws |
| Networking |
PWispHandler.js:23 |
setTimeout(setup(), 1000) invokes immediately; reconnect broken |
| UI |
index.js:1040 |
puter.ui.exit() phantom (exit is on Puter class) |
| UI |
PuterPrompt.js:187,197,205 |
standalone prompt cancel resolves false, not documented null |
(c) 🆕/🗑 manifest-drift
None. Disk file set matches the Expected manifest exactly across modules, FS operations, networking, UI components, types, and docs.
Deep drift audit of the puter.js SDK comparing implementation vs TypeScript types vs documentation. Each finding is reproducible against commit
900b0d7aa6e5af730883b4823da438e1862082a1(branchclaude/exciting-lamport-y8p7nv).Legend: 🟡 types (impl/docs have it, types don't/wrong) · 🔵 docs (impl/types have it, docs don't/wrong) · 🔴 both · 🐛 impl-bug (code fix, type/doc advertises something impl ignores OR phantom method) · 🆕/🗑 manifest-drift.
Step 0 — manifest tripwire: Disk file set matches the Expected manifest exactly. No 🆕/🗑 manifest-drift (no added/removed modules, types, FS ops, networking, UI components, or doc pages).
AI
provideruserParams.provider→requestParams.provider, butChatOptionshas noproviderfield and chat.md never documents it.driverimage_configChatOptions.text_verbosityaliastext/text_verbosity, impl only readstextand a separateverbositykey —text_verbositynever read.verbositytext_verbosity.responseserviceTxt2ImgOptions.servicedeclared in types but impl never reads it (phantom).nano-banana/nano-banana-prodriverinput_imagesTxt2ImgOptionsonly hasinput_image.driverdurationaliasseconds, typed; undocumented.input_reference(String)/last_frameinput_reference+last_frame; types declare onlyinput_reference?: File, nolast_frame.voiceId/modelId/outputFormat/voiceSettings/fileFormat/removeBackgroundNoise/optimizeStreamingLatency/enableLogging(+ snakevoice_id/model_id)removeBackgroundNoise).stream: truerejectionstreamis rejected whentrue; impl has no guard, passes it through.grok/x-aixai-speech2txt; undocumented.sourcereturns a string; impl returns string only whenresponse_format==='text'.engine; undocumented,enginetyped as plain string.response_format→output_format(elevenlabs)eleven/11labs/google/grok/polly/aws…)normalizeTTSProvideraccepts many aliases; docs list only canonical names.ai.d.ts.ai.d.ts.{ source: Blob }shapechoiceschoices?; chatresponse.md doesn't list it.message.images/thoughtSignatureChatMessage.reasoningtext.type/image/tool_usetypetype:"function"; absent fromToolCall+ toolcall.md.duration/wordsApps
users()methodAppinterface.getUsers()methodAppinterface.Auth
(success, error); types only declare options-object form.feature_flags/hasDevAccountAccess/otpPerms
The entire documented + implemented
request*family (16 methods) is absent fromperms.d.ts— TS users get zero typing for the primary documented Perms surface.accesshardcodedaccess:'read', sorequestWriteAppRootDirrequests read access.app_or_uuidapp_or_uuid(never defined; should beapp_uid) → ReferenceError on error path.'must be a strinkg'.FileSystem (FS)
puter.space(); method isputer.fs.space()(no top-level alias).expiresInunits'24h'(typed correctly); docs sayexpiresIn (Number)= milliseconds.newMetadata/createMissingParents/excludeSocketIDdedupeNamedropped in positional formcopy(src,dst,{dedupeName})never extractsdedupeName/dedupe_namefromargs[2]→ silently dropped.dedupeNamephantomdedupeName; move.js never reads/sendsdedupe_name.newName/newMetadata/excludeSocketIDrename/recursivealiases,shortcutTodescendants_onlysnake aliasdescendantsOnlytyped/documented.cacheoptionno_subdomainsno_thumbs/no_assocs; docs mention none.consistencyreturnWorkersaliasreturnSubdomains); missing from types AND docs.generateThumbnails/thumbnailGenerator/thumbnailinit/start/progress/abort)dedupeNamedefaulttruewhen not overwriting; docs sayfalse.is_dir/parent_id/parent_uid/writableisDirectoryand has none of the others (types correct).readURL/writeURL/metadataURLoverwriteignoredFSItem.move(dest, overwrite, new_name)forwards boolean tofs.movewhich readsargs[2]?.overwrite(expects object) → ignored.auto_rename/overwriteignoredfs.copy.KV
399*1024(~399KB); set.md states 400 KB..length(char/element count).undefined; get.md saysnull.set([{key,value,expireAt}…])/set({items:[…]}); no batch overload in types or docs.optConfigarg /nullexpireAtoptConfig; impl also acceptsexpireAt===null(typed asnumber).optConfigclearaliasclear; never documented.Hosting
workers.puter.*subdomains; undocumented.root_dirnot absolutized in object formcreate({subdomain,root_dir})skipsgetAbsolutePathForAppthat the positionaldirPathform applies.*.puter.(site|com)strippingupdatedSitein Hosting.md + Hosting/update.md.Workers
appNamesandboxboolean; types declare onlyappName?: string.(workerName, filePath)— entire 3rd param undocumented.start/cancelon returned streamstart/cancel(onlyclosetyped).new Errornew Error("Worker doesn't exist")constructed withoutthrow.Peer
errorpayload type.errorto anErrorobject; types declareerror: string(doc example readsevent.error?.message).messagephantom methodmessage(data); impl has only private#message.async(Promise); types declarevoid.async(Promise); types declarevoid.Networking
'drain'eventSocketEvent, but never emitted by impl.on('error')Errorobject; types + docs saystring.on('error')Errorobjects; types + docs saystring.ontls*event overloadstlsopen/tlsdata/tlsclose(docs tell users to use them);PTLSSocketadds noonoverloads — TLS usage untyped.onopen/data/closetotls*; undocumented.puter.net(impl + type); documented nowhere.else if (data.resize)callsdata.write(...)(not a method on ArrayBuffer) → throws despite docs/types accepting ArrayBuffer.undefined.queuethrows; breaks backpressure drain.setTimeout(setup(), 1000)invokes immediately + passesundefined; reconnect broken.UI
UI.exit(), butexitlives on thePuterclass —puter.ui.exit()doesn't exist.puter.ui.exit(); correct isputer.exit().connectionevent'connection'with{conn,accept,reject}; absent fromon()types AND docs.defaultValue/defaultaliasesdefaultaliastype(content, suggestedName, type)selects url/move/copy; omitted from types AND docs.acceptoptionoptions.accept; onlymultipletyped/documented.disableMenuItem/enableMenuItemsetMenuItem*are typed but undocumented).void, docs have no Return section.0; impl defaults to window top-left.falseon cancel; docs/types saynull.options.defaultValuetrue; types declarePromise<string>.file_paths/items/pseudonym/callback/app_namealias/#(as)syntaxname+args.undefined(notnull) in gui env.type/durationtype/duration; missing from NotificationOptions + notify.md (GUI path ignores).toggleWindowplausibly public).Utils
puter.auth.reauth_required); absent fromputer.d.ts+ docs.{reason,auth_id}; no type surface, undocumented.escapeHTMLcode.web-worker/service-worker/nodejs; docs list only app/web/gui.(success, error); types only model options-object form.puter.quiettoggle (referenced in console); missing fromputer.d.ts.Drivers
call(iface, parameters)(method defaults to iface); types declare only 3/4-arg.constructor(puter); types declareconstructor(context:{authToken?;APIOrigin;appID?}).OS
(success, error); types model only options-object form.(a) Highest-impact shortlist
request*methods are missing fromperms.d.ts. (🟡)requestWriteAppRootDiris broken — hardcodesaccess:'read'and the error path throws aReferenceError(app_or_uuidundefined). (🐛)puter.ui.exit()is a phantom — typed onUIbut only exists on thePuterclass; runtime call fails. (🐛)'connection'event is emitted by impl but absent from bothon()types and docs. (🔴)errorpayload is anErrorobject everywhere but typed/documented asstring;PTLSSockethas no typedonoverloads for itstls*events. (🔴/🟡)errorpayload typed asstringbut is anError;PuterPeerServer.messageis a phantom public method. (🔴/🐛)puter.on/off+auth.reauth_requiredevent — real public reauth API with zero type/doc coverage. (🔴)providerundocumented+untyped; 9 speech2speech camelCase aliases in neither types nor docs; streamingChatResponseChunkshape (type/image/tool_use) andToolCall.typeused in docs examples but missing from interfaces + Object docs.MAX_VALUE_SIZEdocs say "400 KB" vs impl399*1024;getmissing-key returnsundefinednot the documentednull; batchsetoverload undocumented + untyped.copy(src,dst,{dedupeName}),FSItem.move/FSItem.copyboolean positionals silently dropped;movedocs advertise adedupeNameit never sends.(b) 🐛 impl-bug bucket (code fixes, not doc/type edits)
text_verbosityadvertised but never readservicetyped but never read (phantom)stream:truedocumented as rejected but passed throughresponse_format==='text'requestWriteAppRootDirhardcodesaccess:'read'app_or_uuid→ ReferenceErrorcopy(src,dst,{dedupeName})drops dedupeName in positional formdedupeNamemove never sendsFSItem.movebooleanoverwriteignored (object expected)FSItem.copyauto_rename/overwriteignoredcreate({root_dir})skipsgetAbsolutePathForAppnew Error("Worker doesn't exist")never thrownPuterPeerServer.messagephantom (only private#message)data.write(not an ArrayBuffer method)_continue()called with no streamID → throwssetTimeout(setup(), 1000)invokes immediately; reconnect brokenputer.ui.exit()phantom (exit is on Puter class)false, not documentednull(c) 🆕/🗑 manifest-drift
None. Disk file set matches the Expected manifest exactly across modules, FS operations, networking, UI components, types, and docs.