#4002

Puter.js types and docs drift audit - 2026-10-01

Openreynaldichernandoopened 1mo ago

Full deep audit of puter.js types/docs vs implementation, pinned to commit fc62ea2ee12fc5fcc6d015342cf01cdce2ced56c.

Tags: 🟡 types · 🔵 docs · 🔴 both · 🐛 impl-bug · 🆕/🗑 manifest-drift. Findings were verified by per-family audit agents reading impl, JSDoc and docs. Low-confidence items are marked (low).

🆕 Manifest drift (the manifest is stale)

  • No hand-written types/ dir. src/puter-js/types/** does not exist. Types are generated by tsc from JSDoc in src/ (tsconfig.types.json), entry src/puter-js/index.d.ts. "Types" below means JSDoc and types.js typedefs.
  • Impl layout is now modules/<family>/ for ai, apps, events, hosting, kv, os, perms, teams, Email, FileSystem, networking. Auth.js, Drivers.js, FSItem.js, Peer.js, UI.js, Workers.js remain top-level files. There is no Perms.js, KV.js, Hosting.js, Apps.js, AI.js or OS.js.
  • 🆕 New families not in the manifest: Email (modules/Email, docs Email/), Events (modules/events, docs Events/), Teams (modules/teams, docs Teams/).
  • 🆕 New FS ops: getShareLink, getShares, listShared, listSharedByMe, share, unshare, shareUtil. New docs: FS/{getShareLink,getShares,listShared,listSharedByMe,share,unshare}.
  • 🆕 New docs: Apps/checkName, Auth/{getProfile,getProfilePicture,updateProfile}, Peer/createGuestGrant, Perms/{check,appData}, UI/{exitPictureInPicture,requestPictureInPicture,showFeedbackDialog}, Workers/dynamic.
  • 🆕 New Objects: emaillistpage, emailmessage, emailmessageattachment, emailsummary, puterpeerconnection, puterpeerserver, ttsengine, ttsvoice, userprofile.
  • 🗑 Removed docs: Perms/requestEmail, requestRead* and requestWrite*, requestManage* (replaced by request() plus deprecated aliases). Auth/signIn etc. still exist.
  • Objects.md index omits createappresult, kvlistpage, signinresult, spaceinfo, userprofile (plus the Email and Peer objects).
  • Auth/updateProfile.md is draft: true and is not in the sidebar.

Highest-impact

  1. 🐛🔴 FS return type. stat/readdir/copy/move/mkdir/rename/write/upload are typed and documented as FSItem (with methods such as item.read()), but the ops resolve raw snake_case v1 entries (is_dir, uid) with no methods. The fsitem.md examples would throw.
  2. 🐛🔴 Docs example puter.space() does not exist. It is puter.fs.space() (FS/space.md:34).
  3. 🐛 UI calls that hang or throw when used as documented. socialShare(url[, msg]) throws in IPC on options.left (IPC.js:380). showFontPicker('Arial') throws on a string options (IPC.js:1528). alert() and prompt() with no message never resolve (IPC.js:280,300).
  4. 🐛 UI options silently dropped in the app env. showFontPicker.defaultFont (only default is read), alert icon/body_icon, and notify type/duration.
  5. 🐛🔴 Nested showSpinner/hideSpinner. Docs say calls are ref-counted, but there is no counter (UI.js:3011,3100).
  6. 🔴 KV MAX_VALUE_SIZE is 399*1024, but docs say "400 KB". The check compares .length, not bytes (kv/lib/validate.js:3,18).
  7. 🐛 workers.getLoggingHandle().close() is an unbound socket.close and throws (Workers.js:274).
  8. 🐛 fs.stat({uid}) with consistency: 'eventual' uses cache key item:undefined, which can return another item's result (stat.js:51-56).
  9. 🐛🔴 PuterPeerConnection.close(reason) is documented as delivering the reason to the peer, but it never does (Peer.js:775).
  10. 🐛 'drain' is a typed Socket event that is never emitted (PSocket.js:24). A TLS handshake failure emits error but no close, contrary to the docs (PTLS.js:69).

🐛 Impl-bug bucket

AreaItemRef
UIsocialShare(url) / (url,msg) throws in IPC (options undefined)UI.js:1229; IPC.js:380
UIshowFontPicker(string) throws; defaultFont ignored (only default)UI.js:1401-1407; IPC.js:1528; UIWindowFontPicker.js:47
UIalert icon/body_icon dropped; alert() and prompt() without message hangIPC.js:280-304
UInotify type/duration dropped in the app envIPC.js:320-344
UIrequestPictureInPicture() with no url resolves /undefined; no TypeError as documentedUI.js:1482
UISpinner has no nesting counterUI.js:3011,3100
UIsetWindow* with an unknown window_id leaves the promise pending (minor)IPC.js:656-1260
UItoggleWindow, requestUpgrade, openDevPaymentsAccount have no GUI handler (hang or no-op)UI.js:1805,1523,1200
FSOps return raw entries, not FSItemscaffold.js; mapV2EntryToV1.js
FSFSItem stubs watch/open/setAsWallpaper/versions/trash/metadata are empty but typedFSItem.js:196-290
FSstat cache key with uid onlystat.js:51-56,90
FSupload strict honoured only on the legacy path (minor)legacyBatchUpload.js:325
FSgetShares() with no path/uid sends ~/undefined instead of field_missing (minor)getShares.js:28
AIChatOptions.vision typed but never read from user paramschat.js:176-247
Eventshandlers.publishAll options typed HandlerOptions (includes replace) but only appUid is readlib/handlers.js:82
WorkersgetLoggingHandle().close unbound; no lowercase and no #authenticateIfNeeded (low)Workers.js:228-274
WorkersWorkerDeployment.errors typed, but create throws on failure so it never resolves with errorsWorkers.js:112
Networking'drain' never emitted; TLS handshake failure emits no close; early TLSSocket.write throwsPSocket.js:24; PTLS.js:69,125
Peerclose(reason) not sent to the peer; ensureTurnRelays rejects on a network throw despite "resolves either way" (low)Peer.js:775,918

AI (modules/ai, docs AI/)

FunctionItemIssueTag
chatChatOptions.visionTyped but silently dropped🐛🟡
chatoverloads(prompt, testMode, options) and (prompt, media, testMode, options) are documented but not typed🟡
chatstreamChatOptions has no stream. {stream:false} resolves to the AsyncIterable overload🟡
chatdriver, response, context_managementTyped and forwarded; not in chat.md🔵
ChatResponseusageDocumented but missing in the typedef. choices is typed but undocumented🟡🔵
ChatMessagerefusalTyped, not in chatresponse.md🔵
ImageContentthoughtSignatureUsed in the chat.md example; missing from the typedef🟡
ChatMessage{type:'file', puter_path} partsDocs only; typedef is loose (nit)🟡
listModelsreturnRecord<string, unknown>[]; docs promise id/provider etc.🟡
img2txttest_modeTyped, docs list only testMode🔵
img2txtOcrAnnotationFormatjson_schema/jsonSchema and schema/schemaDefinition are tied in the typedef; docs say independent🟡
txt2imgn typed but reserved; txt2img({prompt}, true) not in docsnit
txt2viddriverMissing from the options table🔵
txt2speech3000-char limitDocs/types say "less than 3000"; the impl allows exactly 3000 (tts.js:100)🔴
listEngines/listVoicesspeechifyMissing from the accepted-values lists and Objects🔵
listVoiceslistVoices(engine)Missing from the Syntax block🔵
speech2speechfile alias; camelCase and voice_id/model_id aliasesNot in docs🔵
speech2speechvoice_settingsDocs say Object|String; typedef only Record🟡
speech2txtresponse_formatExclude<string,'text'> collapses to string, so the return typing is wrong🟡

Apps / Auth / Perms / OS

FunctionItemIssueTag
Objects/app.mdfeedback_enabledTyped, not documented🔵
getUsers/usersuser_emailMissing from the getUsers docs🔵
createreturnTyped CreateAppResult without users/getUsers, which the impl adds🟡
checkNamereturn{name, available} not documented; no Apps.md tab🔵
Auth.whoamimethodPublic and typed, no docs page🔵
Auth.getUserunsignedThrows synchronously with 401; callback forms undocumented🔵
Objects/user.mdfeature_flags, hasDevAccountAccess, otp; email_confirmed and requires_email_confirmation are boolean|numberUndocumented or wrong🔵
Objects/monthlyusage.mdallowanceInfo.unitUndocumented🔵
Perms.request('email')null return when granted with no emailNot documented🔵
Perms.request('appData')own app resolves true with no prompt; check() rejects on unknown appNot documented🔵
os.user / os.versionTyped, no docs family🔵
PermsDeprecated aliases and grant/revoke are intentionally undocumentednote

FS (FileSystem/**, docs FS/)

FunctionItemIssueTag
FSItemuid, uuid, isDirectory, readURL, writeURL, metadataURLTyped, not in fsitem.md. fsitem.write data types are narrower in docs🔵
FSItemis_sharedDocumented on FSItem; only present via FSItemRead🟡
sign, readdirSubdomainsNo docs page🔵
movededupeName/dedupe_nameRead and documented, missing from MoveOptionsOwn🟡
readcacheIn neither types nor docs. byte_count "required with offset" is not enforced🔴 / 🔵
readdirno_subdomainsMissing from types and docs🔴
readdirconsistency, no_thumbs, no_assocsUndocumented. stream is not on ReaddirOptionsOwn🔵 / 🟡
statconsistencyUndocumented. stat(path) and legacy callbacks are not in the docs🔵
writecreateMissingAncestors, init, start, progress, abortUndocumented🔵
uploadname, parsedDataTransferItems, createFileParent, createMissingAncestors, shortcutTo, appUID, strictUndocumented🔵
uploaditemsImpl accepts DataTransferItem(List), single File/Blob, string and mixed arrays; docs list fewer🔵
uploadrejection shapeThe signed path (main) rejects with partial, failedItems[], failedPaths, completedItemCount, totalItemCount; only the legacy UploadBatchError is typed🟡
getReadURLoptions-object and callback overloads untyped (minor)🟡
mkdiraliases rename, recursive; shortcutTo undocumented (minor)🔵
sharerecipients alias; {teamHandle}; return fields type, thumbnail, owner, holderTeam, issuedByApp undocumented. uid array is untyped🔵 / 🟡
unshareimpl reads paths, uid[], recipients, and array recipients; types and docs match each other but are narrower🟡🔵 (minor)
getSharesholderTeam, anyone, pending missing from docs🔵
listSharedDocs list a narrower shape than Share🔵 (minor)
getShareLinkoptions-form item is untyped (minor); docs hardcode puter.com🟡

KV / Hosting / Workers

FunctionItemIssueTag
MAX_VALUE_SIZE399*1024; docs "400 KB" in set/update/add. Docs say bytes but the check uses .length (low)🔴
all opstrailing optConfig {appUuid, disableSharing}Typed and read everywhere; documented only partially (set.md)🔵
setoptConfig forms (3-arg, 4-arg, object, batch+optConfig, {items, optConfig})Not in the Syntax block🔵
flushDocs say "None"; impl accepts optConfig and callbacks. kv.clear alias undocumented🔵
get/del/add/incr/decr/flushObject forms (get({key}), add({key, pathAndValueMap})...)Neither typed nor documented (low)🔴
listoptConfig, top-level appUuid, trailing optConfig positionsUndocumented. fetchUntilFull "requires limit" is not enforced by the SDK🔵
Hosting.createdirPathDocs say required; impl accepts create(subdomain), but the type does not🔴
Hosting.updatedirPathOmitted or empty disconnects the directory (root_dir:null); not documented🔵
Hosting create/get/update/deleteFull host (x.puter.site) is stripped to the labelUndocumented🔵
Hosting.listLegacy callbacks undocumented. limit-only return is inconsistent with workers/list.md wording🔵
Workers.getLoggingHandleNo docs page🔵
Workers.createName lowercased; also reads and writes KV key user-workers; undocumented🔵
Workers/router.mdMissing router.custom, routing, handleCors; handler requestor and waitUntil🔵
Workers/types.mdDeprecated globals my, myself, puter_auth, puter_endpoint not flagged (low)🔵

Networking / Peer / Drivers

FunctionItemIssueTag
net.generateWispV1URLNo docs page🔵
Socket/TLSSocket'drain' typed and never emitted🐛🟡
Socket.writecallback param undocumented🔵
Socket.addListenerDocs list 4 events; types allow more; tls* names never fire on plain Socket🔵
TLSSocket.onAliases data/open/close to tls* undocumented🔵
TLSSocketDocs say close follows error; it doesn't. write before tlsopen throws🐛🔵
net.fetchInput is typed RequestInfo|URL, docs say string. Rejects with plain strings. Always sends Connection: close and does not follow redirects🔵
Peer.close(reason)Reason is never delivered to the peer🐛🔴
connect/serveoptions.port is read by the impl; absent from types and docs (low)🔴
Peer.mdcreateGuestGrant missing from the Functions list. connect.md mentions only invite codes, but room names work🔵
PuterPeerServer.start; PeerConnection createOffer etc.Public and typed, undocumented (low, plumbing)🔵
AppConnectionclose payload statusCode; response, appInstanceID, targetAppInstanceID, messageTarget undocumented🔵
Drivers.callLoose ...unknown[]; puter.call is untyped; no docs page (low)🟡

Email / Events / Teams

FunctionItemIssueTag
Email.sendNo docs page. Docs and the class JSDoc wrongly call it the "previous name" of sendTransactional. options is typed Record<string, unknown>. EmailSendMethod has a stale "legacy alias" comment🔵🟡
Events.handlers.publishAlloptions.replace ignored🐛🟡
Team typedefdirectoryEnabled and require2fa descriptions are interleaved🟡
Teams list.mdrequire2fa missing from the Team table🔵
Teams.updateUpdateTeamAttributes lacks require2fa (internal type)🟡
Teams.listMembersPublic and typed; no docs page🔵
Teams list/listDirectoryError table mentions a blank uid (cosmetic)🔵

UI (UI.js, src/gui/src/IPC.js, docs UI/)

FunctionItemIssueTag
launchAppbackgroundJSDoc says it still appears in the taskbar; docs and impl say otherwise🟡
launchAppfile_paths (godmode only, first path signed only); items (only [0] used); app_name, callback, "name#(as)pseudonym"Undocumented🔵🟡
prompt3rd-arg {defaultValue}Typed, missing from docs🔵
showOpenFilePickerInline param type ignores FilePickerOptions (path, accept: string|string[]). Docs type accept as String but show an array🟡🔵
showDirectoryPicker, promptUnused typedefs (cosmetic)🟡
connectToInstance, isWorkingActive, menubar()No JSDoc or @internal; they leak into the types🟡
puter.exitNo JSDoc; non-number is coerced to 1🟡
instancesOpenPromise<unknown>; the GUI returns a count; no docs🟡🔵
setMenubarMenuItem.id undocumented🔵
requestPermissionTyped and implemented; no docs anywhere🔵
enable/disableMenuItem, setMenuItemIcon, setMenuItemIconActive, setMenuItemCheckedTyped, with IPC handlers; no docs🔵
requestEmailConfirmation, getEntriesFromDataTransferItems, toggleWindow, requestUpgrade, openDevPaymentsAccountNo docs (some should be marked @internal)🔵
AppConnectionresponse.launchResult and launched, appInstanceID, appUid, privateAccess missing from AppConnection.md🔵
authenticateWithPuterReturns undefined outside the web env; undocumented🔵

Utils / top-level wiring

FunctionItemIssueTag
Utils.mdprint blurb ("console") is wrong: it appends to document.body; env blurb says "environment variables" but it is a runtime string🔵
Utils.mdputer.exit, puter.getUser, puter.args, puter.appName, puter.authToken, puter.on/off (incl. auth.reauth_required), puter.driversUndocumented🔵
appID.mdCan be undefined; URL-param and localStorage sources not mentioned (minor)🔵
puter.print / exit / getUserNo JSDoc, so the types are inferred and any🟡
Puter classappID, appName, appDataPath, whoami, call are assigned dynamically and have no type declarations🟡
index.d.tsNot exported: WorkerPage, TeamDirectoryEntry, UpgradePromptContext, the Peer event classes. No phantom exports were found🟡
Objects.md5+ pages are not in the index. /Objects/AppConnection/ casing (low)🔵

Activity

0

No activity yet.