Skip to content

Puter.js types and docs drift audit - 2026-06-08 #3221

@reynaldichernando

Description

@reynaldichernando

Deep audit of the puter.js SDK for TypeScript-types drift and documentation drift against the implementation. Every API family was re-derived from scratch (impl + types + docs read in full).

  • Commit pinned: 15134c99bf106e3e9a2ff6a69c80e3ab047c48bc (branch claude/exciting-lamport-gNnxk)
  • Sources of truth: impl src/puter-js/src/modules/ (+ src/puter-js/src/index.js, and src/gui/src/IPC.js for the UI family) · types src/puter-js/types/** · docs src/docs/src/**

Tag legend: 🟡 types (impl/docs have it, types don't/wrong) · 🔵 docs (impl/types have it, docs don't/wrong) · 🔴 both · 🐛 impl-bug (advertised-but-ignored param, or phantom method in types) · 🆕/🗑 manifest-drift.

Step 0 — manifest tripwire

Enumerated disk against the Expected manifest. No file-level manifest drift — every impl module, FS op, networking file, UI component, type file, and docs file present on disk is accounted for in the manifest, and every manifest entry exists on disk. (Disk is authority; it agreed with the manifest this run.)


AI

puter.ai wired via registerModule('ai', AI) (index.js:198).

Function Item Issue Tag impl ref
chat option provider impl forwards userParams.provider, but ChatOptions omits it and docs don't list it 🔴 AI.js:800-802,817
chat option image_config impl forwards it (PARAMS_TO_PASS); type omits; docs cover it 🟡 AI.js:817
chat option driver impl reads `provider = driver; typed; docs never document driver`
chat / ChatMessage tool_call_id used by impl+docs on tool-result messages; ChatMessage omits it 🟡 chat.md:142
chat / ChatMessage cache_control docs show it as message passthrough; ChatMessage omits it 🟡 chat.md:168
chat / ChatResponseChunk image / type streaming docs describe part.image/part.type; chunk type only has text?,reasoning? 🟡 chat.md:255-271
chat / ChatResponse message.images Gemini image-gen docs show message.images[]; not in types 🟡 chat.md:211-226
txt2speech enginemodel alias for openai/elevenlabs/gemini, engine coerced into model; not in docs/types 🔴 AI.js:285-317
txt2speech.listEngines / listVoices types neither method declared in ai.d.ts 🟡 AI.js:596-690
txt2speech MAX_INPUT_SIZE impl hard-caps 3000 chars for all providers; docs claim xAI "15,000 chars" (unreachable) 🔵/🐛 AI.js:206,353-355
img2txt MAX_INPUT_SIZE (10 MB) undocumented 🔵 AI.js:109
speech2speech camelCase aliases voiceId,modelId,outputFormat,voiceSettings,fileFormat,removeBackgroundNoise,optimizeStreamingLatency,enableLogging normalized by impl; types/docs only snake_case (docs even use removeBackgroundNoise in an example) 🔴 AI.js:414-438
speech2speech MAX_INPUT_SIZE (25 MB) undocumented 🔵 AI.js:402
speech2txt duration/words xAI docs read these; Speech2TxtResult only has text,language,segments 🟡 speech2txt.md:128-134
txt2img nano-banana/nano-banana-pro aliases impl rewrites to Gemini model ids; not in types/docs 🔴 AI.js:898-905
txt2img default service impl defaults to ai-image; JSDoc/@example claim a Gemini default model not applied 🔵 AI.js:897,911-913
txt2img input_image_mime_type/input_images docs reference them; input_image_mime_type missing from type 🟡 txt2img.md:60,106,196
txt2vid durationseconds alias impl maps it; docs only document seconds 🔵 AI.js:977-979
txt2vid last_frame Veo docs document it; not in type (input_reference/reference_images/frame_images are) 🟡 txt2vid.md:64
ToolCall type field docs/OpenAI convention include type:"function"; ToolCall + Objects/toolcall.md omit it 🔴 ai.d.ts:9-12
ChatResponse / chunk obj-docs choices/reasoning type has them; Objects/*.md omit 🔵 ai.d.ts:34,39

Apps

Function Item Issue Tag impl ref
list/get/create/update return decoration returned App is decorated with getUsers()/users() async-iterator (documented in app.md) but missing from the App type 🟡 Apps.js:43-48
get object-only overload get({...}) impl supports it; types only declare get(name, options?) 🟡 Apps.js:190-192
create title "(required)" doc marks required; impl defaults title = args[2] ?? args[0], type title? 🔵 Apps.js:90
delete return {success:true} doc overstates; type {success?:boolean}, impl returns raw driver result 🔵 Apps.js:203
checkName docs impl+types have it; no doc page / not in Apps.md 🔵 Apps.js:206
getDeveloperProfile docs impl+types have it; undocumented 🔵 Apps.js:232

Auth

Function Item Issue Tag impl ref
getGlobalUsage existence impl has it (/metering/globalUsage); missing from type AND docs 🔴 Auth.js:338
User email field requestEmail reads whoami.email, but User type AND user.md both omit email 🔴 Perms.js:154
getUser positional callbacks impl supports getUser(success, error); type only declares options form 🟡 Auth.js:187-195
whoami docs impl+type have it; no doc (internal-ish) 🔵 Auth.js:211
DetailedAppUsage index signature total:number + [key:string]:APIUsage is unsound TS 🟡 auth.d.ts:42

Perms

Function Item Issue Tag impl ref
ALL request* methods types perms.d.ts declares none of the 18+ documented request* methods (only grant/revoke/group plumbing) 🟡 Perms.js:123-348
requestReadAppRootDir / requestWriteAppRootDir existence impl has both (public); not in docs, not in Perms.md, not in types 🔴 Perms.js:333,346
grant*/revoke*/group methods docs typed+implemented; no doc pages 🔵 Perms.js:37-118

