Commit Graph
8 Commits
Author SHA1 Message Date
dckc ff2e7841f2 capsite/webapp: postForm, a multipart POST that can echo a cookie into a field
Some sites check a double-submit token: the session value sent as a
cookie and again in the form body. postForm(fields, echoCookies) builds
a multipart body and copies the named cookies (from the header store,
at send time) into fields, so the caller never sees the value.

It returns a Reply instead of throwing on non-OK: status, content type,
content-disposition, the redirect location with its query stripped, and
the body as bytes (the caller decodes, e.g. per a charset the body
declares). Redirects are not followed, so an expired session shows up
as a 3xx. Set-Cookie is not passed back. Errors name keys, never values.

Generated-by: Claude Opus 5.5
2026-10-11 14:22:09 -05:00
dckc 3f711a5f4b capsite/webapp: the cookie's store is the owner's, apart from the instance
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
2026-10-09 02:32:22 -05:00
dckc 10414c2ce6 capsite/webapp: rotate the cookie in place
The cookie moves out of the immutable init into a MapStore (key shape
"cookie", value M.string()) in the instance's DO storage. Handles get
its read-only view via the new WebApp.withHeaderMap, which reads at
every send, so a rotation reaches handles already out and the webapp
id, and with it the cache's wiring, stays put (checklist goal 6).

Whoever holds the id can rotate, by RPC (WebAppFactory.cookies(id)) or
POST /at/<id>/cookie; the diigo account owner revokes by logging out.

Durable state: instances minted earlier keep the cookie in
init.headers. The first handle() moves it to the store and rewrites
init without it, in one transaction. Code from before this commit
would then see no cookie, so rolling back past it needs the reverse
move.

webapp gains a package.json and a vitest workerd pool for the tests.

Generated-by: Claude Opus 5.5
2026-10-09 02:32:22 -05:00
dckc 0af7a3ea6c diigo-cache: README sells and gets to TADA; CONTRIBUTING updated
New README: two sentences, the dev run through connect, fill, and a
filtered public page, then features. CONTRIBUTING gains the 1d
filters and its own run and deploy sections instead of pointing at
the checklist; links to the old README now point at CONTRIBUTING.

Generated-by: Claude Opus 5.5
2026-10-09 01:27:45 -05:00
dckc 22ae9a2b61 build: tsconfig noEmit for diigo-cache and webapp
wrangler bundles; tsc only checks. Without noEmit a bare `tsc` wrote
compiled .js beside the sources (a stray webapp/src/index.js).

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc cbf1435571 webapp: mint form servable by a proxying worker
wrangler's multi-config dev binds aux workers but doesn't serve their
HTTP, so diigo-cache relays webapp's own mint form:

- WebAppFactory gains fetch(): the HTTP surface over the binding
- GET /form?render=1 leaves the form action as a placeholder the proxy
  points at its relay; ?title= sets the page title
- a dedicated cookie field (sugar for the cookie header; must agree
  with the JSON if both are given)

Generated-by: opencode (GLM)
2026-10-07 04:19:54 -05:00
Connolly c587481761 docs: de-duplicate run instructions, READMEs track current code
diigo-dump/README was stale three ways: described the pre-DO connect
flow (askpass + DIIGO_COOKIE, both retired), referenced deleted files
(src/webapp.ts), and named the old entrypoint. Rewritten against
current code (DiigoBridge, DO storage state surface, state-aware
/_connect); run/connect/deploy instructions now live only in the
capsite checklist, linked (intra-repo docs link rather than repeat).
webapp/README Run section: port note corrected (two-config run makes
diigo-dump the primary) and pointed at the checklist as the source.

Generated-by: opencode (GLM)
2026-10-06 23:42:02 -05:00
Connolly 3f8e77eaa2 feat: webapp DO factory worker; diigo-dump as its consumer
webapp/ (new, site-agnostic, independently deployable):
- WebApp: fluent client (pathjoin/query/withHeaders/cookies/get/post)
  as RpcTarget; flower-style unions cite NuxiNL/flower v0.11 (Jan 2019);
  url/headers private (RpcTarget property reads are RPC); Error messages
  carry no header/param values; query-stripped URLs only
- WebAppDo: per-instance authority in DO storage (survives eviction);
  one-shot configure(), refuses different-url re-configure
- WebAppFactory: newWebApp(init) -> {id, app}, at(id); ids are bearer
  capabilities and are not logged
- HTTP surface: GET / mint form (secret header keys render blank),
  POST / mint (form or JSON), POST /at/<id> drive-by-capability
- types via wrangler types (worker-configuration.d.ts, gitignored)

diigo-dump/: now a webapp consumer. The diigo knowledge is only the
mint call: url=interact_api/, UA + x-requested-with, cookie, 500ms gate.
- src/webapp.ts, src/diigo-web.ts deleted (webapp's are canonical);
  diigo.ts slimmed to dumpBookmarks + PagedGet
- /_connect is state-aware: connect form pre-mint; health check
  (count=1 probe) + re-mint path post-mint; home-page link relabeled
- mint success page: narrow field + copy button (attribute-quoting
  fixed; id in x-diigo-web-id header for scripts)
- scripts/diigo-login: askpass flow, marked OBSOLETE (page flow is
  the primary); speaks the form protocol; writes only DIIGO_WEB_ID —
  the cookie lives in DO storage, never on disk
- package.json: dev = wrangler dev -c wrangler.jsonc -c ../webapp/...
  (verified: Ready on :8787, GET / 200, /_connect 200);
  wrangler ^4.148.0 devDependency after node_modules was cleaned

TODO(webapp) in webapp/README.md: proxy-page vs primary-worker mint
form; reconsider as the UI grows.

Generated-by: opencode (GLM)
2026-10-06 23:30:27 -05:00