Commit Graph
20 Commits
Author SHA1 Message Date
dckc 7d2100bf77 fixup! docs: goal tree and rules track the 1c cache
1e: the fill is driven from the webkey page over Cap'n Web.

Generated-by: Claude Opus 5.5
2026-10-07 04:32:44 -05:00
dckc 3706e6de2c fixup! docs: webkeys — ids as bearer capabilities, kept out of URLs
The cache page now follows the paper's form (fragment + skeleton page),
with the XHR replaced by a Cap'n Web call taking the key in-band.

Generated-by: Claude Opus 5.5
2026-10-07 04:32:44 -05:00
dckc 3d0e3aea69 chore: Update pnpm-lock.yaml
Generated-by: Claude Opus 5.5
2026-10-07 04:32:44 -05:00
dckc 8c221abe6f diigo-cache: fill from a webkey page over Cap'n Web
Starting a fill no longer POSTs the cache id to /_fill. Instead:

- the created page links the cache's webkey, /cache/#<cache id>: a
  skeleton page, the same for every key, that reads the key from the
  fragment (never sent to the server or in a Referer)
- its script trades the key in-band for a capability over Cap'n Web at
  /api: CacheApi.cache(key) returns a CacheCap facet (fill, status,
  fingerprint, the public companion's fill) and never the DO's wiring
  methods; malformed and unknown keys get one refusal that never echoes
  the key, and each refusal is logged without it
- then calls startFill(): trade and call pipeline into one round trip
- the worker serves capnweb's browser build itself at /_capnweb.js (a
  wrangler Text rule), so no third-party script sits beside the key

The /_fill route and its forms are gone. Tests run the real capnweb
client against the worker (fetch routed to worker.fetch).

Generated-by: Claude Opus 5.5
2026-10-07 04:32:44 -05:00
dckc fbe2538345 fixup! docs: goal tree and rules track the 1c cache
1e done: compressed to a pointer at the API and tests.

Generated-by: Claude Opus 5.5
2026-10-07 04:25:38 -05:00
dckc 31ded9735b diigo-cache: fill job — a button that grabs every page (goal 1e)
POST /_fill (cache id in the body; target private|public; action
start|stop) starts or stops a background walk of every diigo page into
the cache. DO alarms advance it pagesPerStep pages per step (default
20), a second apart; progress (FillStatus) is stored in the DO after
each page, so it survives eviction. Cached pages are skipped; starting
while running rejoins the job; a stop mid-step wins; a failure is
recorded with its reason and logged once. The created page gets fill
buttons; the public page shows "filling: n of m pages".

Fill state is new, additive DO storage (fill, fillStep): no existing
state changes meaning.

The 13 fill specs are unskipped and green, plus one: a fill makes one
diigo call per page fetched.

Generated-by: Claude Opus 5.5
2026-10-07 04:25:38 -05:00
dckc 530942f5d9 diigo-cache: dispose RPC stubs after each fetch; one fetch per miss
Two bugs in page()'s miss path, found while building the fill job:

- the webapp stubs (app, pathjoin, query) were never disposed, which
  kept the DO from being evicted (evictDurableObject hung after a single
  miss); they are now disposed once the page is in hand
- a miss on page n > 1 also fetched page 1 and threw it away, doubling
  diigo calls; every page carries `total`, so only page n is fetched

Regression test: a miss, then eviction, then a cache hit. tsconfig adds
the ESNext.Disposable lib for Symbol.dispose.

Generated-by: Claude Opus 5.5
2026-10-07 04:25:23 -05:00
dckc cf5ccce4e2 diigo-cache: fill job, designed as skipped specs (goal 1e)
A button that grabs every page into a cache: owner-only POST /_fill
(cache id in the body; target private|public; action start|stop),
advanced by DO alarms a few pages per step, progress stored in the DO
(new, additive state) so it survives eviction, cached pages skipped,
a rerun rejoins the running job, failures recorded and logged once.
The created page gets the button; the public page shows progress.

startFill/fillStatus/stopFill on PagedCache are JSDoc'd stubs; 13
specs are describe.skip until it lands (alarms driven by
runDurableObjectAlarm, eviction by evictDurableObject).

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc 3e5e139dea diigo-cache: date windows and search, designed as skipped specs (goal 1d)
The public page's filters, toward the weekly PESOS roundup (#23):
?days=N (7/30/90/365 presets), gmail-style after/before (UTC days,
half-open: after inclusive, before exclusive; yyyy/mm/dd accepted), and
q (words, "phrases", #tags exact against diigo's comma-separated tags,
- negation); q alone searches the last 365 days and says so; malformed
filters are a 400. Filtering walks diigo's updated-desc pages from 1 and
stops at the window, so ?days=7 costs one page.