FileSystem (FS)

Function Item Issue Tag impl ref
read cache option impl reads options.cache; missing from ReadOptions type AND read doc 🔴 operations/read.js:46
readdir no_subdomains impl sends it; ReaddirOptions missing it (has no_thumbs,no_assocs); docs omit all three 🔴 operations/readdir.js:57-59
stat returnWorkers alias impl: `return_subdomains = returnSubdomains returnWorkers; type+docs only have returnSubdomains`
upload generateThumbnails/thumbnailGenerator/thumbnail impl reads all; missing from UploadOptions type AND docs 🔴 operations/upload.js:571,690,1313
upload progress/callback surface init/start/progress/abort/success/error typed but entirely undocumented 🔵 operations/upload.js:405
revokeReadURL existence public (index.js:44); not in FS type, no doc 🔴 operations/revokeReadUrl.js:10
readdirSubdomains existence public (index.js:46); not in FS type, no doc 🔴 operations/readdirSubdomains.js:11
sign docs public (index.js:42), typed; no doc page 🔵 operations/sign.js:87
move dedupeName doc lists it but impl never reads/sends dedupe for move (phantom doc option) 🔵 operations/move.js
copy createMissingParents/newMetadata impl reads+sends; docs omit (types ok) 🔵 operations/copy.js:17-18
mkdir rename/recursive aliases impl reads them; docs list only dedupeName/createMissingParents 🔵 operations/mkdir.js:51-54
readdir/stat consistency impl supports it; docs omit 🔵 operations/readdir.js:29
write ArrayBuffer/TypedArray data impl+type accept them; doc says String|File|Blob only 🔵 operations/write.js:48
getReadURL expiresIn impl default is string '24h', type string; doc wrongly says "milliseconds (Number)" 🔵 operations/getReadUrl.js:4
space doc example space.md example calls puter.space() instead of puter.fs.space() 🔵 operations/space.js
FSItem (obj-doc) parent_id/parent_uid/writable/is_dir fsitem.md documents fields the FSItem class never sets; real props are isDirectory,readURL,writeURL,metadataURL,uuid 🔴 FSItem.js:3-58

KV

Function Item Issue Tag impl ref
MAX_VALUE_SIZE constant impl 399*1024 (399 KB); set.md says 400 KB 🔵 KV.js:36
get null vs undefined get.md says missing key → null; impl+type resolve to undefined 🔵 KV.js:253
set batch overload set([{key,value}], …) / set({items}) real but absent from types AND set.md 🔴 KV.js:124
add default value=1 add(key) silently adds 1; undocumented in add.md 🔵 KV.js:386
clear alias clear = flush in types; no doc page / not in KV.md 🔵 KV.js:676

Workers

router.md/types.md describe the deployed-worker runtime (verified sane, not mapped to Workers.js).

Function Item Issue Tag impl ref
create 3rd param appName + sandbox impl accepts string (app-name lookup) OR {sandbox:false} object; type declares only appName?:string, docs omit the param entirely 🔴 Workers.js:10,21,24,37
getLoggingHandle docs public, in .d.ts; no doc page / not in Workers.md 🔵 Workers.js:137
exec x-puter-no-auth escape hatch suppresses auto puter-auth injection; undocumented 🔵 Workers.js:70,73
exec input type docs say workerURL (String) only; impl/type accept any RequestInfo/Request/URL 🔵 Workers.js:69

Hosting

Function Item Issue Tag impl ref
delete return type Promise<boolean> + docs say resolves true, but impl returns raw driver result (no coercion) 🔴 Hosting.js:135

Networking

