@catalyst-cloud/sdk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +92 -0
  2. package/dist/browser.d.ts +9 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.js +24 -0
  5. package/dist/browser.js.map +1 -0
  6. package/dist/live-sync-client.d.ts +128 -9
  7. package/dist/live-sync-client.d.ts.map +1 -1
  8. package/dist/live-sync-client.js +369 -51
  9. package/dist/live-sync-client.js.map +1 -1
  10. package/dist/replica/browser/apply.d.ts +29 -0
  11. package/dist/replica/browser/apply.d.ts.map +1 -0
  12. package/dist/replica/browser/apply.js +59 -0
  13. package/dist/replica/browser/apply.js.map +1 -0
  14. package/dist/replica/browser/browser-lock.d.ts +25 -0
  15. package/dist/replica/browser/browser-lock.d.ts.map +1 -0
  16. package/dist/replica/browser/browser-lock.js +91 -0
  17. package/dist/replica/browser/browser-lock.js.map +1 -0
  18. package/dist/replica/browser/browser-replica.d.ts +237 -0
  19. package/dist/replica/browser/browser-replica.d.ts.map +1 -0
  20. package/dist/replica/browser/browser-replica.js +952 -0
  21. package/dist/replica/browser/browser-replica.js.map +1 -0
  22. package/dist/replica/browser/db.worker.d.ts +2 -0
  23. package/dist/replica/browser/db.worker.d.ts.map +1 -0
  24. package/dist/replica/browser/db.worker.js +40 -0
  25. package/dist/replica/browser/db.worker.js.map +1 -0
  26. package/dist/replica/browser/delta-queue.d.ts +187 -0
  27. package/dist/replica/browser/delta-queue.d.ts.map +1 -0
  28. package/dist/replica/browser/delta-queue.js +328 -0
  29. package/dist/replica/browser/delta-queue.js.map +1 -0
  30. package/dist/replica/browser/ports.d.ts +39 -0
  31. package/dist/replica/browser/ports.d.ts.map +1 -0
  32. package/dist/replica/browser/ports.js +144 -0
  33. package/dist/replica/browser/ports.js.map +1 -0
  34. package/dist/replica/browser/protocol.d.ts +129 -0
  35. package/dist/replica/browser/protocol.d.ts.map +1 -0
  36. package/dist/replica/browser/protocol.js +12 -0
  37. package/dist/replica/browser/protocol.js.map +1 -0
  38. package/dist/replica/browser/seed-read-gate.d.ts +13 -0
  39. package/dist/replica/browser/seed-read-gate.d.ts.map +1 -0
  40. package/dist/replica/browser/seed-read-gate.js +36 -0
  41. package/dist/replica/browser/seed-read-gate.js.map +1 -0
  42. package/dist/replica/browser/seed-session.d.ts +23 -0
  43. package/dist/replica/browser/seed-session.d.ts.map +1 -0
  44. package/dist/replica/browser/seed-session.js +57 -0
  45. package/dist/replica/browser/seed-session.js.map +1 -0
  46. package/dist/replica/browser/snapshot-stream.d.ts +24 -0
  47. package/dist/replica/browser/snapshot-stream.d.ts.map +1 -0
  48. package/dist/replica/browser/snapshot-stream.js +113 -0
  49. package/dist/replica/browser/snapshot-stream.js.map +1 -0
  50. package/dist/replica/browser/sqlite-db.d.ts +9 -0
  51. package/dist/replica/browser/sqlite-db.d.ts.map +1 -0
  52. package/dist/replica/browser/sqlite-db.js +28 -0
  53. package/dist/replica/browser/sqlite-db.js.map +1 -0
  54. package/dist/replica/browser/support.d.ts +2 -0
  55. package/dist/replica/browser/support.d.ts.map +1 -0
  56. package/dist/replica/browser/support.js +30 -0
  57. package/dist/replica/browser/support.js.map +1 -0
  58. package/dist/replica/browser/validate.d.ts +17 -0
  59. package/dist/replica/browser/validate.d.ts.map +1 -0
  60. package/dist/replica/browser/validate.js +47 -0
  61. package/dist/replica/browser/validate.js.map +1 -0
  62. package/dist/replica/browser/worker-core.d.ts +10 -0
  63. package/dist/replica/browser/worker-core.d.ts.map +1 -0
  64. package/dist/replica/browser/worker-core.js +181 -0
  65. package/dist/replica/browser/worker-core.js.map +1 -0
  66. package/dist/replica/catalyst-replica.d.ts +6 -9
  67. package/dist/replica/catalyst-replica.d.ts.map +1 -1
  68. package/dist/replica/catalyst-replica.js +6 -15
  69. package/dist/replica/catalyst-replica.js.map +1 -1
  70. package/dist/replica/migration-shape.d.ts +11 -0
  71. package/dist/replica/migration-shape.d.ts.map +1 -0
  72. package/dist/replica/migration-shape.js +25 -0
  73. package/dist/replica/migration-shape.js.map +1 -0
  74. package/package.json +16 -3
