Companion to #10 (different surface: the extended API's read path is the durable-streams server, not the engine). Investigation of ../electric-ds-rust-1m (packages/durable-streams-rust) found it already ships the cache protocol we need, while the npm @durable-streams/server we deploy today has none of it:
- Historical offset-addressed reads: immutable ranges served
public, max-age=60, stale-while-revalidate=300 + range-derived ETag ("{stream}:{start}:{end}"), with If-None-Match → 304 (handlers.rs:1970-2019).
- CDN request collapsing built in:
stream-cursor header + cursor param, 20s time buckets with 1–180-interval jitter (store.rs:1237-1262).
- Tail/
now reads correctly no-store + no ETag; stream-next-offset / stream-up-to-date on everything.
Scope:
- Make the Rust DS server the client-facing feed path for production deployments (docker overlay + docs); keep the npm server for tests/demos. (Pending the broader "which DS is the production target" decision — issue text to be updated if that lands differently.)
- Client: send
cursor on long-polls and honor 304s (packages/client stream reader currently uses only offset + live=long-poll).
ShapeHandle.streamUrl should be the CDN-fronted URL (config knob on the API server), not the origin DS address.
- Optional upstream patch to ds-rust: per-stream cache policy at create time (e.g.
stream-cache-max-age) so initial-snapshot chunks can get Electric's week-long tier instead of the hardcoded 60s. Requires new StreamConfig/Meta fields, parsing in handle_create, echo in read builders, and relaxing the &'static str header-name type in api.rs (handlers.rs:120,431-465, store.rs:38-48).
Non-goals: engine /v1/shape caching (#10); auth on feed URLs (auth issue, TBD).
🤖 Generated with Claude Code
Companion to #10 (different surface: the extended API's read path is the durable-streams server, not the engine). Investigation of
../electric-ds-rust-1m(packages/durable-streams-rust) found it already ships the cache protocol we need, while the npm@durable-streams/serverwe deploy today has none of it:public, max-age=60, stale-while-revalidate=300+ range-derived ETag ("{stream}:{start}:{end}"), with If-None-Match → 304 (handlers.rs:1970-2019).stream-cursorheader +cursorparam, 20s time buckets with 1–180-interval jitter (store.rs:1237-1262).nowreads correctlyno-store+ no ETag;stream-next-offset/stream-up-to-dateon everything.Scope:
cursoron long-polls and honor 304s (packages/clientstream reader currently uses onlyoffset+live=long-poll).ShapeHandle.streamUrlshould be the CDN-fronted URL (config knob on the API server), not the origin DS address.stream-cache-max-age) so initial-snapshot chunks can get Electric's week-long tier instead of the hardcoded 60s. Requires newStreamConfig/Metafields, parsing inhandle_create, echo in read builders, and relaxing the&'static strheader-name type inapi.rs(handlers.rs:120,431-465,store.rs:38-48).Non-goals: engine
/v1/shapecaching (#10); auth on feed URLs (auth issue, TBD).🤖 Generated with Claude Code