@rindle/remote 0.4.4 → 0.6.3

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.
@@ -0,0 +1,49 @@
1
+ /** The base ws subprotocol the browser offers alongside its `aff.*` ticket; the fleet follower
2
+ * echoes it on the 101 (a strict browser closes a socket whose selected subprotocol it never
3
+ * offered, so the base is always offered in affinity mode). Inlined — NOT imported from
4
+ * `@rindle/affinity`'s `WS_SUBPROTOCOL` — to keep that crate's `node:crypto` out of the browser
5
+ * bundle (the same duplicate-to-stay-bundle-clean discipline the lease wire types use). Keep the
6
+ * two spellings in lock-step. */
7
+ export declare const WS_SUBPROTOCOL = "rindle.v1";
8
+ /** A mutable holder for the current opaque affinity ticket, shared by the transport, the source,
9
+ * and the lease POST (see the module header). */
10
+ export interface AffinityTicketStore {
11
+ /** The ticket to offer on the next ws handshake, or undefined — ticketless, so the edge
12
+ * anycasts + mints a fresh one. A persisted/previous-connection ticket may be returned here
13
+ * even while it is NOT yet safe for a lease; see {@link leaseTicket}. */
14
+ get(): string | undefined;
15
+ /** Record a freshly minted/refreshed ticket (from a connection's `{t:"affinity"}` frame). */
16
+ set(ticket: string): void;
17
+ /** Drop the ticket so the next connect goes ticketless (the pinned follower is gone, §8). */
18
+ clear(): void;
19
+ /** Mark the held ticket handshake-only until this connection emits a fresh mint frame. Called
20
+ * before the first connection and every reconnect, after the held ticket was already selected
21
+ * for the ws subprotocol offer. This prevents a restored/rotated/expired persisted ticket from
22
+ * racing an HTTP lease onto an independently-anycast follower. */
23
+ connectionPending(): void;
24
+ /** Resolve with a ticket minted/refreshed on the CURRENT connection, or the next one
25
+ * {@link set}. A persisted ticket deliberately does not resolve this wait. */
26
+ waitForTicket(): Promise<string>;
27
+ /** Obtain the current connection's ticket for an HTTP lease. The first missing-ticket wait is
28
+ * bounded; its timeout removes the waiter and latches ticketless fallback, so later leases
29
+ * return immediately until a mint frame arrives. Concurrent callers share the one timer.
30
+ * `timedOut` is true only for that transition, allowing one warning per fallback episode. */
31
+ leaseTicket(timeoutMs: number): Promise<{
32
+ ticket?: string;
33
+ timedOut: boolean;
34
+ }>;
35
+ }
36
+ /** Where a store persists the ticket across reloads. The browser backs this with sessionStorage
37
+ * (per-TAB, so two tabs can pin two regions — design §13); tests pass none (pure in-memory). */
38
+ export interface TicketPersistence {
39
+ load(): string | undefined;
40
+ save(ticket: string): void;
41
+ clear(): void;
42
+ }
43
+ /** Build an {@link AffinityTicketStore}, optionally persisted. Pure/in-memory when `persist` is
44
+ * omitted. */
45
+ export declare function createAffinityTicketStore(persist?: TicketPersistence): AffinityTicketStore;
46
+ /** The subprotocol list to offer for one connection: the base protocol always, plus the held ticket
47
+ * (already an `aff.<…>` token) when one exists. */
48
+ export declare function offerSubprotocols(store: AffinityTicketStore): string[];
49
+ //# sourceMappingURL=affinity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affinity.d.ts","sourceRoot":"","sources":["../src/affinity.ts"],"names":[],"mappings":"AAYA;;;;;kCAKkC;AAClC,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C;kDACkD;AAClD,MAAM,WAAW,mBAAmB;IAClC;;8EAE0E;IAC1E,GAAG,IAAI,MAAM,GAAG,SAAS,CAAC;IAC1B,6FAA6F;IAC7F,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,6FAA6F;IAC7F,KAAK,IAAI,IAAI,CAAC;IACd;;;uEAGmE;IACnE,iBAAiB,IAAI,IAAI,CAAC;IAC1B;mFAC+E;IAC/E,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC;;;kGAG8F;IAC9F,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACjF;AAED;iGACiG;AACjG,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,IAAI,IAAI,CAAC;CACf;AAED;eACe;AACf,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,CAyE1F;AAED;oDACoD;AACpD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAGtE"}
@@ -0,0 +1,95 @@
1
+ // Browser-side follower-affinity ticket transport (FOLLOWER-AFFINITY-DESIGN.md §3, §5). The ticket
2
+ // is OPAQUE here — the browser never mints or verifies it (placement, not authorization; §3, §9),
3
+ // so this module carries no crypto. It is the thin seam three pieces share:
4
+ //
5
+ // - {@link WsTransport} offers the held ticket as a ws subprotocol at each connect (so the Fly
6
+ // edge `fly-replay`s to the pinned follower);
7
+ // - {@link RemoteOptimisticSource} writes the follower's minted ticket from the `{t:"affinity"}`
8
+ // frame, and CLEARS it on a sustained outage (the pinned follower is gone → the next reconnect
9
+ // anycasts to a live one and re-pins, §8);
10
+ // - the lease POST forwards the held ticket as `affinity`, sequenced AFTER a fresh connect's mint
11
+ // frame ({@link AffinityTicketStore.waitForTicket}) so both legs land on the same follower (§4.1).
12
+ /** The base ws subprotocol the browser offers alongside its `aff.*` ticket; the fleet follower
13
+ * echoes it on the 101 (a strict browser closes a socket whose selected subprotocol it never
14
+ * offered, so the base is always offered in affinity mode). Inlined — NOT imported from
15
+ * `@rindle/affinity`'s `WS_SUBPROTOCOL` — to keep that crate's `node:crypto` out of the browser
16
+ * bundle (the same duplicate-to-stay-bundle-clean discipline the lease wire types use). Keep the
17
+ * two spellings in lock-step. */
18
+ export const WS_SUBPROTOCOL = "rindle.v1";
19
+ /** Build an {@link AffinityTicketStore}, optionally persisted. Pure/in-memory when `persist` is
20
+ * omitted. */
21
+ export function createAffinityTicketStore(persist) {
22
+ let current = persist?.load();
23
+ // A loaded ticket is useful for the ws handshake, but is not lease-safe until the follower on
24
+ // THIS connection confirms it by minting a fresh frame. The same distinction is re-armed on
25
+ // every reconnect via `connectionPending`.
26
+ let currentConnectionFresh = false;
27
+ let ticketlessFallback = false;
28
+ let waiters = [];
29
+ let leaseWait;
30
+ const finishLeaseWait = (result) => {
31
+ const pending = leaseWait;
32
+ if (!pending)
33
+ return;
34
+ clearTimeout(pending.timer);
35
+ leaseWait = undefined;
36
+ pending.resolve(result);
37
+ };
38
+ return {
39
+ get: () => current,
40
+ set: (ticket) => {
41
+ current = ticket;
42
+ currentConnectionFresh = true;
43
+ ticketlessFallback = false;
44
+ persist?.save(ticket);
45
+ // Resolve everyone waiting for the (now-arrived) ticket, in FIFO order.
46
+ const pending = waiters;
47
+ waiters = [];
48
+ for (const resolve of pending)
49
+ resolve(ticket);
50
+ finishLeaseWait({ ticket, timedOut: false });
51
+ },
52
+ clear: () => {
53
+ // Drop the ticket but leave any waiters pending — the next connect's mint frame resolves them
54
+ // (a dead-follower reassignment must still be able to lease once the new ticket arrives).
55
+ current = undefined;
56
+ currentConnectionFresh = false;
57
+ persist?.clear();
58
+ },
59
+ connectionPending: () => {
60
+ currentConnectionFresh = false;
61
+ },
62
+ waitForTicket: () => currentConnectionFresh && current !== undefined
63
+ ? Promise.resolve(current)
64
+ : new Promise((resolve) => waiters.push(resolve)),
65
+ leaseTicket: (timeoutMs) => {
66
+ if (currentConnectionFresh && current !== undefined) {
67
+ return Promise.resolve({ ticket: current, timedOut: false });
68
+ }
69
+ if (ticketlessFallback)
70
+ return Promise.resolve({ timedOut: false });
71
+ if (leaseWait)
72
+ return leaseWait.promise;
73
+ let resolve;
74
+ const promise = new Promise((r) => {
75
+ resolve = r;
76
+ });
77
+ const timer = setTimeout(() => {
78
+ // Clear the shared waiter before resolving callers. A later mint starts a new, fresh
79
+ // episode; no abandoned resolver accumulates per lease while affinity is off.
80
+ leaseWait = undefined;
81
+ ticketlessFallback = true;
82
+ resolve({ timedOut: true });
83
+ }, Math.max(0, timeoutMs));
84
+ leaseWait = { promise, resolve, timer };
85
+ return promise;
86
+ },
87
+ };
88
+ }
89
+ /** The subprotocol list to offer for one connection: the base protocol always, plus the held ticket
90
+ * (already an `aff.<…>` token) when one exists. */
91
+ export function offerSubprotocols(store) {
92
+ const ticket = store.get();
93
+ return ticket ? [WS_SUBPROTOCOL, ticket] : [WS_SUBPROTOCOL];
94
+ }
95
+ //# sourceMappingURL=affinity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affinity.js","sourceRoot":"","sources":["../src/affinity.ts"],"names":[],"mappings":"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"}
package/dist/backend.d.ts CHANGED
@@ -25,6 +25,11 @@ export declare class RemoteBackend implements Backend {
25
25
  __attachDevtoolsServerDeltas(observer: BackendDevObserver): () => void;
26
26
  private subscribe;
27
27
  private onServerMsg;
28
+ /** Route a `queryError` by its 101 §5 classification: retryable ⇒ keep the QState (and the
29
+ * rows already folded downstream — 101 §6) and re-subscribe after a jittered backoff
30
+ * honoring `retryAfterMs`; terminal (or pre-classification servers) ⇒ drop the
31
+ * subscription, exactly as before (FOLLOWER-LAG-SHED §6.3). */
32
+ private onQueryError;
28
33
  private openSubscriber;
29
34
  private applyBatch;
30
35
  private emitServerEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAIhI,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAahD,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAED,qBAAa,aAAc,YAAW,OAAO;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAoB;IAClD,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;gBAEvC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,oBAAyB;IAOjE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI;IAStE,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAKnC;+FAC2F;IAC3F,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5C,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAI/D,4BAA4B,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAStE,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,eAAe;CAMxB;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EACjD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,GAAE,oBAAyB,GAC9B,KAAK,CAAC,CAAC,CAAC,CAGV"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAIhI,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAiBhD,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAED,qBAAa,aAAc,YAAW,OAAO;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAoB;IAClD,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;gBAEvC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,oBAAyB;IAOjE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI;IAStE,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAOnC;+FAC2F;IAC3F,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5C,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAI/D,4BAA4B,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAStE,OAAO,CAAC,SAAS;IA+BjB,OAAO,CAAC,WAAW;IAanB;;;oEAGgE;IAChE,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,eAAe;CAMxB;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EACjD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,GAAE,oBAAyB,GAC9B,KAAK,CAAC,CAAC,CAAC,CAGV"}
