feat(diigo-dump): fluent WebApp over RPC + bound fetch + logged errors
Restore the fluent client from mm-diigo's WebApp.js as RpcTarget classes (src/webapp.ts): WebApp with pathjoin/query/withHeaders/cookies/get/post, flower-style unions (NuxiNL/flower v0.11, Jan 2019 — merge only if no shared key contradicts), pathjoin containment guard; RateLimitedWebApp shares one gate across all derived handles, enforced at get/post only. src/diigo.ts ports makeDiigoAPI and the dumpBookmarks generator. RPC surface: DiigoService (WorkerEntrypoint) with open() handing a rate-limited stub whose cookie is attached server-side only, and dumpNdjson. Promise pipelining makes a whole chain a single round trip. Divergences from the original for the RPC setting: - url is a private field: a public property on an RpcTarget is readable by stub holders, and query strings can carry credentials - Error messages carry no header/param values; URLs have query stripped (structured details via @endo/errors deferred until node_modules) - fetch default is fetch.bind(globalThis): a detached fetch throws 'Illegal invocation' in workerd (found live, fixed, verified 200) - dumpPage/open log failures via console.error for observability README documents config, RPC use, and each divergence. Generated-by: opencode (GLM)
This commit is contained in:
1 parent
4a8828086e
commit
309f003fa3
6 files changed
+404
-35
No files matched your search
+31
-3
@@ -16,9 +16,37 @@ with the session cookie and shows status, `total`, and the JSON items in a
|
||||
read-only `<pre>`. GET `/` is inert — dumps happen only on explicit submits.
|
||||
|
||||
Provenance notes: the `user-agent` / `x-requested-with` headers and the
|
||||
`interact_api` endpoint mirror the original script; the ocap-style
|
||||
attenuation there (pathjoin/query/rateLimit in WebApp.js) is reduced here to
|
||||
a plain fetch with the cookie never exposed beyond this one call.
|
||||
`interact_api` endpoint mirror the original script; the fluent client from
|
||||
`WebApp.js` is restored in `src/webapp.ts` with `WebApp` and the rate-limit
|
||||
wrapper as `RpcTarget` subclasses. `src/diigo.ts` holds `makeDiigoAPI` and
|
||||
the `dumpBookmarks` generator; `DiigoService.open()` hands an RPC caller a
|
||||
rate-limited stub with the cookie attached only on the server side, and
|
||||
promise pipelining makes a whole `pathjoin().query().get()` chain a single
|
||||
round trip. One deliberate divergence from the original: `url` is a private
|
||||
field, not a public property — on an `RpcTarget`, a public property is
|
||||
readable over RPC (a property read is an argument-less method call), and a
|
||||
query string can carry credentials, so a public `url` would leak them to any
|
||||
stub holder.
|
||||
|
||||
## RPC use (from another worker, same account)
|
||||
|
||||
```jsonc
|
||||
// wrangler.jsonc of the caller
|
||||
"services": [{ "binding": "DIIGO", "service": "diigo-dump", "entrypoint": "DiigoService" }]
|
||||
```
|
||||
|
||||
```ts
|
||||
import { dumpBookmarks } from "./diigo.js";
|
||||
|
||||
const stub = env.DIIGO.open(); // rate-limited, cookie stays server-side
|
||||
// pipeline: one round trip for the whole chain
|
||||
const first = JSON.parse(await stub.pathjoin("load_user_items")
|
||||
.query({ sort: "updated", count: 24, page_num: 1 }).get());
|
||||
// or run the whole dump in this worker's address space:
|
||||
for await (const item of dumpBookmarks({ diigoAPI: stub, pages: 2 })) {
|
||||
console.log(item);
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
Reference in new issue
Block a user