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)
This commit is contained in:
Connolly committed 2026-10-06 23:30:27 -05:00
1 parent 309f003fa3
commit 3f8e77eaa2
14 files changed
+1650 -329

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
# diigo-login: OBSOLETE but kept for terminals: superseded by the /_connect
# page flow (paste the cookie in the browser form; no clipboard/askpass).
# Prompt for the diigo.com session cookie via SSH_ASKPASS, verify it
# against the interact_api (one page), mint the webapp instance via the
# running dev server, and write the instance id to stdout (for
# `>> .dev.vars`). The cookie itself lives only in the DO's storage —
# never on disk, never in logs.
#
# usage: pnpm -s diigo-login >> .dev.vars (dev server must be up; needs
# a display for the GUI prompt)
set -eu
: "${SSH_ASKPASS:=/usr/bin/ssh-askpass}"
export SSH_ASKPASS
# the prompt text (SSH_ASKPASS_PROMPT is what ksshaskpass/gnome-askpass read)
export SSH_ASKPASS_PROMPT="diigo.com login: paste the Cookie header from devtools"
cookie=$(DISPLAY="${DISPLAY:-:0}" "$SSH_ASKPASS" 2>/dev/null) || {
echo "$0: askpass failed (need a display; or export SSH_ASKPASS yourself)" >&2
exit 1
}
[ -n "$cookie" ] || {
echo "$0: empty cookie" >&2
exit 1
}
# verify before committing anything: the endpoint the worker will use,
# with the same headers WebApp will send
target='https://www.diigo.com/interact_api/load_user_items?sort=updated&count=1&page_num=1'
status=$(curl -s -o /dev/null -w '%{http_code}' \
-H "cookie: $cookie" \
-H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20100101 Firefox/141.0' \
-H 'x-requested-with: XMLHttpRequest' \
"$target")
[ "$status" = 200 ] || {
echo "$0: diigo said $status for that cookie; not writing .dev.vars" >&2
exit 1
}
# mint the webapp instance (persist id: the instance keeps the cookie, so
# re-running this mint only replaces an *invalid* cookie). /_mint speaks
# the browser form protocol: proxyMint is html, not json.
minted=$(curl -s -D /tmp/opencode/diigo-mint-headers -X POST http://localhost:8787/_mint \
--data-urlencode "cookie=$cookie") || {
echo "$0: could not reach the dev server at :8787 (is it up?)" >&2
exit 1
}
webapp_id=$(grep -i '^x-diigo-web-id:' /tmp/opencode/diigo-mint-headers | tr -d '\r' | awk '{print $2}')
[ -n "$webapp_id" ] || {
echo "$0: mint failed; server said: $(printf '%s' "$minted" | tr -d '\n' | head -c 200)" >&2
exit 1
}
printf 'DIIGO_WEB_ID="%s"\n' "$webapp_id"