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 |
engine→model 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 |
duration→seconds 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/close → tls* |
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 async → Promise<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.default → defaultFont 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
- 🐛
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)
- 🐛
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)
- 🐛
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)
- 🔴 Multiple public methods exist with zero type+doc coverage: FS
revokeReadURL/readdirSubdomains; UI disableMenuItem/enableMenuItem/toggleWindow/instancesOpen/requestPermission/connectToInstance; Auth getGlobalUsage.
- 🟡
perms.d.ts is missing the entire request* API surface (18+ documented methods) — only grant/revoke/group plumbing is typed.
- 🔴 Socket/TLSSocket
error payload is an Error, not the documented/typed string — affects the most-used socket event and every example. (PSocket.js:52)
- 🔴
workers.create 3rd param (appName + sandbox) is behavior-changing yet undocumented and mistyped. (Workers.js:24)
- 🔵/🐛 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.
- 🔴 fsitem.md documents fields the FSItem class never produces (
parent_id/parent_uid/writable/is_dir) while omitting the real ones.
- 🔴 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
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).
15134c99bf106e3e9a2ff6a69c80e3ab047c48bc(branchclaude/exciting-lamport-gNnxk)src/puter-js/src/modules/(+src/puter-js/src/index.js, andsrc/gui/src/IPC.jsfor the UI family) · typessrc/puter-js/types/**· docssrc/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.aiwired viaregisterModule('ai', AI)(index.js:198).provideruserParams.provider, butChatOptionsomits it and docs don't list itimage_configdriver; typed; docs never documentdriver`tool_call_idChatMessageomits itcache_controlChatMessageomits itimage/typepart.image/part.type; chunk type only hastext?,reasoning?message.imagesmessage.images[]; not in typesengine→modelaliasenginecoerced intomodel; not in docs/typesai.d.tsvoiceId,modelId,outputFormat,voiceSettings,fileFormat,removeBackgroundNoise,optimizeStreamingLatency,enableLoggingnormalized by impl; types/docs only snake_case (docs even useremoveBackgroundNoisein an example)duration/wordsSpeech2TxtResultonly hastext,language,segmentsnano-banana/nano-banana-proaliasesai-image; JSDoc/@exampleclaim a Gemini default model not appliedinput_image_mime_type/input_imagesinput_image_mime_typemissing from typeduration→secondsaliassecondslast_frameinput_reference/reference_images/frame_imagesare)typefieldtype:"function";ToolCall+ Objects/toolcall.md omit itchoices/reasoningApps
Appis decorated withgetUsers()/users()async-iterator (documented in app.md) but missing from theApptypeget({...})get(name, options?)title"(required)"title = args[2] ?? args[0], typetitle?{success:true}{success?:boolean}, impl returns raw driver resultAuth
/metering/globalUsage); missing from type AND docsemailfieldrequestEmailreadswhoami.email, butUsertype AND user.md both omitemailgetUser(success, error); type only declares options formtotal:number+[key:string]:APIUsageis unsound TSPerms
request*methodsperms.d.tsdeclares none of the 18+ documentedrequest*methods (only grant/revoke/group plumbing)FileSystem (FS)
cacheoptionoptions.cache; missing fromReadOptionstype AND read docno_subdomainsReaddirOptionsmissing it (hasno_thumbs,no_assocs); docs omit all threereturnWorkersalias; type+docs only havereturnSubdomains`generateThumbnails/thumbnailGenerator/thumbnailUploadOptionstype AND docsinit/start/progress/abort/success/errortyped but entirely undocumentedFStype, no docFStype, no docdedupeNamecreateMissingParents/newMetadatarename/recursivealiasesdedupeName/createMissingParentsconsistencyString|File|BlobonlyexpiresIn'24h', typestring; doc wrongly says "milliseconds (Number)"puter.space()instead ofputer.fs.space()parent_id/parent_uid/writable/is_dirisDirectory,readURL,writeURL,metadataURL,uuidKV
399*1024(399 KB); set.md says 400 KBnull; impl+type resolve toundefinedset([{key,value}], …)/set({items})real but absent from types AND set.mdadd(key)silently adds 1; undocumented in add.mdclear = flushin types; no doc page / not in KV.mdWorkers
router.md/types.mddescribe the deployed-worker runtime (verified sane, not mapped to Workers.js).appName+sandbox{sandbox:false}object; type declares onlyappName?:string, docs omit the param entirely.d.ts; no doc page / not in Workers.mdx-puter-no-authescape hatchputer-authinjection; undocumentedworkerURL(String) only; impl/type accept anyRequestInfo/Request/URLHosting
Promise<boolean>+ docs say resolvestrue, but impl returns raw driver result (no coercion)Networking
errorreason: (string)— every error handler example prints the wrong thingdraineventSocketEventunion but never fired (dead event in public type)on()aliasingopen/data/close→tls*open/data/closeoverloads misleading on TLS; undocumentedPeer
message(); impl method is private#message(not callable)string, but impl stores an Error; docs readevent.error?.messageasync→Promise<void>; type declaresvoid(can'tawaitper types)string|ArrayBuffer|Blob; type omitsBlobUI (impl: UI.js + IPC.js)
UIclass, but implemented on rootputer(puter.exit);puter.ui.exitdoes not exist. UI.md also lists it asputer.ui.exit()UItype; no implementation (useon(name, handler))connectionevent#eventNamesand emitted ({conn, accept, reject}); not in types or docstypeparam'url'/'move'/'copy'modes honored by impl/IPC; missing from types AND docsgetInstancesOpen); absent from types and docsdefaultValue/defaultaliasesdefaultValue ?? defaultColor ?? default; type only declaresdefaultColordefaultFontoptions.default→defaultFontis a no-op in-apptypeenum{primary,success,info,warning,danger}; GUI keys on{error,warning,info,success}(danger/primaryfall through; working error key iserror)optionsparamoptions({defaultValue}) honored+typed; prompt.md omits it{id}handle (typed); createWindow.md documents no returnvoid; impl returns aPromiseUtils
escapeHTMLoptioncodeapp/web/gui; impl/type also supportweb-worker,service-worker,nodejsDrivers (types-only verify; no docs expected)
call(iface_name, parameters)(e.g.puter.drivers.call('ipgeo', {ip})); type declares only 3-arg/4-arg overloadsOS
No drift found; no docs family expected and none appeared.
user({query})honored and typed.(a) Highest-impact shortlist
puter.ui.exit/broadcast/listenForBroadcast/FILE_*_CANCELLEDare phantom typed members — they don't exist at runtime.exitactually lives on rootputer. TS users hitTypeError. (ui.d.ts:154,195-199)FSItem.copy()/FSItem.move()silently drop theiroverwrite/auto_rename/new_namearguments — 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)requestWriteAppRootDiris broken —#requestAppRootDirignores itsaccessarg and always requests read (access:'read'hardcoded, perm string…:read). Write access is unobtainable. (Perms.js:350-369)revokeReadURL/readdirSubdomains; UIdisableMenuItem/enableMenuItem/toggleWindow/instancesOpen/requestPermission/connectToInstance; AuthgetGlobalUsage.perms.d.tsis missing the entirerequest*API surface (18+ documented methods) — only grant/revoke/group plumbing is typed.errorpayload is anError, not the documented/typedstring— affects the most-used socket event and every example. (PSocket.js:52)workers.create3rd param (appName+sandbox) is behavior-changing yet undocumented and mistyped. (Workers.js:24)getreturnsundefinednotnull(docs wrong);MAX_VALUE_SIZEis 399 KB not 400 KB;setbatch form is untyped+undocumented; the size limit is only enforced for strings/arrays.parent_id/parent_uid/writable/is_dir) while omitting the real ones.txt2speech.listEngines/listVoicesare entirely missing fromai.d.ts.(b) 🐛 impl-bug bucket (code fixes, not doc/type edits)
exit(phantom onUItype — lives on rootputer),broadcast,listenForBroadcast,FILE_SAVE_CANCELLED/FILE_OPEN_CANCELLEDgetters — all phantom inui.d.ts.FontPickerOptions.defaultFontis advertised but ignored by the GUI (readsoptions.default). (ui.d.ts:154,195-199; UIWindowFontPicker.js:47)overwrite/auto_rename/new_namesilently dropped, boolean lands in success-callback slot. (FSItem.js:89-95; copy.js:15; move.js:17)#requestAppRootDir: ignoresaccessarg (hardcodesread) sorequestWriteAppRootDirrequests read; references undefined varapp_or_uuid(should beapp_uid); error typo "strinkg". (Perms.js:350-369)ChatOptions.visionis a phantom option (chat()never readsuserParams.vision); docs'text_verbosityalias is never read;speech2speechprovideroption is stripped and ignored (hardcodedelevenlabs-voice-changer); txt2speech 3000-char cap makes the documented xAI "15,000 chars" unreachable. (AI.js:733,817,484)args.value.length→ effectively only enforcesMAX_VALUE_SIZEfor strings/arrays, not the serialized JSON payload actually sent;incr/decr/add/expire/expireAtderefoptions.key.lengthbefore validating the key → rawTypeErrorinstead ofkey_undefined. (KV.js:208,328)deletebuildsnew Error("Worker doesn't exist")but neverthrows it (dead error);getLoggingHandlecallsmake_driver_method([], …)(authToken, workerName)with empty arg_defs → both positional args dropped. (Workers.js:119-123,138)deletereturns raw driver result though type/docs promisetrue;updatewith a non-string first arg silently sends{object:undefined}(asymmetric withcreate). (Hosting.js:135,83-104)PSocket.writeArrayBuffer branch callsdata.write(...)on the ArrayBuffer (throws);PWispHandler._continue()is called with no arg →streamMap.get(undefined)throws (buffered-write flush dead);setup()reconnect usessetTimeout(setup(), 1000)(calls immediately instead of scheduling). (PSocket.js:74-76; PWispHandler.js:51,23)PuterPeerServer.messageis a phantom public method in the type (real method is private#message). (Peer.js:104)getDeveloperProfilehas duplicatedoptionsdecls + a nested unreturned Promise (works by accident);update('name')with no attributes dereferencesobject_raw.nameonundefined→ 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-unknownprovider/driver/worker stream payloads, and internal plumbing (Util.rpc,setAuthToken/setAPIOrigin).https://claude.ai/code/session_019B8Wy8kJfbwLNwtLtcBq3v