Function Item Issue Tag impl ref
Socket / TLSSocket error payload type impl emits an Error object; type+docs say reason: (string) — every error handler example prints the wrong thing 🔴 PSocket.js:52; PTLS.js:67,86
Socket drain event never emitted registered + in SocketEvent union but never fired (dead event in public type) 🟡 PSocket.js:16
TLSSocket on() aliasing open/data/closetls* impl silently remaps; inherited open/data/close overloads misleading on TLS; undocumented 🔵 PTLS.js:92
generateWispV1URL docs typed + wired (index.js:627); undocumented (likely internal) 🔵 index.js:627

Peer

Function Item Issue Tag impl ref
PuterPeerServer.message phantom method type declares public message(); impl method is private #message (not callable) 🟡 Peer.js:104
PuterPeerConnectionErrorEvent.error type typed string, but impl stores an Error; docs read event.error?.message 🟡 Peer.js:35
setRemoteDescription / addIceCandidate return type impl asyncPromise<void>; type declares void (can't await per types) 🟡 Peer.js:326,330
PuterPeerConnectionMessageEvent.data type impl forwards string|ArrayBuffer|Blob; type omits Blob 🟡 Peer.js:13

UI (impl: UI.js + IPC.js)

Function Item Issue Tag impl ref
exit placement typed on UI class, but implemented on root puter (puter.exit); puter.ui.exit does not exist. UI.md also lists it as puter.ui.exit() 🐛/🔵 index.js:1031
broadcast / listenForBroadcast phantom methods declared on UI type; no implementation (use on(name, handler)) 🐛 ui.d.ts:195-196
FILE_SAVE_CANCELLED / FILE_OPEN_CANCELLED phantom getters typed instance getters; are module-private constants, no public getters 🐛 ui.d.ts:198-199
on connection event in #eventNames and emitted ({conn, accept, reject}); not in types or docs 🔴 UI.js:250,568
showSaveFilePicker 3rd type param 'url'/'move'/'copy' modes honored by impl/IPC; missing from types AND docs 🔴 UI.js:898; IPC.js:1697
disableMenuItem / enableMenuItem existence implemented + IPC-handled; absent from types and docs 🔴 UI.js:1101; IPC.js:734
toggleWindow existence implemented; absent from types and docs 🔴 UI.js:1074
instancesOpen existence implemented (IPC getInstancesOpen); absent from types and docs 🔴 UI.js:722; IPC.js:302
requestPermission existence implemented (returns boolean); absent from types and docs 🔴 UI.js:1091; IPC.js:1292
connectToInstance existence implemented (returns AppConnection); absent from types and docs 🔴 UI.js:1330
showColorPicker defaultValue/default aliases GUI honors defaultValue ?? defaultColor ?? default; type only declares defaultColor 🟡 UIWindowColorPicker.js:77
showFontPicker defaultFont typed, but GUI reads only options.defaultdefaultFont is a no-op in-app 🐛 UIWindowFontPicker.js:47
alert type enum types/docs say {primary,success,info,warning,danger}; GUI keys on {error,warning,info,success} (danger/primary fall through; working error key is error) 🟡 UIAlert.js:45-53
prompt options param 3rd options ({defaultValue}) honored+typed; prompt.md omits it 🔵 UI.js:734; IPC.js:244
createWindow return shape resolves {id} handle (typed); createWindow.md documents no return 🔵 UI.js:1351
setMenuItemIcon/IconActive/Checked docs impl+types; no doc pages / not in UI.md 🔵 UI.js:1109
requestUpgrade / launchApp options docs typed; under-documented 🔵 UI.js:892,1287
socialShare return type typed void; impl returns a Promise 🟡 UI.js:728

Utils

Function Item Issue Tag impl ref
print escapeHTML option impl+type have it; print.md documents only code 🔵 index.js:1249
env enum values env.md lists app/web/gui; impl/type also support web-worker,service-worker,nodejs 🔵 index.js:354-389

Drivers (types-only verify; no docs expected)

Function Item Issue Tag impl ref
call 2-arg overload impl supports call(iface_name, parameters) (e.g. puter.drivers.call('ipgeo', {ip})); type declares only 3-arg/4-arg overloads 🟡 Drivers.js:262-265

OS

No drift found; no docs family expected and none appeared. user({query}) honored and typed.


(a) Highest-impact shortlist

  1. 🐛 puter.ui.exit / broadcast / listenForBroadcast / FILE_*_CANCELLED are phantom typed members — they don't exist at runtime. exit actually lives on root puter. TS users hit TypeError. (ui.d.ts:154,195-199)
  2. 🐛 FSItem.copy() / FSItem.move() silently drop their overwrite/auto_rename/new_name arguments — they pass booleans into an options-object slot, so the args have no effect and a boolean can land in the success-callback slot. (FSItem.js:89-95)
  3. 🐛 requestWriteAppRootDir is broken#requestAppRootDir ignores its access arg and always requests read (access:'read' hardcoded, perm string …:read). Write access is unobtainable. (Perms.js:350-369)
  4. 🔴 Multiple public methods exist with zero type+doc coverage: FS revokeReadURL/readdirSubdomains; UI disableMenuItem/enableMenuItem/toggleWindow/instancesOpen/requestPermission/connectToInstance; Auth getGlobalUsage.
  5. 🟡 perms.d.ts is missing the entire request* API surface (18+ documented methods) — only grant/revoke/group plumbing is typed.
  6. 🔴 Socket/TLSSocket error payload is an Error, not the documented/typed string — affects the most-used socket event and every example. (PSocket.js:52)
  7. 🔴 workers.create 3rd param (appName + sandbox) is behavior-changing yet undocumented and mistyped. (Workers.js:24)
  8. 🔵/🐛 KV: get returns undefined not null (docs wrong); MAX_VALUE_SIZE is 399 KB not 400 KB; set batch form is untyped+undocumented; the size limit is only enforced for strings/arrays.
  9. 🔴 fsitem.md documents fields the FSItem class never produces (parent_id/parent_uid/writable/is_dir) while omitting the real ones.
  10. 🔴 AI: speech2speech camelCase aliases & txt2img model aliases are undocumented/untyped; txt2speech.listEngines/listVoices are entirely missing from ai.d.ts.

(b) 🐛 impl-bug bucket (code fixes, not doc/type edits)

  • UI: exit (phantom on UI type — lives on root puter), broadcast, listenForBroadcast, FILE_SAVE_CANCELLED/FILE_OPEN_CANCELLED getters — all phantom in ui.d.ts. FontPickerOptions.defaultFont is advertised but ignored by the GUI (reads options.default). (ui.d.ts:154,195-199; UIWindowFontPicker.js:47)
  • FSItem.copy() / FSItem.move() pass booleans into the options-object slot → overwrite/auto_rename/new_name silently dropped, boolean lands in success-callback slot. (FSItem.js:89-95; copy.js:15; move.js:17)
  • Perms #requestAppRootDir: ignores access arg (hardcodes read) so requestWriteAppRootDir requests read; references undefined var app_or_uuid (should be app_uid); error typo "strinkg". (Perms.js:350-369)
  • AI: ChatOptions.vision is a phantom option (chat() never reads userParams.vision); docs' text_verbosity alias is never read; speech2speech provider option is stripped and ignored (hardcoded elevenlabs-voice-changer); txt2speech 3000-char cap makes the documented xAI "15,000 chars" unreachable. (AI.js:733,817,484)
  • KV: value-size check uses args.value.length → effectively only enforces MAX_VALUE_SIZE for strings/arrays, not the serialized JSON payload actually sent; incr/decr/add/expire/expireAt deref options.key.length before validating the key → raw TypeError instead of key_undefined. (KV.js:208,328)
  • Workers: delete builds new Error("Worker doesn't exist") but never throws it (dead error); getLoggingHandle calls make_driver_method([], …)(authToken, workerName) with empty arg_defs → both positional args dropped. (Workers.js:119-123,138)
  • Hosting: delete returns raw driver result though type/docs promise true; update with a non-string first arg silently sends {object:undefined} (asymmetric with create). (Hosting.js:135,83-104)
  • Networking: PSocket.write ArrayBuffer branch calls data.write(...) on the ArrayBuffer (throws); PWispHandler._continue() is called with no arg → streamMap.get(undefined) throws (buffered-write flush dead); setup() reconnect uses setTimeout(setup(), 1000) (calls immediately instead of scheduling). (PSocket.js:74-76; PWispHandler.js:51,23)
  • Peer: PuterPeerServer.message is a phantom public method in the type (real method is private #message). (Peer.js:104)
  • Apps: getDeveloperProfile has duplicated options decls + a nested unreturned Promise (works by accident); update('name') with no attributes dereferences object_raw.name on undefined → TypeError. (Apps.js:246-268,155-156)

(c) Manifest drift

None. Disk file set exactly matches the Expected manifest this run (no 🆕 new files, no 🗑 removed files). The drift above is all within-file API drift.


Pinned to 15134c99bf106e3e9a2ff6a69c80e3ab047c48bc. Each finding is reproducible against that tree. Excluded as not-drift: _-suffixed internal methods, cosmetic param-name differences, intentionally-unknown provider/driver/worker stream payloads, and internal plumbing (Util.rpc, setAuthToken/setAPIOrigin).

https://claude.ai/code/session_019B8Wy8kJfbwLNwtLtcBq3v

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions