puter.js SDK — TypeScript & Documentation Drift Audit
Tree: pinned to commit 6fc79a7184fccc7a4d2ccd0959a2bb7b801a3ce1 (branch claude/exciting-lamport-szoqek)
Date: 2026-06-29
Scope: full deep audit of every API family — impl (src/puter-js/src/modules/ + src/index.js + src/gui/src/IPC.js for UI), types (src/puter-js/types/), docs (src/docs/src/).
Legend: 🟡 types (impl/docs have it, types don't/wrong) · 🔵 docs (impl/types have it, docs don't/wrong) · 🔴 both · 🐛 impl-bug (advertised param impl ignores, or phantom method in types) · 🆕/🗑 manifest-drift.
Manifest tripwire (Step 0)
Disk vs the Expected manifest. Disk is the authority.
| File |
Status |
Tag |
src/docs/src/Objects/ttsengine.md |
On disk, not in manifest's AI Objects deps. Content accurate vs TTSEngine (ai.d.ts:297-306) & listEngines return. |
🆕 manifest-drift (new file) |
src/docs/src/Objects/ttsvoice.md |
On disk, not in manifest's AI Objects deps. Content accurate vs TTSVoice (ai.d.ts:316-335) & listVoices return. |
🆕 manifest-drift (new file) |
No removed/renamed files (no 🗑). All modules, FS ops, networking, UI components, types, and other docs match the manifest.
🔝 Highest-impact shortlist (cross-family)
- 🔴 FSItem
isDir vs isDirectory — both the type (isDir: boolean) and Objects/fsitem.md advertise isDir, but the runtime instance property is isDirectory (FSItem.js:17). Every FSItem from stat/readdir/mkdir/etc. returns undefined for item.isDir. Most user-visible drift in the whole SDK.
- 🐛 txt2img
provider / service are no-ops — docs+types prominently advertise provider:'gemini'|'xai'|'together'… and service as the routing knob, but AI.js:899-915 only inspects options.driver. Following the docs to select a non-OpenAI image provider silently mis-routes to ai-image.
- 🐛
notify({type, duration}) silently ignored in the app/GUI path — both documented & typed, but IPC.js:269-297 / UINotification.js never read them; only the standalone web-component fallback honors them.
- 🐛 Perms
requestWriteAppRootDir is broken — #requestAppRootDir hardcodes access:'read' and a :read permission string regardless of the write wrapper (Perms.js:359-369), plus a guaranteed ReferenceError on undefined app_or_uuid (Perms.js:367). Both methods are also absent from types & docs.
- 🐛 Apps
getDeveloperProfile never resolves — constructs an outer Promise but returns a nested Promise never wired to the outer resolve/reject (Apps.js:246-268); the returned promise hangs forever.
- 🐛 Peer phantom
PuterPeerServer.message() — types declare a public message() (peer.d.ts:67) that doesn't exist; impl has only private #message (Peer.js:104). Calling it throws TypeError.
- 🐛
PSocket.write ArrayBuffer branch broken — data.write(...) is called on an ArrayBuffer (PSocket.js:74-76), which has no .write; the advertised ArrayBuffer input type throws.
- 🔴 KV
MAX_VALUE_SIZE documented as 400 KB but is 399 KB — impl 399 * 1024 = 408,576 bytes (KV.js:36); types JSDoc, set.md, KVSetItem/KVSetObject all say "400 KB". Values between 399–400 KB are rejected despite docs.
- 🔴 FS
revokeReadURL & readdirSubdomains fully undocumented & untyped — public methods on puter.fs (FileSystem/index.js:44,46) absent from filesystem.d.ts and docs.
- 🟡
Drivers.call missing the 2-arg overload — the idiomatic puter.drivers.call('ipgeo', {…}) shorthand (Drivers.js:262) fails type-checking; types only declare 3- and 4-arg forms.
AI (AI.js / ai.d.ts / AI/)
| Function |
Item |
Issue |
Tag |
impl ref |
| txt2img |
provider option |
Docs+types advertise provider as routing knob; impl never reads it (only driver). |
🐛 |
AI.js:899-915 |
| txt2img |
service option |
Typed (ai.d.ts:182) but impl never reads it. Phantom. |
🐛 |
AI.js:909 |
| txt2img |
nano-banana/nano-banana-pro model aliases |
Impl maps to gemini models; absent from types & docs. |
🔴 |
AI.js:900-907 |
| txt2img |
driver option |
Read by impl, typed, but undocumented. |
🔵 |
AI.js:909-915 |
| chat |
vision option |
ChatOptions.vision typed but impl computes vision itself and never reads user value. |
🐛 |
AI.js:782-824 |
| chat |
streaming "image" chunk |
Documented (chat.md:366-385) but missing from ChatResponseChunk type + chatresponsechunk.md. |
🔴 |
AI.js:833 |
| chat |
streaming "error" chunk |
Documented (chat.md:227,295) but missing from type enum + object doc. |
🔴 |
AI.js:833 |
| chat |
images[].thoughtSignature |
Used in docs (chat.md:347,361); missing from ImageContent (ai.d.ts:3-6) & chatresponse.md. |
🔴 |
— |
| chat |
ChatMessage.images |
Declared required & non-optional (ai.d.ts:14); should be images? (assistant-output-only). |
🟡 |
ai.d.ts:14 |
| chat |
content type:"file"/puter_path |
Documented (chat.md:60-64); not modeled in AIMessageContent. |
🟡 |
ai.d.ts:1 |
| speech2speech |
camelCase aliases (voiceId,modelId,outputFormat,voiceSettings,fileFormat,removeBackgroundNoise,optimizeStreamingLatency,enableLogging) |
Normalized by impl; types only list snake_case. Docs' own example uses removeBackgroundNoise. |
🟡 |
AI.js:414-438 |
| speech2speech |
provider option |
Typed (ai.d.ts:411) but impl deletes it; always elevenlabs-voice-changer. Phantom. |
🐛 |
AI.js:484-486 |
| speech2speech |
MAX_INPUT_SIZE = 25 MB |
Enforced by impl; absent from docs & types. |
🔴 |
AI.js:402 |
| speech2speech |
file alias for audio |
Impl+types support file; options list in docs omits it. |
🔵 |
AI.js:461-464 |
| speech2txt |
MAX_INPUT_SIZE = 25 MB |
Enforced; absent from docs & types. |
🔴 |
AI.js:514 |
| txt2speech |
engine→provider inference |
Impl infers provider from engine; undocumented & untyped. |
🔴 |
AI.js:268-282 |
| txt2vid |
duration→seconds alias |
Typed; docs only document seconds. |
🔵 |
AI.js:979-981 |
| img2txt |
nested {source:{source:Blob}} |
Supported by impl; undocumented & untyped (edge case). |
🔴 |
AI.js:158-161 |
| chatresponse |
choices field |
Typed choices?: unknown (ai.d.ts:93); not in chatresponse.md. |
🔵 |
ai.d.ts:93 |
| ToolCall |
type field |
Used in docs (chat.md:577) tool calls; missing from ToolCall type & toolcall.md. |
🔴 |
ai.d.ts:17-20 |
| ttsengine.md / ttsvoice.md |
new object docs |
Not in manifest (content accurate). |
🆕 |
— |
Apps (Apps.js / apps.d.ts / Apps/)
| Function |
Item |
Issue |
Tag |
impl ref |
checkName |
method existence |
In impl + types; undocumented. |
🔵 |
Apps.js:206-230 |
getDeveloperProfile |
method existence |
In impl + types; undocumented. |
🔵 |
Apps.js:232-269 |
getDeveloperProfile |
never resolves |
Returns nested Promise never tied to outer resolver; promise hangs. options computed twice (dead code). |
🐛 |
Apps.js:246-268 |
(All other Apps surfaces — create/update/list/delete, App object, CreateAppResult — types & docs consistent.)
Auth (Auth.js / auth.d.ts / Auth/)
| Function |
Item |
Issue |
Tag |
impl ref |
getGlobalUsage |
method existence |
Implemented (/metering/globalUsage); missing from types AND docs. |
🔴 |
Auth.js:338-374 |
whoami |
method existence |
In impl + types (used by Perms); undocumented. |
🔵 |
Auth.js:211-256 |
getUser |
positional (success,error) overload |
Supported by impl; types only declare options-object form. |
🟡 |
Auth.js:175-205 |
User |
feature_flags |
In types; not in user.md. |
🔵 |
auth.d.ts:15 |
User |
hasDevAccountAccess |
In types; not in user.md. |
🔵 |
auth.d.ts:16 |
User |
otp |
In types; not in user.md. |
🔵 |
auth.d.ts:18 |
Perms (Perms.js / perms.d.ts / Perms/)
| Function |
Item |
Issue |
Tag |
impl ref |
grantUser/grantGroup/grantApp/grantAppAnyUser/grantOrigin |
method existence |
In impl + types; undocumented. |
🔵 |
Perms.js:37-65 |
revokeUser/revokeGroup/revokeApp/revokeAppAnyUser/revokeOrigin |
method existence |
In impl + types; undocumented. |
🔵 |
Perms.js:68-96 |
createGroup/addUsersToGroup/removeUsersFromGroup/listGroups |
method existence |
In impl + types; undocumented. |
🔵 |
Perms.js:99-118 |
requestReadAppRootDir |
method existence |
In impl; missing from types AND docs. |
🔴 |
Perms.js:333-335 |
requestWriteAppRootDir |
method existence |
In impl; missing from types AND docs. |
🔴 |
Perms.js:346-348 |
#requestAppRootDir |
hardcoded access:'read' |
Write wrapper passes 'write' but helper hardcodes 'read' in the body — write access never requested. |
🐛 |
Perms.js:361 |
#requestAppRootDir |
app_or_uuid undefined |
References undefined var (typo for app_uid) → ReferenceError if first fetch errors. |
🐛 |
Perms.js:367 |
#requestAppRootDir |
permission level :read |
Builds app-root-dir:…:read even for write path. |
🐛 |
Perms.js:369 |
requestPermission |
deprecated alias |
In impl (@deprecated); not in types/docs (low priority). |
🟡 |
Perms.js:123-125 |
FS (FSItem.js + FileSystem/operations/* / filesystem.d.ts, fs-item.d.ts / FS/)
| Function |
Item |
Issue |
Tag |
impl ref |
| FSItem |
isDir vs isDirectory |
Runtime property is isDirectory; type & fsitem.md say isDir. |
🔴 |
FSItem.js:17 |
revokeReadURL |
method existence |
Public (puter.fs); missing from types AND docs. |
🔴 |
revokeReadUrl.js:10 |
readdirSubdomains |
method existence |
Public; missing from types AND docs. |
🔴 |
readdirSubdomains.js:11 |
sign |
doc page |
In impl + types; no doc page. |
🔵 |
sign.js:15 |
read |
cache option |
Read by impl; missing from ReadOptions & read.md. |
🔴 |
read.js:46 |
stat |
returnWorkers alias |
Read by impl; missing from StatOptions & stat.md. |
🔴 |
stat.js:54,126 |
stat |
consistency option |
Typed; omitted from stat.md. |
🔵 |
stat.js:31 |
readdir |
no_subdomains option |
Read+sent by impl; missing from ReaddirOptions (which has no_thumbs/no_assocs) & docs. |
🔴 |
readdir.js:57-60 |
readdir |
consistency option |
Typed; omitted from readdir.md. |
🔵 |
readdir.js:29,44 |
upload |
generateThumbnails/thumbnailGenerator/thumbnail |
Read by impl; missing from UploadOptions & docs. |
🔴 |
upload.js:571,573,1313 |
copy |
positional 3rd-arg parsed as object only |
copy(src,dst,boolean) (as FSItem.copy calls it) drops auto_rename/overwrite — never reach the wire. |
🐛 |
copy.js:8-24; FSItem.js:94 |
copy |
create_missing_parents/new_metadata/excludeSocketID |
Parsed into options but never sent in payload — dead options. |
🐛 |
copy.js:17-19 vs 48-57 |
move |
positional 3rd/4th-arg dropped |
FSItem.move passes overwrite/new_name positionally; move only reads args[2] as object. |
🐛 |
move.js:11-21; FSItem.js:90 |
move |
dedupeName documented but never read |
Phantom documented option. |
🔵 |
move.js |
move |
newName/newMetadata/excludeSocketID |
Read+sent; omitted from move.md. |
🔵 |
move.js:63-66 |
mkdir |
rename alias (dedupe), recursive alias (createMissingParents), shortcutTo |
Read by impl; aliases/shortcutTo undocumented. |
🔵 |
mkdir.js:51-54 |
delete |
descendants_only snake alias |
Sent by impl; only descendantsOnly in types/docs. |
🔵 |
deleteFSEntry.js:55 |
write |
write(path) single-arg overload |
Docs show it; type requires data. |
🟡 |
write.js:4,52-55 |
space |
docs example puter.space() |
No top-level puter.space; should be puter.fs.space(). Also missing platforms frontmatter. |
🔵 |
FileSystem/index.js:31 |
| FSItem |
move/copy not in fsitem.md |
Typed + implemented; doc omits both. |
🔵 |
FSItem.js:89,93 |
getReadURL |
directory rejection |
Impl rejects for dirs; not noted in doc. |
🔵 |
getReadUrl.js:18-20 |
KV (KV.js / kv.d.ts / KV/)
| Function |
Item |
Issue |
Tag |
impl ref |
| MAX_VALUE_SIZE |
exact value |
Impl 399*1024; types JSDoc + set.md + KVSetItem/KVSetObject say "400 KB". |
🔴 |
KV.js:36 |
optConfig |
all methods |
Read by every method (set/get/incr/decr/add/remove/update/expire/expireAt/del/list/flush) with {appUuid} shorthand; typed via overloads but documented on no method. |
🔵 |
KV.js:174 etc. |
clear |
alias |
clear = this.flush, in types; no KV/clear.md, absent from KV.md function list. |
🔵 |
KV.js:676 |
get/del/incr/decr/add |
object-form single-arg overload |
get({key}) etc. supported by impl; absent from types & docs (only set/update document object form). |
🟡 |
KV.js:256,308,338,368,540 |
| MAX_KEY_SIZE |
exact value |
1024 = 1 KB exactly — consistent. |
ok |
KV.js:35 |
Hosting (Hosting.js / hosting.d.ts / Hosting/)
| Function |
Item |
Issue |
Tag |
impl ref |
list |
workers.puter.* filter |
Impl silently filters these out; undocumented. |
🔵 |
Hosting.js:44 |
update |
non-string first arg |
Falls through with empty options={} → malformed driver call instead of a clear error. |
🐛 |
Hosting.js:84-103 |
create |
object-form root_dir not absolutized |
Asymmetry vs positional dirPath (which calls getAbsolutePathForApp). Docs warn about it, but a footgun. |
🐛/— |
Hosting.js:76-77 |
update |
root_dir null default |
update(subdomain) sets root_dir to null; undocumented. |
🔵 |
Hosting.js:99 |
Workers (Workers.js / workers.d.ts / Workers/)
| Function |
Item |
Issue |
Tag |
impl ref |
getLoggingHandle |
method existence |
In impl + types; undocumented (no page, not in functions list). |
🔵 |
Workers.js:137 |
create |
errors type |
Impl reads driverResult.errors as a string (new Error(...)); types (string[]) & workerdeployment.md (Array) say array. |
🔴 |
Workers.js:51 |
(router.md/types.md describe the deployed-worker runtime, verified internally consistent — not mapped to SDK methods.)
Peer (Peer.js / peer.d.ts / Peer/)
| Function |
Item |
Issue |
Tag |
impl ref |
PuterPeerServer.message() |
phantom method |
Typed public message() (peer.d.ts:67); impl has only private #message. |
🐛 |
Peer.js:104 |
| error event |
payload type |
Impl dispatches an Error object; type says error: string (peer.d.ts:43). Docs example reads event.error?.message (treats as Error), contradicting the type. |
🟡 |
Peer.js:236,285,306 |
| PuterPeerConnection |
object doc |
The AppConnection.md listed for Peer actually documents puter.ui's app-connection object; the real PuterPeerConnection has no Objects/ doc (only inline in serve.md/connect.md). |
🔵 |
— |
Networking (networking/* / networking.d.ts / Networking/)
| Function |
Item |
Issue |
Tag |
impl ref |
PSocket.write |
ArrayBuffer branch |
data.write(...) called on an ArrayBuffer (no such method) → throws for advertised ArrayBuffer input. |
🐛 |
PSocket.js:74-76 |
PSocket |
'drain' event |
In SocketEvent type + registered, but never emitted. |
🐛/🟡 |
PSocket.js:16 |
PSocket.write |
callback param |
Accepted+invoked by impl, typed; docs omit it. |
🔵 |
PSocket.js:70 |
generateWispV1URL |
doc |
Public on puter.net, in types; no docs entry. |
🔵 |
index.js:627 |
PTLSSocket.on |
plain-name remap |
on('open'|'data'|'close') silently remapped to tls*; undocumented & not surfaced in types. |
🔵 |
PTLS.js:92-98 |
fetch |
string rejections |
Impl rejects with strings in several paths; docs don't note. |
🔵 |
requests.js:63,85,254 |
PWispHandler |
reconnect / backpressure |
setTimeout(setup(), 1000) invokes immediately; _continue() called with no streamID. (Non-drift, surfaced during walk.) |
🐛 |
PWispHandler.js:23,51 |
Drivers (Drivers.js / drivers.d.ts, verify-only)
| Function |
Item |
Issue |
Tag |
impl ref |
call |
2-arg overload |
call('ipgeo', {…}) shorthand supported by impl; types only have 3- & 4-arg overloads → fails type-checking. |
🟡 |
Drivers.js:262-265 |
call |
<2-arg guard |
0/1 args leave iface_name/method_name undefined, no guard. |
🐛 (minor) |
Drivers.js:232-269 |
(3- and 4-arg overloads, get, list all consistent.)
OS (OS.js / os.d.ts, verify-only)
No drift. user (incl. query), version match types. Positional (success,error) callback form untyped (convention, minor). No docs family present (expected).
Utils / top-level (src/index.js / puter.d.ts, shared.d.ts / Utils/)
| Function |
Item |
Issue |
Tag |
impl ref |
env |
return values |
Docs list only app/web/gui; impl also returns service-worker/web-worker/nodejs. Types correct. |
🔵 |
index.js:357-388 |
print |
escapeHTML option |
Supported (impl) + typed; undocumented (only code in print.md). |
🔵 |
index.js:1258 |
print |
variadic signature |
Impl print(...args) (multi-arg); docs (print(text)) & types (print(text, options?)) understate it. |
🔴 |
index.js:1251 |
exit |
docs |
In impl + types; no doc page, not listed in Utils.md. Non-obvious coercion (non-number→1) + cross-frame post. |
🔵 |
index.js:1040 |
| Puter interface |
quiet/debugMode/on/off/whoami |
Wired in impl; missing from Puter type. |
🟡 |
index.js:170,173,771,972 |
| Puter interface |
getUser positional overload |
(success,error) form wired; type declares options-object form only. |
🟡 |
index.js:1217 |
UI (UI.js + IPC.js + ui/components/* / ui.d.ts / UI/)
| Function |
Item |
Issue |
Tag |
impl ref |
notify |
type option |
Documented + typed; GUI/IPC path never reads it (only standalone fallback). |
🐛 |
IPC.js:269-297 |
notify |
duration option |
Same — ignored in app/GUI path. |
🐛 |
IPC.js:269-297 |
exit |
mislisted location |
UI.md lists puter.ui.exit(); it lives on root puter (exit.md is correct). |
🔵 |
UI.md:36 |
prompt |
options param |
Impl + IPC + types support options.defaultValue; prompt.md never mentions options. |
🔵 |
IPC.js:253 |
showColorPicker |
defaultValue/default aliases |
Honored only in standalone; types declare only defaultColor. Docs lack Parameters/Return sections. |
🔴 |
UI.js:884 |
showFontPicker |
default alias + options/return docs |
Standalone reads default; types miss it. Docs lack Parameters/Return for the options form. |
🔵/🟡 |
UI.js:866 |
showOpenFilePicker/showSaveFilePicker |
.undefinedOnCancel |
Impl + types expose it; docs never mention it. |
🔵 |
UI.js:842,971 |
setMenubar |
theme option, item id |
theme typed + standalone-only; id required to target items dynamically — both omitted from setMenubar.md. |
🔵 |
UI.js:1102; IPC.js:744 |
disableMenuItem/enableMenuItem |
method existence |
In UI.js + wired in IPC; missing from types AND docs. (Siblings setMenuItemIcon*/Checked typed but undocumented.) |
🟡/🔵 |
UI.js:1117-1135 |
requestPermission (ui) |
method existence |
In UI.js + IPC; missing from types AND docs. |
🟡/🔵 |
UI.js:1107 |
contextMenu |
theme/x/y + item danger/checked/shortcut |
Honored only in standalone; x/y and item fields in neither types nor docs; GUI/IPC drops them. |
🟡/🔵 |
UI.js:1147-1151 |
socialShare |
return value |
Typed void; impl returns a Promise. Docs lack Return section. |
🟡/🔵 |
UI.js:728 |
launchApp |
options.callback, LaunchAppResult fields |
callback read by impl, undocumented; LaunchAppResult (launched/appUid/privateAccess) richer than docs. |
🔵 |
UI.js:1312 |
No phantom methods in ui.d.ts (every typed method exists). Type gaps are missing members, not invented ones.
🐛 impl-bug bucket (code fixes, not doc/type edits)
| Location |
Bug |
| AI.js:899-915 |
txt2img provider (docs+types) & service (types) silently ignored; only driver routes. |
| AI.js:484-486 |
speech2speech typed provider deleted before driver call; always elevenlabs-voice-changer. |
| AI.js:782-824 |
chat typed vision option never read from user params. |
| Apps.js:246-268 |
getDeveloperProfile returns nested Promise never tied to outer resolver — never settles. Dead duplicate options. |
| Perms.js:361 |
#requestAppRootDir hardcodes access:'read' — requestWriteAppRootDir requests read. |
| Perms.js:367 |
References undefined app_or_uuid (typo for app_uid) — ReferenceError on first-fetch error. |
| Perms.js:369 |
Permission string hardcoded :read for the write path. |
| copy.js:8-24 (+FSItem.js:94) |
copy(src,dst,boolean) parses args[2] as object only — FSItem.copy's auto_rename/overwrite dropped. |
| copy.js:17-19 |
create_missing_parents/new_metadata/excludeSocketID parsed but never sent — dead options. |
| move.js:11-21 (+FSItem.js:90) |
move(src,dst,overwrite,new_name) positional args dropped (only args[2] read as object). |
| Hosting.js:84-103 |
update with non-string first arg → empty options={} → malformed driver call. |
| Peer.js:104 (vs peer.d.ts:67) |
Phantom public PuterPeerServer.message(); only private #message exists. |
| PSocket.js:74-76 |
write ArrayBuffer branch calls data.write(...) on an ArrayBuffer → throws. |
| PSocket.js:16 |
'drain' declared/registered but never emitted. |
| Drivers.js:232-269 |
call() with <2 args leaves iface/method undefined, no guard. |
| PWispHandler.js:23,51 |
setTimeout(setup(), …) invokes immediately; _continue() called without streamID (reconnect/backpressure). |
| IPC.js:269-297 |
notify type & duration ignored in app/GUI path. |
🆕 manifest-drift
Objects/ttsengine.md, Objects/ttsvoice.md — new files, content-accurate, absent from the audit manifest.
Generated by an automated drift audit (8 parallel family agents) against commit 6fc79a7184fccc7a4d2ccd0959a2bb7b801a3ce1. Each finding cites an impl reference (file:line) for reproduction.
🤖 Generated with Claude Code
puter.js SDK — TypeScript & Documentation Drift Audit
Tree: pinned to commit
6fc79a7184fccc7a4d2ccd0959a2bb7b801a3ce1(branchclaude/exciting-lamport-szoqek)Date: 2026-06-29
Scope: full deep audit of every API family — impl (
src/puter-js/src/modules/+src/index.js+src/gui/src/IPC.jsfor UI), types (src/puter-js/types/), docs (src/docs/src/).Legend: 🟡 types (impl/docs have it, types don't/wrong) · 🔵 docs (impl/types have it, docs don't/wrong) · 🔴 both · 🐛 impl-bug (advertised param impl ignores, or phantom method in types) · 🆕/🗑 manifest-drift.
Manifest tripwire (Step 0)
Disk vs the Expected manifest. Disk is the authority.
src/docs/src/Objects/ttsengine.mdTTSEngine(ai.d.ts:297-306) &listEnginesreturn.src/docs/src/Objects/ttsvoice.mdTTSVoice(ai.d.ts:316-335) &listVoicesreturn.No removed/renamed files (no 🗑). All modules, FS ops, networking, UI components, types, and other docs match the manifest.
🔝 Highest-impact shortlist (cross-family)
isDirvsisDirectory— both the type (isDir: boolean) andObjects/fsitem.mdadvertiseisDir, but the runtime instance property isisDirectory(FSItem.js:17). Every FSItem from stat/readdir/mkdir/etc. returnsundefinedforitem.isDir. Most user-visible drift in the whole SDK.provider/serviceare no-ops — docs+types prominently advertiseprovider:'gemini'|'xai'|'together'…andserviceas the routing knob, butAI.js:899-915only inspectsoptions.driver. Following the docs to select a non-OpenAI image provider silently mis-routes toai-image.notify({type, duration})silently ignored in the app/GUI path — both documented & typed, butIPC.js:269-297/UINotification.jsnever read them; only the standalone web-component fallback honors them.requestWriteAppRootDiris broken —#requestAppRootDirhardcodesaccess:'read'and a:readpermission string regardless of the write wrapper (Perms.js:359-369), plus a guaranteedReferenceErroron undefinedapp_or_uuid(Perms.js:367). Both methods are also absent from types & docs.getDeveloperProfilenever resolves — constructs an outer Promise but returns a nested Promise never wired to the outer resolve/reject (Apps.js:246-268); the returned promise hangs forever.PuterPeerServer.message()— types declare a publicmessage()(peer.d.ts:67) that doesn't exist; impl has only private#message(Peer.js:104). Calling it throwsTypeError.PSocket.writeArrayBuffer branch broken —data.write(...)is called on anArrayBuffer(PSocket.js:74-76), which has no.write; the advertisedArrayBufferinput type throws.MAX_VALUE_SIZEdocumented as 400 KB but is 399 KB — impl399 * 1024 = 408,576bytes (KV.js:36); types JSDoc,set.md,KVSetItem/KVSetObjectall say "400 KB". Values between 399–400 KB are rejected despite docs.revokeReadURL&readdirSubdomainsfully undocumented & untyped — public methods onputer.fs(FileSystem/index.js:44,46) absent fromfilesystem.d.tsand docs.Drivers.callmissing the 2-arg overload — the idiomaticputer.drivers.call('ipgeo', {…})shorthand (Drivers.js:262) fails type-checking; types only declare 3- and 4-arg forms.AI (
AI.js/ai.d.ts/AI/)provideroptionprovideras routing knob; impl never reads it (onlydriver).serviceoptionai.d.ts:182) but impl never reads it. Phantom.nano-banana/nano-banana-promodel aliasesdriveroptionvisionoptionChatOptions.visiontyped but impl computesvisionitself and never reads user value."image"chunkChatResponseChunktype + chatresponsechunk.md."error"chunkimages[].thoughtSignatureImageContent(ai.d.ts:3-6) & chatresponse.md.ChatMessage.imagesimages?(assistant-output-only).type:"file"/puter_pathAIMessageContent.voiceId,modelId,outputFormat,voiceSettings,fileFormat,removeBackgroundNoise,optimizeStreamingLatency,enableLogging)removeBackgroundNoise.provideroptionai.d.ts:411) but impl deletes it; alwayselevenlabs-voice-changer. Phantom.filealias foraudiofile; options list in docs omits it.engine; undocumented & untyped.duration→secondsaliasseconds.{source:{source:Blob}}choicesfieldchoices?: unknown(ai.d.ts:93); not in chatresponse.md.typefieldToolCalltype & toolcall.md.Apps (
Apps.js/apps.d.ts/Apps/)checkNamegetDeveloperProfilegetDeveloperProfileoptionscomputed twice (dead code).(All other Apps surfaces —
create/update/list/delete,Appobject,CreateAppResult— types & docs consistent.)Auth (
Auth.js/auth.d.ts/Auth/)getGlobalUsage/metering/globalUsage); missing from types AND docs.whoamigetUser(success,error)overloadUserfeature_flagsUserhasDevAccountAccessUserotpPerms (
Perms.js/perms.d.ts/Perms/)grantUser/grantGroup/grantApp/grantAppAnyUser/grantOriginrevokeUser/revokeGroup/revokeApp/revokeAppAnyUser/revokeOrigincreateGroup/addUsersToGroup/removeUsersFromGroup/listGroupsrequestReadAppRootDirrequestWriteAppRootDir#requestAppRootDiraccess:'read''write'but helper hardcodes'read'in the body — write access never requested.#requestAppRootDirapp_or_uuidundefinedapp_uid) →ReferenceErrorif first fetch errors.#requestAppRootDir:readapp-root-dir:…:readeven for write path.requestPermission@deprecated); not in types/docs (low priority).FS (
FSItem.js+FileSystem/operations/*/filesystem.d.ts,fs-item.d.ts/FS/)isDirvsisDirectoryisDirectory; type & fsitem.md sayisDir.revokeReadURLputer.fs); missing from types AND docs.readdirSubdomainssignreadcacheoptionReadOptions& read.md.statreturnWorkersaliasStatOptions& stat.md.statconsistencyoptionreaddirno_subdomainsoptionReaddirOptions(which hasno_thumbs/no_assocs) & docs.readdirconsistencyoptionuploadgenerateThumbnails/thumbnailGenerator/thumbnailUploadOptions& docs.copycopy(src,dst,boolean)(as FSItem.copy calls it) dropsauto_rename/overwrite— never reach the wire.copycreate_missing_parents/new_metadata/excludeSocketIDmoveoverwrite/new_namepositionally;moveonly readsargs[2]as object.movededupeNamedocumented but never readmovenewName/newMetadata/excludeSocketIDmkdirrenamealias (dedupe),recursivealias (createMissingParents),shortcutToshortcutToundocumented.deletedescendants_onlysnake aliasdescendantsOnlyin types/docs.writewrite(path)single-arg overloaddata.spaceputer.space()puter.space; should beputer.fs.space(). Also missingplatformsfrontmatter.move/copynot in fsitem.mdgetReadURLKV (
KV.js/kv.d.ts/KV/)399*1024; types JSDoc + set.md +KVSetItem/KVSetObjectsay "400 KB".optConfig{appUuid}shorthand; typed via overloads but documented on no method.clearclear = this.flush, in types; noKV/clear.md, absent from KV.md function list.get/del/incr/decr/addget({key})etc. supported by impl; absent from types & docs (onlyset/updatedocument object form).1024= 1 KB exactly — consistent.Hosting (
Hosting.js/hosting.d.ts/Hosting/)listworkers.puter.*filterupdateoptions={}→ malformed driver call instead of a clear error.createroot_dirnot absolutizeddirPath(which callsgetAbsolutePathForApp). Docs warn about it, but a footgun.updateroot_dirnull defaultupdate(subdomain)sets root_dir to null; undocumented.Workers (
Workers.js/workers.d.ts/Workers/)getLoggingHandlecreateerrorstypedriverResult.errorsas a string (new Error(...)); types (string[]) & workerdeployment.md (Array) say array.(
router.md/types.mddescribe the deployed-worker runtime, verified internally consistent — not mapped to SDK methods.)Peer (
Peer.js/peer.d.ts/Peer/)PuterPeerServer.message()message()(peer.d.ts:67); impl has only private#message.Errorobject; type sayserror: string(peer.d.ts:43). Docs example readsevent.error?.message(treats as Error), contradicting the type.AppConnection.mdlisted for Peer actually documentsputer.ui's app-connection object; the realPuterPeerConnectionhas no Objects/ doc (only inline in serve.md/connect.md).Networking (
networking/*/networking.d.ts/Networking/)PSocket.writedata.write(...)called on an ArrayBuffer (no such method) → throws for advertisedArrayBufferinput.PSocket'drain'eventSocketEventtype + registered, but never emitted.PSocket.writecallbackparamgenerateWispV1URLputer.net, in types; no docs entry.PTLSSocket.onon('open'|'data'|'close')silently remapped totls*; undocumented & not surfaced in types.fetchPWispHandlersetTimeout(setup(), 1000)invokes immediately;_continue()called with no streamID. (Non-drift, surfaced during walk.)Drivers (
Drivers.js/drivers.d.ts, verify-only)callcall('ipgeo', {…})shorthand supported by impl; types only have 3- & 4-arg overloads → fails type-checking.calliface_name/method_nameundefined, no guard.(3- and 4-arg overloads,
get,listall consistent.)OS (
OS.js/os.d.ts, verify-only)No drift.
user(incl.query),versionmatch types. Positional(success,error)callback form untyped (convention, minor). No docs family present (expected).Utils / top-level (
src/index.js/puter.d.ts,shared.d.ts/Utils/)envapp/web/gui; impl also returnsservice-worker/web-worker/nodejs. Types correct.printescapeHTMLoptioncodein print.md).printprint(...args)(multi-arg); docs (print(text)) & types (print(text, options?)) understate it.exitquiet/debugMode/on/off/whoamiPutertype.getUserpositional overload(success,error)form wired; type declares options-object form only.UI (
UI.js+IPC.js+ui/components/*/ui.d.ts/UI/)notifytypeoptionnotifydurationoptionexitputer.ui.exit(); it lives on rootputer(exit.md is correct).promptoptionsparamoptions.defaultValue; prompt.md never mentionsoptions.showColorPickerdefaultValue/defaultaliasesdefaultColor. Docs lack Parameters/Return sections.showFontPickerdefaultalias + options/return docsdefault; types miss it. Docs lack Parameters/Return for the options form.showOpenFilePicker/showSaveFilePicker.undefinedOnCancelsetMenubarthemeoption, itemidthemetyped + standalone-only;idrequired to target items dynamically — both omitted from setMenubar.md.disableMenuItem/enableMenuItemsetMenuItemIcon*/Checkedtyped but undocumented.)requestPermission(ui)contextMenutheme/x/y+ itemdanger/checked/shortcutx/yand item fields in neither types nor docs; GUI/IPC drops them.socialSharevoid; impl returns a Promise. Docs lack Return section.launchAppoptions.callback,LaunchAppResultfieldscallbackread by impl, undocumented;LaunchAppResult(launched/appUid/privateAccess) richer than docs.No phantom methods in
ui.d.ts(every typed method exists). Type gaps are missing members, not invented ones.🐛 impl-bug bucket (code fixes, not doc/type edits)
provider(docs+types) &service(types) silently ignored; onlydriverroutes.providerdeleted before driver call; alwayselevenlabs-voice-changer.visionoption never read from user params.getDeveloperProfilereturns nested Promise never tied to outer resolver — never settles. Dead duplicateoptions.#requestAppRootDirhardcodesaccess:'read'—requestWriteAppRootDirrequests read.app_or_uuid(typo forapp_uid) — ReferenceError on first-fetch error.:readfor the write path.copy(src,dst,boolean)parsesargs[2]as object only — FSItem.copy'sauto_rename/overwritedropped.create_missing_parents/new_metadata/excludeSocketIDparsed but never sent — dead options.move(src,dst,overwrite,new_name)positional args dropped (onlyargs[2]read as object).updatewith non-string first arg → emptyoptions={}→ malformed driver call.PuterPeerServer.message(); only private#messageexists.writeArrayBuffer branch callsdata.write(...)on an ArrayBuffer → throws.'drain'declared/registered but never emitted.call()with <2 args leaves iface/method undefined, no guard.setTimeout(setup(), …)invokes immediately;_continue()called without streamID (reconnect/backpressure).notifytype&durationignored in app/GUI path.🆕 manifest-drift
Objects/ttsengine.md,Objects/ttsvoice.md— new files, content-accurate, absent from the audit manifest.Generated by an automated drift audit (8 parallel family agents) against commit
6fc79a7184fccc7a4d2ccd0959a2bb7b801a3ce1. Each finding cites an impl reference (file:line) for reproduction.🤖 Generated with Claude Code