package/dist/backend.js CHANGED
@@ -10,6 +10,7 @@ import { Store } from "@rindle/client";
10
10
  import { ProtocolError, Subscriber } from "./protocol.js";
11
11
  import { defaultSubscribeTarget, isThenable, subscribeMessage, } from "./subscribe.js";
12
12
  import { WsTransport } from "./transport.js";
13
+ import { retryDelayMs } from "./query-error.js";
13
14
  export class RemoteBackend {
14
15
  transport;
15
16
  resolveSubscribe;
@@ -28,10 +29,13 @@ export class RemoteBackend {
28
29
  console.error(`[rindle-remote] flat query ${qid} has no named remote identity`);
29
30
  return;
30
31
  }
31
- this.subs.set(qid, { remote, subscriber: null, epoch: 0, resubscribing: false, subscribeTicket: 0 });
32
+ this.subs.set(qid, { remote, subscriber: null, epoch: 0, resubscribing: false, subscribeTicket: 0, retryTimer: undefined, retryAttempt: 0 });
32
33
  this.subscribe(qid, remote);
33
34
  }
34
35
  unregisterQuery(qid) {
36
+ const s = this.subs.get(qid);
37
+ if (s?.retryTimer !== undefined)
38
+ clearTimeout(s.retryTimer);
35
39
  this.subs.delete(qid);
36
40
  this.transport.send({ t: "unsubscribe", queryId: qid });
37
41
  }