src/query.ts is the typed, JSDoc'd API (stubs that throw); 22 specs are
describe.skip until it lands. The fake webapp gains a dated account.

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc 860bbee2b5 diigo-cache: public list shows each bookmark's date first
The list is in diigo's updated order; each item now leads with its
updated_at as Date#toISOString() (diigo sends epoch seconds; updatedISO
converts, tested), or "(no date)".

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc 80c9279825 diigo-cache: test that a cached page replays fetch-time order
A hit must replay diigo's order as fetched (page_members.pos), not a
column sort. The fake webapp's link_id and updated_at are scrambled so
neither column sorts back into diigo's order; ordering the replay by
updated or item_id fails the new test.

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc a1b1640e06 chore: Update pnpm-lock.yaml
Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc 0cfa9d204e diigo-cache: own test toolchain; pnpm lint, pnpm test
vitest, @cloudflare/vitest-plugin, and typescript are devDependencies
here instead of being borrowed from diigo-bookmarks through hand-made
node_modules symlinks and a deep-path import.

- lint: wrangler types, then tsc over src/ and tests/ (Cloudflare's
  documented typecheck shape: regenerate types, then tsc)
- test: vitest run
- tests/tsconfig.json per the vitest-plugin docs; the dangling
  typecheck script (tsconfig.check.json never existed) is gone

Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -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 d0a9b899f2 docs: goal tree and rules track the 1c cache
- checklist: 1c (diigo-dump evolves into a bookmark cache) with its
  create-flow, id-wiring, and verification subgoals
- notes: diigo-cache replaces diigo-dump in What-we-built
- AGENTS: no worker secret since 1c; durable state — be LOUD and
  conservative about breaking changes to stored DB state; pointer to
  the workspace skills for commit trailers

Generated-by: opencode (GLM)
Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc 6f409fc83a diigo-cache: bookmark cache in Durable Objects (goal 1c)
The dump worker becomes a page cache: a hit is served from DO SQLite
storage with no diigo call; a miss asks the webapp instance in the
cache's wiring and etches the page.

- two independent caches, one behavior (PagedCache): DiigoCache keeps
  every item; PublicCache keeps shared items only, dropping private
  rows before they are stored; served at /public/<username> (HTML page
  form, or JSON)
- create flow on one port: /_connect relays webapp's mint form, /_mint
  proxies the mint, /_wire wires a private or public cache; /_publish
  adds a public cache later
- ids are webkeys: kept out of URLs (POST bodies), shown and logged
  only as a hash fingerprint; saved to the password manager under the
  holder's petname (never sent to the server)
- items keyed on diigo's link_id; username from u_name; unkeyable
  items and every failure path are logged; each page read logs hit/miss
- tests run the real worker + DOs in the vitest pool against a fake
  webapp (tests/fake-webapp.js)

Generated-by: opencode (GLM)
Generated-by: Claude Opus 5.5
2026-10-07 04:19:54 -05:00
dckc c5e433cc9c docs: webkeys — ids as bearer capabilities, kept out of URLs
Close's web-key pattern (W2SP 2008) and its Waterken precursors, applied
to diigo-cache: cache ids are webkeys in substance; they travel in POST
bodies, never query strings, and a one-way hash (swissHash discipline)
stands in for them where log correlation is wanted.

Generated-by: opencode (GLM)
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
dckc 58be2ccaf8 refactor: rename diigo-dump to diigo-cache
Pure rename ahead of the dump worker's evolution into a bookmark cache
(goal 1c), so history follows the files. The diigo-login helper script
is dropped: the cookie now enters through webapp's mint form, never a
local script.
2026-10-07 03:25:56 -05:00
dckc 4a8828086e fixup! feat(diigo-dump): session-cookie dump worker, manual test passing
fixup: scrub failed API-key ping from checklist

diigo-ping never authenticated (Diigo 401); the working path is the
session-cookie dump worker. Renumber steps, note the scrub with the
reason, and drop the ping how-to.

Generated-by: opencode (GLM)
2026-10-06 21:36:44 -05:00