Repository navigation
feat(db): window.storage, the Claude artifacts storage API - #20
Merged
Merged
Conversation
notsuhas
force-pushed
the
feat/window-storage
branch
4 times, most recently
from
October 9, 2026 13:07
406b12d to
2a8ec5f
Compare
notsuhas
marked this pull request as ready for review
October 9, 2026 13:07
Pages can now keep small values across visits with the same API Claude
artifacts expose: window.storage.get/set/delete/list(key, ..., shared).
Personal keys belong to the viewer; shared keys to everyone who can open the
site. Nothing is stored unless a page calls set.
- site_kv table (siteId, ownerId '' for shared, key, value), 200-char keys,
1 MB values, 20 MB per site
- /api/_data/_kv/{personal|shared}[/key] behind the data plane; reads need
read, writes need create (every viewer), checked in the capability gate
- the SDK defines window.storage and sends it through the viewer's broker as
a single 'kv' op, so the page still never holds a credential
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- /_kv is its own sub-app with its own capability table, mounted before the method gate; no path regex. Anything under /_kv it doesn't route (PUT /_kv/shared, DELETE /_kv/personal) falls through to the document routes and keeps the owner-only write rule - quota is checked and written in one INSERT … SELECT … ON CONFLICT … RETURNING statement, so concurrent sets can't jointly overshoot - sizes are UTF-8 bytes (bytes column); 1 MB per value, 5 MB per viewer for personal keys, 20 MB per site - a trigger removes a deleted user's personal keys - key/value limits and the key validator live in packages/shared/kv.ts and are used by both the broker and the server; the broker parses kv calls into a typed union - responses carry `shared`; docs warn that shared keys are writable by any viewer and unattributed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, quota pools Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One viewer could fill the site-wide key/byte cap and lock everyone out. Each pool (a viewer's personal keys, the shared keys) now caps itself, so the site counters and their triggers go. list uses a key range instead of LIKE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d keys Shared keys were writable by anyone who could open a site, with no attribution. Every key now belongs to one viewer (userId FK, cascades with the user); `shared = true` rejects and points at postplan.db. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
notsuhas
force-pushed
the
feat/window-storage
branch
from
October 9, 2026 13:10
2a8ec5f to
789cae6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #18. Adds
window.storage, the storage API Claude artifacts expose, so sandboxed pages can keep small values across visits.Keys are private to each viewer. Claude's
shared = trueis refused with an error pointing atpostplan.db; nothing is shared across viewers. Nothing is stored unless a page callsset, and rows go with the site and with the user.site_kvtable (siteId, userId, key, value, bytes), both FKs cascade. Keys up to 200 chars with no spaces, slashes or control chars; values up to 1 MB; 5 MB and 1,000 keys per viewer per site, checked and written in one statement./api/_data/_kv[/key]is its own terminal sub-app with its own capability table: reads needread, writes needcreate.listis a case-sensitive prefix match over the primary key, at most 1,000 keys.postplan.dbcollection names starting with_are now reserved (prod has no documents, so nothing breaks).Migration:
0036_site_kv— apply before deploying.Testing
bun run test: per-viewer isolation, quota by bytes and by key count, case-sensitive prefix list, user delete cascade, read-only token can't write,/_kvis terminal; broker mapping and validation tests. Typecheck, biome, dead-code clean.visits=2) andset(..., true)rejected.🤖 Generated with Claude Code