@@ -57,6 +61,12 @@ export class RemoteBackend {
57
61
  const s = this.subs.get(qid);
58
62
  if (!s)
59
63
  return;
64
+ // A fresh subscribe (gap recovery, the retry timer itself) supersedes any scheduled
65
+ // retryable-error retry — never leave two subscribe paths racing for one query.
66
+ if (s.retryTimer !== undefined) {
67
+ clearTimeout(s.retryTimer);
68
+ s.retryTimer = undefined;
69
+ }
60
70
  const request = { queryId: qid, remote, mode: "flat" };
61
71
  const ticket = ++s.subscribeTicket;
62
72
  const send = (target) => {
@@ -85,8 +95,7 @@ export class RemoteBackend {
85
95
  }
86
96
  onServerMsg(msg) {
87
97
  if (msg.t === "queryError") {
88
- this.subs.delete(msg.queryId);
89
- console.error(`[rindle-remote] query ${msg.queryId} subscription rejected: ${msg.message}`);
98
+ this.onQueryError(msg.queryId, msg);
90
99
  return;
91
100
  }
92
101
  // This backend is flat-only; it ignores normalized frames (`nhello`/`nbatch`).
@@ -100,6 +109,37 @@ export class RemoteBackend {
100
109
  else
101
110
  this.applyBatch(msg.queryId, s, msg.batch);
102
111
  }
112
+ /** Route a `queryError` by its 101 §5 classification: retryable ⇒ keep the QState (and the
113
+ * rows already folded downstream — 101 §6) and re-subscribe after a jittered backoff
114
+ * honoring `retryAfterMs`; terminal (or pre-classification servers) ⇒ drop the
115
+ * subscription, exactly as before (FOLLOWER-LAG-SHED §6.3). */
116
+ onQueryError(qid, err) {
117
+ const s = this.subs.get(qid);
118
+ if (!s)
119
+ return;
120
+ if (err.retryable !== true) {
121
+ if (s.retryTimer !== undefined)
122
+ clearTimeout(s.retryTimer);
123
+ this.subs.delete(qid);
124
+ console.error(`[rindle-remote] query ${qid} subscription rejected: ${err.message}`);
125
+ return;
126
+ }
127
+ if (s.retryTimer !== undefined)
128
+ return; // a retry is already scheduled — don't stack them
129
+ s.subscriber = null; // stop validating the dead epoch; recovery is a fresh seq-0 hydrate
130
+ s.resubscribing = true;
131
+ const delay = retryDelayMs(s.retryAttempt++, err.retryAfterMs);
132
+ console.warn(`[rindle-remote] query ${qid} ${err.code ?? "error"} (retryable): re-subscribing in ${delay}ms: ${err.message}`);
133
+ const timer = setTimeout(() => {
134
+ const cur = this.subs.get(qid);
135
+ if (cur !== s)
136
+ return;
137
+ s.retryTimer = undefined;
138
+ this.subscribe(qid, s.remote);
139
+ }, delay);
140
+ timer.unref?.();
141
+ s.retryTimer = timer;
142
+ }
103
143
  openSubscriber(qid, s, hello) {
104
144
  try {
105
145
  // The Subscriber ctor validates the comparator + fingerprint and emits the `hello`
@@ -107,6 +147,7 @@ export class RemoteBackend {
107
147
  s.subscriber = new Subscriber(hello, (ev) => this.emitServerEvent(qid, ev));
108
148
  s.epoch = hello.epoch;
109
149
  s.resubscribing = false;
150
+ s.retryAttempt = 0; // a successful hello resets the retryable-error backoff
110
151
  }
111
152
  catch (e) {
112
153
  // A comparator/schema mismatch at hello is unrecoverable (a code-contract divergence) —
@@ -1 +1 @@
1
- {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,iFAAiF;AACjF,0FAA0F;AAC1F,kGAAkG;AAClG,EAAE;AACF,6FAA6F;AAC7F,6FAA6F;AAC7F,2FAA2F;AAE3F,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EACL,sBAAsB,EACtB,UAAU,EACV,gBAAgB,GAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAqB7C,MAAM,OAAO,aAAa;IACP,SAAS,CAAY;IACrB,gBAAgB,CAAoB;IACpC,YAAY,CAAqB;IAC1C,OAAO,GAA4C,GAAG,EAAE,GAAE,CAAC,CAAC;IACnD,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEnD,YAAY,SAAoB,EAAE,OAA6B,EAAE;QAC/D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,sBAAsB,CAAC;QACxE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACtC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,aAAa,CAAC,GAAY,EAAE,IAAa,EAAE,MAAoB;QAC7D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,+BAA+B,CAAC,CAAC;YAChF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC;QACrG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,eAAe,CAAC,GAAY;QAC1B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED;+FAC2F;IAC3F,MAAM,CAAC,SAAqB;QAC1B,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,OAAgD;QACtD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,4BAA4B,CAAC,QAA4B;QACvD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC;IAED,gFAAgF;IAExE,SAAS,CAAC,GAAY,EAAE,MAAmB;QACjD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAe,EAAE,CAAC;QAChE,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,eAAe,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,MAAiD,EAAE,EAAE;YACjE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,eAAe,KAAK,MAAM;gBAAE,OAAO;YACxD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,GAAY,EAAE,EAAE;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,eAAe,KAAK,MAAM;gBAAE,OAAO;YACxD,CAAC,CAAC,aAAa,GAAG,KAAK,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,iCAAiC,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;QACvH,CAAC,CAAC;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,UAAU,CAAC,MAAM,CAAC;gBAAE,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;;gBAChD,IAAI,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,GAAc;QAChC,IAAI,GAAG,CAAC,CAAC,KAAK,YAAY,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,OAAO,2BAA2B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QACD,+EAA+E;QAC/E,IAAI,GAAG,CAAC,CAAC,KAAK,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK,OAAO;YAAE,OAAO;QACnD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC;YAAE,OAAO,CAAC,+BAA+B;QAC/C,IAAI,GAAG,CAAC,CAAC,KAAK,OAAO;YAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;;YACjE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAEO,cAAc,CAAC,GAAY,EAAE,CAAS,EAAE,KAAY;QAC1D,IAAI,CAAC;YACH,mFAAmF;YACnF,4DAA4D;YAC5D,CAAC,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAC5E,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YACtB,CAAC,CAAC,aAAa,GAAG,KAAK,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,wFAAwF;YACxF,qDAAqD;YACrD,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,2BAA4B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,GAAY,EAAE,CAAS,EAAE,KAAY;QACtD,IAAI,CAAC,CAAC,CAAC,UAAU;YAAE,OAAO,CAAC,mCAAmC;QAC9D,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,+CAA+C;QAClF,IAAI,CAAC;YACH,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,YAAY,aAAa,CAAC;gBAAE,MAAM,CAAC,CAAC;YAC3C,IAAI,CAAC,CAAC,aAAa;gBAAE,OAAO,CAAC,qBAAqB;YAClD,oFAAoF;YACpF,CAAC,CAAC,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,GAAY,EAAE,EAAe;QACnD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY;gBAAE,CAAC,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;CACF;AAED,6FAA6F;AAC7F,MAAM,UAAU,iBAAiB,CAC/B,MAAiB,EACjB,cAAkC,EAClC,OAA6B,EAAE;IAE/B,MAAM,SAAS,GAAG,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;IACxG,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC"}
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { RemoteBackend, createRemoteStore } from "./backend.ts";
3
3
  export type { RemoteBackendOptions } from "./backend.ts";
4
4
  export { WsTransport } from "./transport.ts";
5
5
  export type { Transport } from "./transport.ts";
6
+ export { WS_SUBPROTOCOL, createAffinityTicketStore, offerSubprotocols } from "./affinity.ts";
7
+ export type { AffinityTicketStore, TicketPersistence } from "./affinity.ts";
6
8
  export type { MutationEnvelopeSender, RawMutationSender, SubscribeMode, SubscribeRequest, SubscribeResolver, SubscribeTarget, } from "./subscribe.ts";
7
9
  export { COMPARATOR_VERSION, Publisher, ProtocolError, Subscriber, schemaFp } from "./protocol.ts";
8
10
  export type { Batch, ClientMsg, Hello, ProtocolErrorKind, ServerMsg, SubscribeClientMsg } from "./protocol.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,gBAAgB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnG,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAC1F,YAAY,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC9F,YAAY,EACV,0BAA0B,EAC1B,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,gBAAgB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC7F,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnG,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAC1F,YAAY,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC9F,YAAY,EACV,0BAA0B,EAC1B,6BAA6B,EAC7B,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@
5
5
  export * from "@rindle/client";
6
6
  export { RemoteBackend, createRemoteStore } from "./backend.js";
7
7
  export { WsTransport } from "./transport.js";
8
+ // Browser-side follower-affinity ticket transport (FOLLOWER-AFFINITY-DESIGN.md §3, §5).
9
+ export { WS_SUBPROTOCOL, createAffinityTicketStore, offerSubprotocols } from "./affinity.js";
8
10
  export { COMPARATOR_VERSION, Publisher, ProtocolError, Subscriber, schemaFp } from "./protocol.js";
9
11
  // The normalized subscription protocol (the path-free twin) + the client-side source.
10
12
  export { NormalizedSubscriber, normalizedFp } from "./normalized.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,0FAA0F;AAC1F,8FAA8F;AAC9F,uEAAuE;AAEvE,cAAc,gBAAgB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAW7C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGnG,sFAAsF;AACtF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAG1F,0FAA0F;AAC1F,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAO9F,yFAAyF;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,0FAA0F;AAC1F,8FAA8F;AAC9F,uEAAuE;AAEvE,cAAc,gBAAgB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,wFAAwF;AACxF,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAW7F,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGnG,sFAAsF;AACtF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAG1F,0FAA0F;AAC1F,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAO9F,yFAAyF;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,4 +1,5 @@
1
- import type { MutationEnvelope, NormalizedEvent, NormalizedTableSchema, OptimisticSource, ProgressFrame, QueryId, RemoteQuery } from "@rindle/client";
1
+ import type { MutationEnvelope, MutationOutcomeFrame, NormalizedEvent, NormalizedTableSchema, OptimisticSource, ProgressFrame, QueryId, RemoteQuery } from "@rindle/client";
2
+ import type { AffinityTicketStore } from "./affinity.ts";
2
3
  import { type MutationEnvelopeSender, type SubscribeResolver } from "./subscribe.ts";
3
4
  import type { Transport } from "./transport.ts";
4
5
  /** Build a transport to a follower's public ws endpoint (READ-ROUTER-DESIGN.md §2.3). Default
@@ -22,6 +23,11 @@ export interface RemoteOptimisticSourceOptions {
22
23
  resolveSubscribe?: SubscribeResolver;
23
24
  /** Override named-mutator delivery, e.g. POST envelopes to the app API server. */
24
25
  pushMutation?: MutationEnvelopeSender;
26
+ /** Follower-affinity mode (FOLLOWER-AFFINITY-DESIGN.md §3): the shared ticket store. When set, the
27
+ * source records the follower's minted ticket from the `{t:"affinity"}` frame and CLEARS it on a
28
+ * sustained outage so the next (ticketless) reconnect anycasts to a live follower and re-pins
29
+ * (§8). Absent ⇒ affinity off (today's behavior). */
30
+ affinity?: AffinityTicketStore;
25
31
  }
26
32
  export declare class RemoteOptimisticSource implements OptimisticSource {
27
33
  /** The CURRENT transport (undefined in pure-lazy mode until the first lease opens one). */
@@ -33,9 +39,23 @@ export declare class RemoteOptimisticSource implements OptimisticSource {
33
39
  private readonly clientID;
34
40
  private readonly resolveSubscribe;
35
41
  private readonly pushMutationSender?;
42
+ /** The affinity ticket store (undefined ⇒ affinity off). See {@link RemoteOptimisticSourceOptions.affinity}. */
43
+ private readonly affinityStore?;
36
44
  private handler;
37
45
  private progressHandler;
38
46
  private restartHandler;
47
+ private outcomeHandler;
48
+ private resyncHandler;
49
+ /** Set by {@link resync} when this is a LEASE-AUTH session (some sub presented a `leaseToken`):
50
+ * transport pushes queue in {@link pendingPushes} until the first authenticated re-subscribe's
51
+ * hello re-establishes the socket's subject, then flush (see QState.authed). Never set on a
52
+ * token-less (embedded/rindled) session — its pushes need no subject and go straight out. */
53
+ private awaitingAuthedHello;
54
+ /** Envelopes held while {@link awaitingAuthedHello} (H-v §7.5 rule 3). Every entry corresponds
55
+ * to a still-pending backend mutation (the re-send reconstructs from pending entries; app
56
+ * invokes in the window are pending by definition), so a superseding resync may CLEAR this —
57
+ * its own re-send regenerates whatever still matters. */
58
+ private pendingPushes;
39
59
  private readonly subs;
40
60
  /** Queries whose subscribe is waiting for a transport to exist — endpoint-less subscribes issued
41
61
  * in pure-lazy mode before any lease opens a transport (the lmid system query is registered by
@@ -91,13 +111,38 @@ export declare class RemoteOptimisticSource implements OptimisticSource {
91
111
  pushMutation(envelope: MutationEnvelope): Promise<void>;
92
112
  onNormalized(handler: (qid: QueryId, ev: NormalizedEvent) => void): void;
93
113
  onProgress(handler: (frame: ProgressFrame) => void): void;
114
+ /** The room deopt handshake's verdict stream (H-v). Dispatched OUT-OF-BAND on arrival — see
115
+ * {@link onServerMsg}'s `mutationOutcome` arm for why it must never wait behind the cv buffer. */
116
+ onMutationOutcome(handler: (frame: MutationOutcomeFrame) => void): void;
117
+ /** Fired once per re-established session, SYNCHRONOUSLY inside {@link resync} — before any
118
+ * post-reconnect frame can release (the §7.5 rule-3 window: a replayed lmid snapshot must not
119
+ * retire an entry whose outcome frame died with the old socket before the re-send captured
120
+ * it). The backend re-sends the domain's unconfirmed pending envelopes with their original
121
+ * mids; on a lease-auth session their DELIVERY is deferred until the first token hello
122
+ * re-authenticates the socket ({@link pendingPushes}). */
123
+ onResync(handler: () => void): void;
94
124
  private subscribe;
95
125
  private onServerMsg;
96
- /** On reconnect: re-announce identity and re-subscribe every live query (each re-resolves its
97
- * lease, so a restarted daemon re-materializes + re-leases on the fly). */
126
+ /** On reconnect: re-announce identity, fire the `onResync` re-send, and re-subscribe every live
127
+ * query (each re-resolves its lease, so a restarted daemon re-materializes + re-leases on the
128
+ * fly). The re-send fires HERE — synchronously, before any post-reconnect frame can be
129
+ * processed — because the §7.5 rule-3 window closes fast: the re-subscribed lmid stream's
130
+ * fresh snapshot may cover a mid whose outcome frame died with the OLD socket, and once the
131
+ * release retires that entry as an apparent success there is nothing left to re-send (the
132
+ * lost-deopt write would silently vanish). Firing now captures the in-flight set intact; on a
133
+ * lease-auth session the envelopes themselves are HELD ({@link pendingPushes}) until the first
134
+ * token re-subscribe's hello re-authenticates the socket, then flush in order — so the shell's
135
+ * subject gate never refuses them, and its re-answer (a recorded outcome for any non-applied
136
+ * mid) resolves even an already-retired entry via the handshake's not-found arm. */
98
137
  private resync;
99
138
  /** Track the daemon's boot id; a change (after the first) means it restarted — fire onRestart. */
100
139
  private observeBootId;
140
+ /** Route a `queryError` by its 101 §5 classification: retryable ⇒ keep the QState (and the
141
+ * rows already folded downstream — 101 §6) and re-subscribe after a jittered backoff
142
+ * honoring `retryAfterMs`; terminal (or pre-classification servers) ⇒ drop the
143
+ * subscription, exactly as before. Fixes the stranded-client gap: a worker fault's or a
144
+ * shedding follower's error now heals end-to-end (FOLLOWER-LAG-SHED §6.3). */
145
+ private onQueryError;
101
146
  private openSubscriber;
102
147
  private applyBatch;
103
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"optimistic-source.d.ts","sourceRoot":"","sources":["../src/optimistic-source.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"optimistic-source.d.ts","sourceRoot":"","sources":["../src/optimistic-source.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,OAAO,EACP,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAMzD,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAuBhD;iDACiD;AACjD,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC;AAE/D;;;;;;uBAMuB;AACvB,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,GACxB;IAAE,OAAO,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC5C,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,kFAAkF;IAClF,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC;;;0DAGsD;IACtD,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,2FAA2F;IAC3F,OAAO,CAAC,SAAS,CAAwB;IACzC,yFAAyF;IACzF,OAAO,CAAC,eAAe,CAAqB;IAC5C,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAyB;IAC7D,gHAAgH;IAChH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAsB;IACrD,OAAO,CAAC,OAAO,CAAyD;IACxE,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,cAAc,CAAmD;IACzE,OAAO,CAAC,aAAa,CAAwB;IAC7C;;;kGAG8F;IAC9F,OAAO,CAAC,mBAAmB,CAAS;IACpC;;;8DAG0D;IAC1D,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;IACnD;;2EAEuE;IACvE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,8EAA8E;IAC9E,OAAO,CAAC,UAAU,CAAqB;IACvC,mGAAmG;IACnG,OAAO,CAAC,YAAY,CAAsC;IAC1D;gDAC4C;IAC5C,OAAO,CAAC,MAAM,CAAS;IACvB;;uCAEmC;IACnC,OAAO,CAAC,iBAAiB,CAAS;IAClC;wGACoG;IACpG,OAAO,CAAC,cAAc,CAAK;gBAEf,UAAU,EAAE,0BAA0B,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,6BAAkC;IAiB9G,+CAA+C;IAC/C,OAAO,CAAC,MAAM;IAcd,gGAAgG;IAChG,OAAO,CAAC,OAAO;IAYf,gFAAgF;IAChF,OAAO,CAAC,YAAY;IAKpB;;uDAEmD;IACnD,OAAO,CAAC,OAAO;IAOf;;;wDAGoD;IACpD,OAAO,CAAC,cAAc;IAUtB,mGAAmG;IACnG,OAAO,CAAC,aAAa;IAUrB;;;;yEAIqE;IACrE,OAAO,CAAC,MAAM;IAcd;+EAC2E;IAC3E,KAAK,IAAI,IAAI;IAWb;iGAC6F;IAC7F,SAAS,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpC,kBAAkB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,IAAI;IAIzD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IActD,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAQnC,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAavD,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAIxE,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAIzD;uGACmG;IACnG,iBAAiB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI;IAIvE;;;;;+DAK2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAMnC,OAAO,CAAC,SAAS;IA4DjB,OAAO,CAAC,WAAW;IAyCnB;;;;;;;;;;yFAUqF;IACrF,OAAO,CAAC,MAAM;IAYd,kGAAkG;IAClG,OAAO,CAAC,aAAa;IAMrB;;;;mFAI+E;IAC/E,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,UAAU;CAenB;AAED;;uCAEuC;AACvC,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,6BAAkC,GACvC,sBAAsB,CAMxB"}