@rindle/daemon-client 0.5.0 → 0.6.4
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.
- package/README.md +14 -11
- package/dist/index.d.ts +19 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +37 -37
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# @rindle/daemon-client
|
|
2
2
|
|
|
3
|
-
Low-level private client for a Rindle
|
|
4
|
-
file-backed Rust `rindle-server`
|
|
5
|
-
`
|
|
6
|
-
|
|
3
|
+
Low-level private client for a single Rindle node. It speaks the control contract of the
|
|
4
|
+
file-backed Rust nodes — a `rindle-server` **follower** (reads/subscriptions) or a
|
|
5
|
+
`rindle-replicator` **write-master** (writes). One client points at one node; in a synced
|
|
6
|
+
app `@rindle/api-server`'s `SplitDaemonClient` wraps two of these to route reads and writes
|
|
7
|
+
to the right node. (The former in-process JS daemon, `createRindleDaemon`, has been retired;
|
|
8
|
+
the contract now lives in `packages/reference/server/test/daemon-conformance.mjs`.)
|
|
7
9
|
|
|
8
10
|
It is intentionally small: it knows the control/write request shapes and can POST JSON to a
|
|
9
|
-
|
|
11
|
+
node, but it does not resolve named queries, authenticate users, or run application mutator
|
|
10
12
|
policy. Use `@rindle/api-server` for that higher-level app boundary.
|
|
11
13
|
|
|
12
14
|
Full docs — the control plane, seeding, and the boot-id re-warm hook:
|
|
@@ -17,18 +19,19 @@ the daemon itself: [rindle.sh/docs/daemon](https://rindle.sh/docs/daemon) · for
|
|
|
17
19
|
```ts
|
|
18
20
|
import { HttpRindleDaemonClient } from "@rindle/daemon-client";
|
|
19
21
|
|
|
20
|
-
const
|
|
21
|
-
baseUrl: "https://rindle.internal",
|
|
22
|
-
headers: { authorization: `Bearer ${process.env.RINDLE_DAEMON_TOKEN}` },
|
|
23
|
-
});
|
|
22
|
+
const authz = { authorization: `Bearer ${process.env.RINDLE_DAEMON_TOKEN}` };
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
// Reads/subscriptions → a follower.
|
|
25
|
+
const follower = new HttpRindleDaemonClient({ baseUrl: "https://follower.internal", headers: authz });
|
|
26
|
+
const lease = await follower.materialize({
|
|
26
27
|
ast,
|
|
27
28
|
mode: "normalized",
|
|
28
29
|
policy: { kind: "whileSubscribed" },
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
// Writes → the write-master (a follower has no write ingress).
|
|
33
|
+
const master = new HttpRindleDaemonClient({ baseUrl: "https://write-master.internal", headers: authz });
|
|
34
|
+
await master.executeSqlTxn({
|
|
32
35
|
clientID: "client-1",
|
|
33
36
|
mid: 1,
|
|
34
37
|
statements: [{ sql: "INSERT INTO issue (id, title) VALUES (?, ?)", params: [1, "first"] }],
|
package/dist/index.d.ts
CHANGED
|
@@ -15,17 +15,23 @@ export interface MaterializeInput {
|
|
|
15
15
|
leaseTtlMs?: number;
|
|
16
16
|
maxSubscribers?: number;
|
|
17
17
|
metadata?: Record<string, unknown>;
|
|
18
|
+
/** The browser's opaque follower-affinity ticket (FOLLOWER-AFFINITY-DESIGN.md §3), forwarded by
|
|
19
|
+
* the api-server. {@link HttpRindleDaemonClient} lifts it into the `Rindle-Affinity` request
|
|
20
|
+
* HEADER (never the body) so the fleet edge `fly-replay`s this `/materialize` to the follower the
|
|
21
|
+
* browser's ws is pinned to (§4) — both legs co-locate on one follower. Placement, not
|
|
22
|
+
* authorization: the follower verifies it, the api-server forwards it opaquely. Absent ⇒ no
|
|
23
|
+
* affinity (single daemon / affinity off), byte-identical to today. */
|
|
24
|
+
affinity?: string;
|
|
18
25
|
}
|
|
19
26
|
export interface MaterializeOutput {
|
|
20
27
|
materializationId: string;
|
|
21
28
|
queryKey?: string;
|
|
22
29
|
leaseToken: string;
|
|
23
30
|
reused?: boolean;
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
wsEndpoint?: string;
|
|
31
|
+
/** Fresh follower-placement ticket returned by an affinity-enabled daemon. A machine client
|
|
32
|
+
* opening a separate ws for this follower-local lease (for example a room upstream) offers it
|
|
33
|
+
* as a subprotocol so the fleet edge routes that socket back to the minting follower. */
|
|
34
|
+
affinity?: string;
|
|
29
35
|
}
|
|
30
36
|
export interface DematerializeInput {
|
|
31
37
|
materializationId?: string;
|
|
@@ -49,6 +55,10 @@ export interface SqlTxnOutput {
|
|
|
49
55
|
applied?: boolean;
|
|
50
56
|
cv?: number;
|
|
51
57
|
txId?: number | string;
|
|
58
|
+
/** Replicator-master commit identity (the public mutation SQL facade calls this `cursor`). */
|
|
59
|
+
cursor?: string;
|
|
60
|
+
/** Flat convenience mirror of this client's entry in `lmidAdvances`. */
|
|
61
|
+
lmid?: number;
|
|
52
62
|
lmidAdvances?: Array<{
|
|
53
63
|
clientID: string;
|
|
54
64
|
lmid: number;
|
|
@@ -127,19 +137,6 @@ export interface RoomLmidsInput {
|
|
|
127
137
|
export interface RoomLmidsOutput {
|
|
128
138
|
lmids: Record<string, number>;
|
|
129
139
|
}
|
|
130
|
-
/** `/cover-check` (RINDLE-REALTIME-QUERY-ENABLEMENT §2.3, slice G-iv-b): is `query`'s wire AST
|
|
131
|
-
* provably covered by the unwindowed room `footprint` AST? Pure — the daemon runs
|
|
132
|
-
* `rindle_cover::footprint_covers` inline (no engine command, no DB read). */
|
|
133
|
-
export interface CoverQueryInput {
|
|
134
|
-
footprint: unknown;
|
|
135
|
-
query: unknown;
|
|
136
|
-
}
|
|
137
|
-
/** The verdict: sound / no false positives — every `covered: false` is a safe "serve from the
|
|
138
|
-
* daemon", with human-readable `reasons` for the api-server's one-time diagnostic. */
|
|
139
|
-
export interface CoverQueryOutput {
|
|
140
|
-
covered: boolean;
|
|
141
|
-
reasons?: string[];
|
|
142
|
-
}
|
|
143
140
|
/** `/mutate-session/begin` (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1): open an interactive write
|
|
144
141
|
* transaction on the master, held open across round trips under the daemon-owned deadline.
|
|
145
142
|
* Client-attributed sessions (`clientID` + `mid`) get mid dedup/gap resolution UP FRONT — an
|
|
@@ -240,6 +237,10 @@ export interface QueryOnceInput {
|
|
|
240
237
|
ast: unknown;
|
|
241
238
|
visibilityKey?: string;
|
|
242
239
|
ttlMs?: number;
|
|
240
|
+
/** The browser's opaque follower-affinity ticket — see {@link MaterializeInput.affinity}. Lifted
|
|
241
|
+
* into the `Rindle-Affinity` header so an SSR / one-shot read co-locates on the same pinned
|
|
242
|
+
* follower the browser's ws is (or will be) on. */
|
|
243
|
+
affinity?: string;
|
|
243
244
|
}
|
|
244
245
|
/** The `POST /query` response: assembled `rows` (nested by name, ready to hydrate without an
|
|
245
246
|
* engine), the `cvMin` baseline they reflect, the per-query `schema` hello, and `queryKey`. */
|
|
@@ -252,10 +253,6 @@ export interface QueryOnceOutput {
|
|
|
252
253
|
cols: Record<string, WireValue>;
|
|
253
254
|
[rel: string]: unknown;
|
|
254
255
|
}>;
|
|
255
|
-
/** The follower this one-shot read warmed (READ-ROUTER-DESIGN.md §2.4) — the SSR loader injects
|
|
256
|
-
* it into the bootstrap so the booting client opens its ws to the same follower the warm
|
|
257
|
-
* pipeline lives on (the warm handoff). Absent ⇒ single-daemon. Stamped by the read router. */
|
|
258
|
-
wsEndpoint?: string;
|
|
259
256
|
}
|
|
260
257
|
/** One column in a {@link SchemaTable}: its name and the daemon's `ColType` wire name. */
|
|
261
258
|
export interface SchemaColumn {
|
|
@@ -318,11 +315,6 @@ export interface RindleDaemonClient {
|
|
|
318
315
|
claimRoomEpoch?(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
319
316
|
/** The room's boot probe (§3.3). Optional, same contract as {@link claimRoomEpoch}. */
|
|
320
317
|
roomLmids?(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
321
|
-
/** The §2.3 serve-proof (RINDLE-REALTIME-QUERY-ENABLEMENT G-iv-b): is `query` provably covered
|
|
322
|
-
* by the unwindowed room `footprint`? Optional, same contract as {@link claimRoomEpoch}: only
|
|
323
|
-
* daemons hosting the covering checker implement it, and the api-server's lease path FAILS
|
|
324
|
-
* OPEN (serves from the daemon, exactly as today) when its configured client lacks it. */
|
|
325
|
-
coverQuery?(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
326
318
|
}
|
|
327
319
|
export interface HttpRindleDaemonClientPaths {
|
|
328
320
|
materialize: string;
|
|
@@ -336,7 +328,6 @@ export interface HttpRindleDaemonClientPaths {
|
|
|
336
328
|
schema: string;
|
|
337
329
|
claimRoomEpoch: string;
|
|
338
330
|
roomLmids: string;
|
|
339
|
-
coverQuery: string;
|
|
340
331
|
mutateSessionBegin: string;
|
|
341
332
|
mutateSessionExec: string;
|
|
342
333
|
mutateSessionQuery: string;
|
|
@@ -395,7 +386,6 @@ export declare class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
395
386
|
applyRowChangeTxn(input: RowChangeTxn): Promise<RowChangeTxnOutput>;
|
|
396
387
|
claimRoomEpoch(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
397
388
|
roomLmids(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
398
|
-
coverQuery(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
399
389
|
rejectMutation(input: MutationRejection): Promise<MutationRejectionOutput>;
|
|
400
390
|
beginMutationSession(input: MutationSessionBegin): Promise<MutationSessionBeginOutput>;
|
|
401
391
|
execInMutationSession(input: MutationSessionExec): Promise<unknown>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,YAAY,CAAC;AAE/C,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/** The api-server → fleet control-plane header carrying the browser's opaque affinity ticket on
|
|
2
|
+
* `/materialize` and `/query` (FOLLOWER-AFFINITY-DESIGN.md §5). Inlined (not imported from
|
|
3
|
+
* `@rindle/affinity`'s `HEADER_NAME`) to keep this client free of that crate's `node:crypto`
|
|
4
|
+
* dependency — an api-server may run on a Worker. Keep the two spellings in lock-step. */
|
|
5
|
+
const AFFINITY_HEADER = "Rindle-Affinity";
|
|
1
6
|
const defaultPaths = {
|
|
2
7
|
materialize: "/materialize",
|
|
3
8
|
dematerialize: "/dematerialize",
|
|
@@ -10,7 +15,6 @@ const defaultPaths = {
|
|
|
10
15
|
schema: "/schema",
|
|
11
16
|
claimRoomEpoch: "/claim-room-epoch",
|
|
12
17
|
roomLmids: "/room-lmids",
|
|
13
|
-
coverQuery: "/cover-check",
|
|
14
18
|
mutateSessionBegin: "/mutate-session/begin",
|
|
15
19
|
mutateSessionExec: "/mutate-session/exec",
|
|
16
20
|
mutateSessionQuery: "/mutate-session/query",
|
|
@@ -44,7 +48,11 @@ export class HttpRindleDaemonClient {
|
|
|
44
48
|
this.onBootId = opts.onBootId;
|
|
45
49
|
}
|
|
46
50
|
materialize(input) {
|
|
47
|
-
|
|
51
|
+
// The affinity ticket rides the `Rindle-Affinity` HEADER, not the body (the fleet edge reads it
|
|
52
|
+
// pre-dispatch to `fly-replay` this POST to the pinned follower). Strip it from the body so the
|
|
53
|
+
// daemon's `MaterializeInput` deserialization never sees an unknown field.
|
|
54
|
+
const { affinity, ...body } = input;
|
|
55
|
+
return this.post(this.paths.materialize, body, affinity);
|
|
48
56
|
}
|
|
49
57
|
dematerialize(input) {
|
|
50
58
|
return this.post(this.paths.dematerialize, input);
|
|
@@ -67,9 +75,6 @@ export class HttpRindleDaemonClient {
|
|
|
67
75
|
roomLmids(input) {
|
|
68
76
|
return this.post(this.paths.roomLmids, input);
|
|
69
77
|
}
|
|
70
|
-
coverQuery(input) {
|
|
71
|
-
return this.post(this.paths.coverQuery, input);
|
|
72
|
-
}
|
|
73
78
|
rejectMutation(input) {
|
|
74
79
|
return this.post(this.paths.rejectMutation, input);
|
|
75
80
|
}
|
|
@@ -89,7 +94,8 @@ export class HttpRindleDaemonClient {
|
|
|
89
94
|
return this.post(this.paths.mutateSessionRollback, input);
|
|
90
95
|
}
|
|
91
96
|
query(input) {
|
|
92
|
-
|
|
97
|
+
const { affinity, ...body } = input;
|
|
98
|
+
return this.post(this.paths.query, body, affinity);
|
|
93
99
|
}
|
|
94
100
|
migrate(input) {
|
|
95
101
|
return this.post(this.paths.migrate, input);
|
|
@@ -108,8 +114,13 @@ export class HttpRindleDaemonClient {
|
|
|
108
114
|
schema() {
|
|
109
115
|
return this.get(this.paths.schema);
|
|
110
116
|
}
|
|
111
|
-
async post(path, input) {
|
|
117
|
+
async post(path, input, affinity) {
|
|
112
118
|
const headers = await this.resolveHeaders();
|
|
119
|
+
// The api-server → fleet control-plane affinity ticket rides as a header on top of the usual
|
|
120
|
+
// bearer/content headers (FOLLOWER-AFFINITY-DESIGN.md §5); the fleet edge reads it to `fly-replay`
|
|
121
|
+
// to the pinned follower. Only `/materialize` + `/query` carry one.
|
|
122
|
+
if (affinity !== undefined)
|
|
123
|
+
headers[AFFINITY_HEADER] = affinity;
|
|
113
124
|
const res = await this.fetchImpl(urlJoin(this.baseUrl, path), {
|
|
114
125
|
method: "POST",
|
|
115
126
|
headers: { "content-type": "application/json", ...headers },
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4XA;;;2FAG2F;AAC3F,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAE1C,MAAM,YAAY,GAAgC;IAChD,WAAW,EAAE,cAAc;IAC3B,aAAa,EAAE,gBAAgB;IAC/B,aAAa,EAAE,kBAAkB;IACjC,cAAc,EAAE,mBAAmB;IACnC,iBAAiB,EAAE,uBAAuB;IAC1C,cAAc,EAAE,kBAAkB;IAClC,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,SAAS;IACjB,cAAc,EAAE,mBAAmB;IACnC,SAAS,EAAE,aAAa;IACxB,kBAAkB,EAAE,uBAAuB;IAC3C,iBAAiB,EAAE,sBAAsB;IACzC,kBAAkB,EAAE,uBAAuB;IAC3C,mBAAmB,EAAE,wBAAwB;IAC7C,qBAAqB,EAAE,0BAA0B;CAClD,CAAC;AAEF,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAS;IACf,UAAU,CAAS;IACnB,IAAI,CAAS;IAEtB,YAAY,MAAc,EAAE,UAAkB,EAAE,IAAY;QAC1D,KAAK,CAAC,iCAAiC,MAAM,IAAI,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,sBAAsB;IAChB,OAAO,CAAS;IAChB,SAAS,CAAY;IACrB,OAAO,CAAiC;IACxC,KAAK,CAA8B;IACnC,QAAQ,CAA4B;IAC7C,UAAU,CAAU;IAE5B,YAAY,IAAmC;QAC7C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAChD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED,WAAW,CAAC,KAAuB;QACjC,gGAAgG;QAChG,gGAAgG;QAChG,2EAA2E;QAC3E,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,aAAa,CAAC,KAAyB;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,cAAc,CAAC,KAAc;QAC3B,8FAA8F;QAC9F,4FAA4F;QAC5F,kEAAkE;QAClE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,iBAAiB,CAAC,KAAmB;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED,cAAc,CAAC,KAA0B;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,SAAS,CAAC,KAAqB;QAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,cAAc,CAAC,KAAwB;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,oBAAoB,CAAC,KAA2B;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,qBAAqB,CAAC,KAA0B;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED,sBAAsB,CAAC,KAA2B;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,qBAAqB,CAAC,KAAyB;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,uBAAuB,CAAC,KAAyB;QAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,KAAqB;QACzB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,KAAmB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED;;;yGAGqG;IACrG,YAAY,CAAC,MAAsB;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED;;;sGAGkG;IAClG,MAAM;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,KAAc,EAAE,QAAiB;QACnE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5C,6FAA6F;QAC7F,mGAAmG;QACnG,oEAAoE;QACpE,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC;QAChE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE;YAC3D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAM,CAAC;IACpD,CAAC;IAED;;qBAEiB;IACT,KAAK,CAAC,GAAG,CAAI,IAAY;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAC5D,MAAM,EAAE,KAAK;YACb,OAAO;YACP,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAM,CAAC;IACpD,CAAC;IAED;;sEAEkE;IAC1D,aAAa,CAAC,GAAsB;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,gBAAgB,CAAC,IAAI,SAAS,CAAC;QAC/D,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO;QAClD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC7F,MAAM,GAAG,GAA2B,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,KAAK,KAAK,SAAS;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,OAAO,CAAC,OAAe,EAAE,IAAY;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AACvC,CAAC;AAOD,MAAM,YAAY,GAAc,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;IACpD,MAAM,SAAS,GAAI,UAAoC,CAAC,KAAK,CAAC;IAC9D,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC1G,4FAA4F;IAC5F,oEAAoE;IACpE,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,CAAC"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface MaterializeInput {
|
|
|
14
14
|
leaseTtlMs?: number;
|
|
15
15
|
maxSubscribers?: number;
|
|
16
16
|
metadata?: Record<string, unknown>;
|
|
17
|
+
/** The browser's opaque follower-affinity ticket (FOLLOWER-AFFINITY-DESIGN.md §3), forwarded by
|
|
18
|
+
* the api-server. {@link HttpRindleDaemonClient} lifts it into the `Rindle-Affinity` request
|
|
19
|
+
* HEADER (never the body) so the fleet edge `fly-replay`s this `/materialize` to the follower the
|
|
20
|
+
* browser's ws is pinned to (§4) — both legs co-locate on one follower. Placement, not
|
|
21
|
+
* authorization: the follower verifies it, the api-server forwards it opaquely. Absent ⇒ no
|
|
22
|
+
* affinity (single daemon / affinity off), byte-identical to today. */
|
|
23
|
+
affinity?: string;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
export interface MaterializeOutput {
|
|
@@ -21,11 +28,10 @@ export interface MaterializeOutput {
|
|
|
21
28
|
queryKey?: string;
|
|
22
29
|
leaseToken: string;
|
|
23
30
|
reused?: boolean;
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
wsEndpoint?: string;
|
|
31
|
+
/** Fresh follower-placement ticket returned by an affinity-enabled daemon. A machine client
|
|
32
|
+
* opening a separate ws for this follower-local lease (for example a room upstream) offers it
|
|
33
|
+
* as a subprotocol so the fleet edge routes that socket back to the minting follower. */
|
|
34
|
+
affinity?: string;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
export interface DematerializeInput {
|
|
@@ -54,6 +60,10 @@ export interface SqlTxnOutput {
|
|
|
54
60
|
applied?: boolean;
|
|
55
61
|
cv?: number;
|
|
56
62
|
txId?: number | string;
|
|
63
|
+
/** Replicator-master commit identity (the public mutation SQL facade calls this `cursor`). */
|
|
64
|
+
cursor?: string;
|
|
65
|
+
/** Flat convenience mirror of this client's entry in `lmidAdvances`. */
|
|
66
|
+
lmid?: number;
|
|
57
67
|
lmidAdvances?: Array<{ clientID: string; lmid: number }>;
|
|
58
68
|
}
|
|
59
69
|
|
|
@@ -127,20 +137,6 @@ export interface RoomLmidsOutput {
|
|
|
127
137
|
lmids: Record<string, number>;
|
|
128
138
|
}
|
|
129
139
|
|
|
130
|
-
/** `/cover-check` (RINDLE-REALTIME-QUERY-ENABLEMENT §2.3, slice G-iv-b): is `query`'s wire AST
|
|
131
|
-
* provably covered by the unwindowed room `footprint` AST? Pure — the daemon runs
|
|
132
|
-
* `rindle_cover::footprint_covers` inline (no engine command, no DB read). */
|
|
133
|
-
export interface CoverQueryInput {
|
|
134
|
-
footprint: unknown;
|
|
135
|
-
query: unknown;
|
|
136
|
-
}
|
|
137
|
-
/** The verdict: sound / no false positives — every `covered: false` is a safe "serve from the
|
|
138
|
-
* daemon", with human-readable `reasons` for the api-server's one-time diagnostic. */
|
|
139
|
-
export interface CoverQueryOutput {
|
|
140
|
-
covered: boolean;
|
|
141
|
-
reasons?: string[];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
140
|
/** `/mutate-session/begin` (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1): open an interactive write
|
|
145
141
|
* transaction on the master, held open across round trips under the daemon-owned deadline.
|
|
146
142
|
* Client-attributed sessions (`clientID` + `mid`) get mid dedup/gap resolution UP FRONT — an
|
|
@@ -249,6 +245,10 @@ export interface QueryOnceInput {
|
|
|
249
245
|
ast: unknown;
|
|
250
246
|
visibilityKey?: string;
|
|
251
247
|
ttlMs?: number;
|
|
248
|
+
/** The browser's opaque follower-affinity ticket — see {@link MaterializeInput.affinity}. Lifted
|
|
249
|
+
* into the `Rindle-Affinity` header so an SSR / one-shot read co-locates on the same pinned
|
|
250
|
+
* follower the browser's ws is (or will be) on. */
|
|
251
|
+
affinity?: string;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/** The `POST /query` response: assembled `rows` (nested by name, ready to hydrate without an
|
|
@@ -259,10 +259,6 @@ export interface QueryOnceOutput {
|
|
|
259
259
|
bootId?: string;
|
|
260
260
|
schema?: unknown;
|
|
261
261
|
rows: Array<{ cols: Record<string, WireValue>; [rel: string]: unknown }>;
|
|
262
|
-
/** The follower this one-shot read warmed (READ-ROUTER-DESIGN.md §2.4) — the SSR loader injects
|
|
263
|
-
* it into the bootstrap so the booting client opens its ws to the same follower the warm
|
|
264
|
-
* pipeline lives on (the warm handoff). Absent ⇒ single-daemon. Stamped by the read router. */
|
|
265
|
-
wsEndpoint?: string;
|
|
266
262
|
}
|
|
267
263
|
|
|
268
264
|
/** One column in a {@link SchemaTable}: its name and the daemon's `ColType` wire name. */
|
|
@@ -329,11 +325,6 @@ export interface RindleDaemonClient {
|
|
|
329
325
|
claimRoomEpoch?(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
330
326
|
/** The room's boot probe (§3.3). Optional, same contract as {@link claimRoomEpoch}. */
|
|
331
327
|
roomLmids?(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
332
|
-
/** The §2.3 serve-proof (RINDLE-REALTIME-QUERY-ENABLEMENT G-iv-b): is `query` provably covered
|
|
333
|
-
* by the unwindowed room `footprint`? Optional, same contract as {@link claimRoomEpoch}: only
|
|
334
|
-
* daemons hosting the covering checker implement it, and the api-server's lease path FAILS
|
|
335
|
-
* OPEN (serves from the daemon, exactly as today) when its configured client lacks it. */
|
|
336
|
-
coverQuery?(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
337
328
|
}
|
|
338
329
|
|
|
339
330
|
export interface HttpRindleDaemonClientPaths {
|
|
@@ -348,7 +339,6 @@ export interface HttpRindleDaemonClientPaths {
|
|
|
348
339
|
schema: string;
|
|
349
340
|
claimRoomEpoch: string;
|
|
350
341
|
roomLmids: string;
|
|
351
|
-
coverQuery: string;
|
|
352
342
|
mutateSessionBegin: string;
|
|
353
343
|
mutateSessionExec: string;
|
|
354
344
|
mutateSessionQuery: string;
|
|
@@ -388,6 +378,12 @@ export interface HttpRindleDaemonClientOptions {
|
|
|
388
378
|
onBootId?: (bootId: string) => void;
|
|
389
379
|
}
|
|
390
380
|
|
|
381
|
+
/** The api-server → fleet control-plane header carrying the browser's opaque affinity ticket on
|
|
382
|
+
* `/materialize` and `/query` (FOLLOWER-AFFINITY-DESIGN.md §5). Inlined (not imported from
|
|
383
|
+
* `@rindle/affinity`'s `HEADER_NAME`) to keep this client free of that crate's `node:crypto`
|
|
384
|
+
* dependency — an api-server may run on a Worker. Keep the two spellings in lock-step. */
|
|
385
|
+
const AFFINITY_HEADER = "Rindle-Affinity";
|
|
386
|
+
|
|
391
387
|
const defaultPaths: HttpRindleDaemonClientPaths = {
|
|
392
388
|
materialize: "/materialize",
|
|
393
389
|
dematerialize: "/dematerialize",
|
|
@@ -400,7 +396,6 @@ const defaultPaths: HttpRindleDaemonClientPaths = {
|
|
|
400
396
|
schema: "/schema",
|
|
401
397
|
claimRoomEpoch: "/claim-room-epoch",
|
|
402
398
|
roomLmids: "/room-lmids",
|
|
403
|
-
coverQuery: "/cover-check",
|
|
404
399
|
mutateSessionBegin: "/mutate-session/begin",
|
|
405
400
|
mutateSessionExec: "/mutate-session/exec",
|
|
406
401
|
mutateSessionQuery: "/mutate-session/query",
|
|
@@ -439,7 +434,11 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
439
434
|
}
|
|
440
435
|
|
|
441
436
|
materialize(input: MaterializeInput): Promise<MaterializeOutput> {
|
|
442
|
-
|
|
437
|
+
// The affinity ticket rides the `Rindle-Affinity` HEADER, not the body (the fleet edge reads it
|
|
438
|
+
// pre-dispatch to `fly-replay` this POST to the pinned follower). Strip it from the body so the
|
|
439
|
+
// daemon's `MaterializeInput` deserialization never sees an unknown field.
|
|
440
|
+
const { affinity, ...body } = input;
|
|
441
|
+
return this.post(this.paths.materialize, body, affinity);
|
|
443
442
|
}
|
|
444
443
|
|
|
445
444
|
dematerialize(input: DematerializeInput): Promise<DematerializeOutput> {
|
|
@@ -469,10 +468,6 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
469
468
|
return this.post(this.paths.roomLmids, input);
|
|
470
469
|
}
|
|
471
470
|
|
|
472
|
-
coverQuery(input: CoverQueryInput): Promise<CoverQueryOutput> {
|
|
473
|
-
return this.post(this.paths.coverQuery, input);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
471
|
rejectMutation(input: MutationRejection): Promise<MutationRejectionOutput> {
|
|
477
472
|
return this.post(this.paths.rejectMutation, input);
|
|
478
473
|
}
|
|
@@ -498,7 +493,8 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
498
493
|
}
|
|
499
494
|
|
|
500
495
|
query(input: QueryOnceInput): Promise<QueryOnceOutput> {
|
|
501
|
-
|
|
496
|
+
const { affinity, ...body } = input;
|
|
497
|
+
return this.post(this.paths.query, body, affinity);
|
|
502
498
|
}
|
|
503
499
|
|
|
504
500
|
migrate(input: MigrateInput): Promise<MigrateOutput> {
|
|
@@ -521,8 +517,12 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
521
517
|
return this.get(this.paths.schema);
|
|
522
518
|
}
|
|
523
519
|
|
|
524
|
-
private async post<T>(path: string, input: unknown): Promise<T> {
|
|
520
|
+
private async post<T>(path: string, input: unknown, affinity?: string): Promise<T> {
|
|
525
521
|
const headers = await this.resolveHeaders();
|
|
522
|
+
// The api-server → fleet control-plane affinity ticket rides as a header on top of the usual
|
|
523
|
+
// bearer/content headers (FOLLOWER-AFFINITY-DESIGN.md §5); the fleet edge reads it to `fly-replay`
|
|
524
|
+
// to the pinned follower. Only `/materialize` + `/query` carry one.
|
|
525
|
+
if (affinity !== undefined) headers[AFFINITY_HEADER] = affinity;
|
|
526
526
|
const res = await this.fetchImpl(urlJoin(this.baseUrl, path), {
|
|
527
527
|
method: "POST",
|
|
528
528
|
headers: { "content-type": "application/json", ...headers },
|