Letting the instance id rotate the cookie let its holder (the cache, or
whoever learns the id) swap in another account's session, which the
owner's logout would not stop. Now mint makes two things: the instance,
and a header store (lib's MapStoreDo, shaped ("cookie", { keyShape:
"cookie", valueShape: M.string() })). The instance id is authority to
use the cookie; the store id, for the account owner, to rotate (PUT
/store/<storeId>/cookie, or WebAppFactory.store) or revoke (DELETE).
Instances read the store's read-only view at every send, via init's new
headerStore.
This replaces the in-instance cookie store and its migration: instances
minted earlier keep their cookie in init.headers, untouched, and simply
cannot rotate. The MapStoreDo class arrives as wrangler migration v2
(additive).
Generated-by: Claude Opus 5.5
webapp
DO-backed fluent web client factory: site-agnostic. Deploy once; instances
are attenuated handles whose ids are bearer capabilities — anyone
holding the id string can drive the instance; nobody without it can.
TODO: this proxy-page flow (see diigo-cache CONTRIBUTING) vs running webapp as
the primary worker (wrangler dev -c ../webapp/wrangler.jsonc -c ../diigo-cache/wrangler.jsonc)
so its own port serves the mint form directly; reconsider when the UI
grows past a form or two.
HTTP surface
GET /— the mint form. Prefill via query string:?url=…&headers=<urlencoded JSON>&msPerCall=…&title=…; secret header keys (cookie, authorization, proxy-authorization) render blank — paste them at mint time; never echoed back. A dedicatedcookiefield is sugar for thecookieheader (if the JSON also has one, they must agree).GET /form?render=1&…— the same form for a proxying worker (diigo-cache's/_connect): the action is left as anACTIONplaceholder for the proxy to point at its own relay.POST /— mint. Form-encoded (that page) or JSON{url, headers, msPerCall}(service-style). Responds{id, storeId}(andx-webapp-id,x-webapp-store-id). Neither id is logged: possession is authority.POST /at/<id>— drive an instance by capability: JSON{path?, query?, method?, body?}→ the fluent chain →{status, text}(or{error}; messages carry no header/param values).PUT /store/<storeId>/<key>— set a header-store entry (JSON value body), e.g.PUT /store/<storeId>/cookiewith"session=…"rotates the cookie;DELETEremoves it. →{ok: true}(or{error}; messages carry no keys or values).
RPC surface (same-account workers; binding entrypoint: "WebAppFactory")
fetch(request)— the HTTP surface above, over the bindingnewWebApp({url, headers?, msPerCall?})→{id, storeId, app}— the fluent stub; promise pipelining makes a wholepathjoin().query().get()chain a single round tripat(id)— the fluent stub for a previously-minted instancestore(storeId)— a header store, with full authority:set("cookie", …)rotates the cookie under every handle already out
The header store: two ids, two authorities
Mint makes two things: the instance, and a header store (a MapStoreDo
from the capsite lib, shaped
("cookie", { keyShape: "cookie", valueShape: M.string() })). A cookie
header goes into the store, not the instance's init; the instance reads
the store's read-only view at every send.
- the instance id is authority to use the cookie: it goes to the cache's wiring.
- the store id is authority to choose it: it stays with the account
owner, who can rotate it (log in again,
PUT) or revoke it (DELETE, or log out).
Kept apart because whoever can choose the cookie can swap in another account's session: if the cache's id could rotate, a leaked instance id would let Mallory fill the cache (and its public page) with her own bookmarks, and the owner's logout would not stop it.
Instances minted before header stores keep their cookie in
init.headers, unchanged; they work as before and cannot rotate.
Run
pnpm test # header store + rotation (vitest, workerd pool)
npx wrangler dev # → its own ready line (usually :8787 with the
# two-config diigo-cache run; standalone, :8788)
Status: mint + drive exercised end-to-end in the combined dev run (through diigo-cache's create flow, 2026-10-07); not yet deployed. See ../capsite-checklist.md — the single source for run/connect/deploy instructions.