package/README.md CHANGED
@@ -127,6 +127,98 @@ void client.start(); // never await in the browser
127
127
 
128
128
  Requires a platform `WebSocket` (browser, Bun, or Node ≥22). On older Node, inject a `wsFactory` that wraps the [`ws`](https://www.npmjs.com/package/ws) package.
129
129
 
130
+ ### Browser — managed OPFS replica (`/browser`)
131
+
132
+ `BrowserReplica` is the browser twin of `/node`'s `CatalystReplica`: an OPFS-persisted SQLite replica
133
+ in a dedicated Web Worker, seeded from `/snapshot` in bounded streamed batches, kept live off the same
134
+ change feed, and read through the same `@catalyst-cloud/read-model` views — no hand-written worker,
135
+ apply, or seeding code in your app.
136
+
137
+ ```ts
138
+ import {
139
+ BrowserReplica,
140
+ isBrowserReplicaSupported,
141
+ type ReplicaStatus,
142
+ } from "@catalyst-cloud/sdk/browser";
143
+
144
+ let status: ReplicaStatus = "loading";
145
+
146
+ if (isBrowserReplicaSupported()) {
147
+ const replica = new BrowserReplica(
148
+ {
149
+ onChanged: () => void refreshList(), // after the seed and after every applied delta drain
150
+ onStatus: (s) => {
151
+ status = s; // "loading" | "live" | "reconnecting" | "error" | "secondary" | …
152
+ setBadge(s);
153
+ },
154
+ },
155
+ {
156
+ baseUrl: "/api/v1", // same-origin, cookie-authed; accountId optional
157
+ // REQUIRED. The OPFS database is shared by every replica on the origin and a warm cursor skips
158
+ // the snapshot, so without a fence a change of signed-in user serves the PREVIOUS user's rows.
159
+ // Pass a stable per-user id from your session — e.g. the WorkOS `user.id`. It never leaves the
160
+ // browser; it is only compared against the value stamped in the local DB, and a mismatch wipes
161
+ // the replica and forces a re-seed.
162
+ identity: session.user.id,
163
+ },
164
+ );
165
+ // AWAIT it. start() suspends on the Web Lock before the worker exists, so a query issued against a
166
+ // not-yet-started replica rejects with "replica client closed".
167
+ await replica.start(); // resolves once seeded — or immediately, with status "secondary"
168
+
169
+ // Another tab already owns the origin's replica. That is a normal outcome, not an error: this tab
170
+ // should read via its usual fetch path and leave the local DB alone.
171
+ if (status !== "secondary") {
172
+ const rows = await replica.queryIssues(); // read-model IssueView[], served locally
173
+ }
174
+ // replica.close() on teardown — cooperatively releases the OPFS handles, then terminates the worker
175
+ }
176
+ ```
177
+
178
+ `status` above is whatever your `onStatus` handler last recorded. `start()` REJECTS if the boot fails
179
+ (bad origin, missing worker chunk, OPFS unavailable) — it does not resolve into a broken state, so a
180
+ `try`/`catch` around it is where you surface the error to the user.
181
+
182
+ Built in, because browsers need them:
183
+
184
+ - **Single-owner election** (Web Locks): OPFS SAHPool is single-connection-per-origin, so exactly one
185
+ tab boots the replica; every other tab gets status `"secondary"` (a clean state, not an error) and
186
+ should read via its normal fetch path.
187
+ - **Backpressure**: live deltas are coalesced into batched, single-flight applies with a bounded
188
+ buffer; a backlog too deep to replay escalates to a fresh snapshot instead of growing.
189
+
190
+ **Peer dependency**: install [`@sqlite.org/sqlite-wasm`](https://www.npmjs.com/package/@sqlite.org/sqlite-wasm)
191
+ yourself — the SDK never bundles the wasm.
192
+
193
+ **Bundlers**: the worker is created with `new Worker(new URL("./db.worker.js", import.meta.url),
194
+ { type: "module" })`, which Vite, webpack 5, and Rollup detect statically and split into its own chunk
195
+ (nothing wasm-related touches your main bundle; `/node` consumers never see it at all). Notes:
196
+
197
+ - **Vite**: works out of the box in `build`. In dev, if pre-bundling interferes with the worker URL,
198
+ add `optimizeDeps: { exclude: ["@catalyst-cloud/sdk"] }`.
199
+ - **webpack 5 / Rollup**: the `new Worker(new URL(...))` syntax is supported natively (Rollup needs
200
+ worker support in your config, e.g. `@surma/rollup-plugin-off-main-thread` or equivalent).
201
+ - **Exotic bundlers**: pass `createWorker` in `BrowserReplicaOptions` and construct the worker
202
+ however your toolchain requires. The worker module is published at the dedicated subpath
203
+ **`@catalyst-cloud/sdk/browser/db-worker`** — that specifier is the supported entry point:
204
+
205
+ ```ts
206
+ // Vite
207
+ import DbWorker from "@catalyst-cloud/sdk/browser/db-worker?worker";
208
+ createWorker: () => new DbWorker();
209
+
210
+ // webpack 5 / anything that resolves a bare specifier to a URL
211
+ createWorker: () =>
212
+ new Worker(
213
+ new URL("@catalyst-cloud/sdk/browser/db-worker", import.meta.url),
214
+ { type: "module" },
215
+ );
216
+ ```
217
+
218
+ The worker is a **side-effect module** (it registers a message handler and exports nothing), so it
219
+ is listed in the package's `sideEffects` array — do not configure your bundler to tree-shake it, or
220
+ it will load and register nothing and every replica call will hang.
221
+
130
222
  ## API
131
223
 
132
224
  | Export | What it is |
@@ -0,0 +1,9 @@
1
+ export { BrowserReplica, streamSeedIntoWorker, type BrowserReplicaOptions, type ReplicaHandlers, type ReplicaStatus, } from "./replica/browser/browser-replica.js";
2
+ export { isBrowserReplicaSupported } from "./replica/browser/support.js";
3
+ export { acquireReplicaLock, type ReplicaLockHandle, type ReplicaLockOptions, } from "./replica/browser/browser-lock.js";
4
+ export { DeltaQueue, MAX_APPLY_BATCH_ROWS, MAX_INBOX_DEPTH, type SeqChange, type DeltaQueueOptions, } from "./replica/browser/delta-queue.js";
5
+ export { streamSnapshotBatches, SEED_BATCH_ROWS } from "./replica/browser/snapshot-stream.js";
6
+ export type { WireChange, ReplicaRequest, ReplicaResponse, Envelope, ResultMap, ApplyChangesResult, } from "./replica/browser/protocol.js";
7
+ export { LiveSyncClient, type AuthStrategy, type LiveSyncStatus, type LogLevel, type WebSocketLike, type WebSocketFactory, } from "./live-sync-client.js";
8
+ export { ENTITY_NAMES, CHANGE_OPS, type AccountId, type EntityName, type ChangeOp, type ChangeFrame, } from "./types.js";
9
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,eAAe,EACf,KAAK,SAAS,EACd,KAAK,iBAAiB,GACvB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAE9F,YAAY,EACV,UAAU,EACV,cAAc,EACd,eAAe,EACf,QAAQ,EACR,SAAS,EACT,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,24 @@
1
+ // @catalyst-cloud/sdk/browser — the managed replica for the browser (CTC-114, milestone 2 of the
2
+ // managed-replica roadmap; ADR-0002).
3
+ //
4
+ // `BrowserReplica` is the browser twin of `/node`'s CatalystReplica behind ONE import: claim
5
+ // single-ownership of the origin's replica (Web Locks — a losing tab degrades to "secondary", never a
6
+ // red error), open + migrate an OPFS SAHPool SQLite DB inside a dedicated Worker, stream-seed
7
+ // /snapshot in bounded batches, subscribe to the live change feed (the SDK's LiveSyncClient) through a
8
+ // coalescing, depth-bounded delta queue, and serve the @catalyst-cloud/read-model `build*View`
9
+ // queries over it — the "same query, four runtimes" proof, in the browser.
10
+ //
11
+ // BUNDLER CONTRACT: the worker is reached via `new Worker(new URL("./db.worker.js",
12
+ // import.meta.url), { type: "module" })`, which Vite, webpack 5 and Rollup detect statically and emit
13
+ // as a separate chunk; `@sqlite.org/sqlite-wasm` is a PEER dependency resolved by the consumer inside
14
+ // that chunk. Import this subpath ONLY from browser code — the root ("@catalyst-cloud/sdk") stays the
15
+ // transport-only isomorphic surface, and '/node' never pulls any of this into a node bundle.
16
+ export { BrowserReplica, streamSeedIntoWorker, } from "./replica/browser/browser-replica.js";
17
+ export { isBrowserReplicaSupported } from "./replica/browser/support.js";
18
+ export { acquireReplicaLock, } from "./replica/browser/browser-lock.js";
19
+ export { DeltaQueue, MAX_APPLY_BATCH_ROWS, MAX_INBOX_DEPTH, } from "./replica/browser/delta-queue.js";
20
+ export { streamSnapshotBatches, SEED_BATCH_ROWS } from "./replica/browser/snapshot-stream.js";
21
+ // Re-export the transport surface so a consumer can stay on one import.
22
+ export { LiveSyncClient, } from "./live-sync-client.js";
23
+ export { ENTITY_NAMES, CHANGE_OPS, } from "./types.js";
24
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,sCAAsC;AACtC,EAAE;AACF,6FAA6F;AAC7F,sGAAsG;AACtG,8FAA8F;AAC9F,uGAAuG;AACvG,+FAA+F;AAC/F,2EAA2E;AAC3E,EAAE;AACF,oFAAoF;AACpF,sGAAsG;AACtG,sGAAsG;AACtG,sGAAsG;AACtG,6FAA6F;AAE7F,OAAO,EACL,cAAc,EACd,oBAAoB,GAIrB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE,OAAO,EACL,kBAAkB,GAGnB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,eAAe,GAGhB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAW9F,wEAAwE;AACxE,OAAO,EACL,cAAc,GAMf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,GAKX,MAAM,YAAY,CAAC"}
@@ -45,8 +45,20 @@ export interface LiveSyncClientOptions {
45
45
  * verbatim (path-preserving). A trailing slash is trimmed.
46
46
  */
47
47
  baseUrl: string;
48
- /** The tenant id = the mirror's name; sent as `?account=` on the connect URL. */
49
- accountId: string;
48
+ /**
49
+ * The tenant id = the mirror's name; sent as `?account=` on the connect URL.
50
+ *
51
+ * OPTIONAL, and omitting it is the browser default: the OPEN read plane scopes a cookie-authed
52
+ * connection to the session user's own tenant, and an explicit account is the tenant-SWITCHER path.
53
+ * When absent the parameter is omitted entirely rather than serialized as `?account=` — an empty
54
+ * value is not a mirror name, and freezing it into the wire contract would leave the one nearby
55
+ * server-side fallback that a bare empty value can reach (`adminAccountScope`'s `|| "tenant-0"`)
56
+ * cross-tenant-shaped.
57
+ *
58
+ * REQUIRED for `auth: {kind:"token"}` — a host has no session to fall back to, so the constructor
59
+ * throws rather than letting it fail later as an opaque server 401.
60
+ */
61
+ accountId?: string;
50
62
  /**
51
63
  * The connect route. Default "/connect"; the service dual-serves it at "/api/v1/connect" too, so a
52
64
  * path-prefixed `baseUrl` ("…/api/v1") with the default "/connect" resolves to "…/api/v1/connect".
@@ -63,8 +75,21 @@ export interface LiveSyncClientOptions {
63
75
  * and the client re-enters the backoff path, so this callback can never wedge the transport; still,
64
76
  * bound your own I/O (as the replica's seedFromSnapshot does) so a dead fetch fails fast, not at
65
77
  * the backstop.
78
+ *
79
+ * `signal` ABORTS when the transport gives up on this attempt — the {@link reseedTimeoutMs}
80
+ * deadline expiring, or `stop()` (CTC-114 review round 10). Honour it: the transport considers the
81
+ * attempt over the moment it fires, and RECONNECTS. A callback that keeps writing after that is a
82
+ * second writer racing the socket the transport just reopened — the browser replica's concrete
83
+ * failure was frames delivered past the abandoned seed's cursor being dropped by its paused queue,
84
+ * after which a late seed completion left the socket advanced over a hole that later deltas sealed
85
+ * permanently.
86
+ *
87
+ * This is why "abandon" alone was not enough. Two layers bounding one operation with NO
88
+ * cancellation link between them is the defect; the signal is the link. Optional parameter, so
89
+ * existing zero-arg callbacks still typecheck — but a consumer that ignores it keeps the old
90
+ * two-writer hazard.
66
91
  */
67
- reseed: () => Promise<number>;
92
+ reseed: (signal?: AbortSignal) => Promise<number>;
68
93
  /**
69
94
  * Read the consumer's durable cursor (the last applied feed seq), or null/undefined if it has
70
95
  * never seeded. Drives the `{type:"sync", after}` catch-up request. Return `null` to send
@@ -117,6 +142,17 @@ export interface LiveSyncClientOptions {
117
142
  * Default `600_000` (10 min); `0` disables.
118
143
  */
119
144
  reseedTimeoutMs?: number;
145
+ /**
146
+ * How long a CANCELLED reseed gets to unwind before the transport settles and reconnects anyway.
147
+ * Default 250ms; the value must cover the consumer's OWN cleanup bound (CTC-114 review round 14).
148
+ *
149
+ * Reconnecting before the consumer has unwound is not merely early: its store may still be latched,
150
+ * so replayed frames are refused while this client's `deliveredSeq` advances over them — and the
151
+ * next frame it does accept carries the durable cursor past the gap, permanently. The transport
152
+ * cannot know how long a given consumer takes to unwind, so the consumer sets this. The browser
153
+ * replica raises it to cover its worker-RPC deadline, since its cleanup is a `seedAbort` RPC.
154
+ */
155
+ cancelCleanupGraceMs?: number;
120
156
  /**
121
157
  * Gap detection (CTL-1402): how long (ms) to wait for a `{type:"sync"}` gap re-request to finish
122
158
  * redelivering the detected hole before retrying (or, once {@link gapRetryLimit} re-requests have
@@ -158,7 +194,7 @@ export declare function stripTrailingSlashes(s: string): string;
158
194
  export declare function buildConnectUrl(opts: {
159
195
  baseUrl: string;
160
196
  connectPath: string;
161
- accountId: string;
197
+ accountId?: string;
162
198
  auth: AuthStrategy;
163
199
  }): string;
164
200
  export declare class LiveSyncClient {
@@ -177,6 +213,7 @@ export declare class LiveSyncClient {
177
213
  private readonly pongTimeoutMs;
178
214
  private readonly openTimeoutMs;
179
215
  private readonly reseedTimeoutMs;
216
+ private readonly cancelCleanupGraceMs;
180
217
  private readonly gapTimeoutMs;
181
218
  private readonly gapRetryLimit;
182
219
  private readonly wsFactory;
@@ -184,6 +221,36 @@ export declare class LiveSyncClient {
184
221
  private readonly telemetryConfig;
185
222
  private ws;
186
223
  private stopped;
224
+ /**
225
+ * Has start() been entered? `stopped` alone cannot answer this — it is false BEFORE the first
226
+ * start() as well as during a run, so every "am I running?" guard read true on a client that had
227
+ * never booted. Only the public `requestResync()` can reach that window (CTC-114 review round 5):
228
+ * it would reseed and open a socket with no lifecycle deferred and no telemetry resolved, and the
229
+ * later real start() would then openSocket() again — overwriting `this.ws`, so the first socket
230
+ * kept delivering duplicate frames and could no longer be closed through the stored reference.
231
+ */
232
+ private started;
233
+ /** The in-flight boot task, or null once it settles — `requestResync()` serializes behind it. */
234
+ private bootTask;
235
+ /** Settles an in-flight `boundedReseed` wrapper on stop(), so an awaited resync cannot hang. */
236
+ private abandonReseed;
237
+ /**
238
+ * The in-flight resync, so a concurrent caller AWAITS it instead of being handed an
239
+ * already-resolved promise and acting on a store still being rebuilt (round 10).
240
+ */
241
+ private activeResync;
242
+ /** Did the boot this request waited on perform a COLD re-seed? Only then may it be absorbed. */
243
+ private bootColdSeeded;
244
+ /**
245
+ * Did the last boot REJECT? Latched until the next `start()` (CTC-114 review round 9).
246
+ *
247
+ * Round 8 read the failure from the awaited `bootTask`, but that handle is nulled once the boot
248
+ * settles — so a `requestResync()` arriving after that microtask found no record of the failure,
249
+ * with `started` still true and `stopped` still false, and sailed past the guard into a reseed that
250
+ * could open a live socket under an application already told startup had failed. The outcome has to
251
+ * outlive the handle.
252
+ */
253
+ private bootFailed;
187
254
  private resyncing;
188
255
  private backoff;
189
256
  private reconnectTimer;
@@ -242,8 +309,10 @@ export declare class LiveSyncClient {
242
309
  private socketOpened;
243
310
  /** The pending reseed deadline (CTC-281) — the timer that makes "resyncing" (no socket, reconnect
244
311
  * suppressed) a bounded state instead of a restart-only wedge. Cleared when the reseed settles in
245
- * time and by stop() (ask 4: stop() leaves NOTHING pending). At most one reseed is ever in flight
246
- * (`resyncing` guards the resync path; the boot seed runs before any socket exists). */
312
+ * time and by stop() (ask 4: stop() leaves NOTHING pending). At most one reseed is ever in flight:
313
+ * `resyncing` guards the resync path, and the boot cold seed SETS that same flag for its duration.
314
+ * (It used to rely on "the boot seed runs before any socket exists" — true only while a resync
315
+ * needed a server frame. The public `requestResync()` added in 0.8.0 needs no socket.) */
247
316
  private reseedTimer;
248
317
  constructor(opts: LiveSyncClientOptions);
249
318
  /**
@@ -257,6 +326,13 @@ export declare class LiveSyncClient {
257
326
  stop(): void;
258
327
  /** The ws(s):// URL this client opens, for diagnostics/tests. Re-derived from the options. */
259
328
  connectUrl(): string;
329
+ /**
330
+ * The tenant label for telemetry. Attributes are `Record<string, string>`, and an empty string reads
331
+ * as a MISSING attribute in Loki/Tempo — which silently merges every session-scoped browser client
332
+ * into one unlabelled bucket. `"session"` names the case instead: this client is scoped to whatever
333
+ * tenant the cookie resolves to.
334
+ */
335
+ private get tenantAttr();
260
336
  private setStatus;
261
337
  private openSocket;
262
338
  /** End the in-flight connect span exactly once (idempotent — nulls the handle). */
@@ -318,11 +394,39 @@ export declare class LiveSyncClient {
318
394
  * The injected callback is a trust boundary like the ws impl: while it runs there is NO socket and
319
395
  * scheduleReconnect is suppressed, so an unbounded await here was the last zero-timer wedge — the
320
396
  * deadline below is the pending timer that upholds the header invariant for the "resyncing" state.
321
- * On timeout the attempt is ABANDONED, not cancelled (the callback owns its own I/O bounds — the
322
- * replica's seedFromSnapshot aborts its fetch itself): a late settle is discarded via the `settled`
323
- * latch, and a late REJECTION is swallowed so it can never surface as an unhandled rejection.
397
+ * On timeout the attempt is both CANCELLED and abandoned (CTC-114 review round 10). It used to be
398
+ * abandoned only, justified as "the callback owns its own I/O bounds" but the callback owning
399
+ * bounds is exactly what makes a SECOND, independent deadline here dangerous. The browser seed is
400
+ * bounded by network idleness and by per-RPC worker deadlines, both of which a legitimately slow
401
+ * ~100 MB snapshot satisfies indefinitely; this total deadline could therefore fire on a seed that
402
+ * was making honest progress, whereupon the transport reconnected while the callback kept writing.
403
+ * Frames past the abandoned seed's cursor were then accepted by the socket and discarded by the
404
+ * replica's paused queue, and a late seed completion left the socket advanced over a hole that
405
+ * later deltas sealed for good.
406
+ *
407
+ * So the deadline now fires an AbortSignal FIRST and rejects second: whoever is told the attempt is
408
+ * over is also told to stop. A late settle is still discarded via the `settled` latch, and a late
409
+ * REJECTION is still swallowed so it can never surface as an unhandled rejection.
324
410
  */
325
411
  private boundedReseed;
412
+ /**
413
+ * Ask the client to drop the socket, re-seed, and reconnect from the fresh cursor — the same path a
414
+ * server `{type:"resync"}` frame drives, exposed for a consumer that discovers ON ITS OWN SIDE that
415
+ * its store can no longer be caught up by deltas.
416
+ *
417
+ * The browser replica is the motivating caller: when its delta queue overflows (or its applies keep
418
+ * rejecting) the buffered frames are dropped, so the transport's notion of what has been delivered is
419
+ * now ahead of what the store actually holds. Re-seeding through here — rather than calling the
420
+ * `reseed` callback directly — is what makes that safe: this CLOSES THE SOCKET FIRST, so no live
421
+ * frame interleaves with the snapshot and lands in the window that is in neither the snapshot nor the
422
+ * store.
423
+ *
424
+ * Delegates to the existing resync path in full — same `resyncing` re-entrancy guard, same
425
+ * `boundedReseed` deadline, same span, same failure→backoff behaviour. NEVER rejects: a failed
426
+ * re-seed is already handled internally by re-entering the reconnect path, and this is called from
427
+ * event handlers and `void` contexts where a rejection would surface as an unhandled promise.
428
+ */
429
+ requestResync(): Promise<void>;
326
430
  /**
327
431
  * Cursor underflow: the deltas we need were evicted from the service's retained change buffer. Close the socket
328
432
  * (so no live frame interleaves with the re-seed), re-seed via the injected callback, then reconnect
@@ -330,6 +434,21 @@ export declare class LiveSyncClient {
330
434
  * frame and suppresses scheduleReconnect for the duration so we reopen exactly once.
331
435
  */
332
436
  private handleResync;
437
+ /**
438
+ * The resync body. Never call directly — `handleResync()` owns the in-flight handle.
439
+ *
440
+ * TWO FLAGS, ONE FACT — documented rather than consolidated here, deliberately. `resyncing` and
441
+ * `activeResync` both mean "a re-seed is in flight", and they can disagree: the boot path sets
442
+ * `resyncing` directly (so a resync cannot race startup) without ever creating an `activeResync`
443
+ * handle. In that window a call landing here would hit the guard below and resolve silently, which
444
+ * is the very shape round 10 fixed for the live path.
445
+ *
446
+ * It is NOT reachable today, and both reasons are load-bearing: `requestResync()` serialises behind
447
+ * `bootTask` before it can get here, and the server-frame path needs a socket, which does not exist
448
+ * until the boot opens one. Consolidating the two into a single handle is the right fix and belongs
449
+ * with the wider lifecycle rework — not in a release candidate at round eleven.
450
+ */
451
+ private runResync;
333
452
  /** Epoch ms of the last inbound frame (change, pong, or malformed) — null before the first frame.
334
453
  * Any inbound bytes prove the socket is alive; the catalyst daemon's stall classifier reads this to
335
454
  * tell a quiet feed from a half-open socket (the per-frame timestamp it previously lacked). */
@@ -1 +1 @@
1
- {"version":3,"file":"live-sync-client.d.ts","sourceRoot":"","sources":["../src/live-sync-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"live-sync-client.d.ts","sourceRoot":"","sources":["../src/live-sync-client.ts"],"names":[],"mappings":"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"}