@rindle/daemon-client 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.
- package/README.md +14 -11
- package/dist/index.d.ts +39 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +62 -13
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;
|
|
@@ -117,13 +123,29 @@ export interface ClaimRoomEpochInput {
|
|
|
117
123
|
export interface ClaimRoomEpochOutput {
|
|
118
124
|
epoch: number;
|
|
119
125
|
}
|
|
120
|
-
/** `/room-lmids` (§3.3): the ledger's lmid per client — the
|
|
126
|
+
/** `/room-lmids` (§3.3): the domain-scoped ledger's lmid per client under `doc` — the
|
|
127
|
+
* room's boot probe. `doc` scopes the read to `_rindle_room_client_mutations` (§7.1), so a
|
|
128
|
+
* client's room stream never aliases its slow-path daemon stream. */
|
|
121
129
|
export interface RoomLmidsInput {
|
|
130
|
+
doc: string;
|
|
122
131
|
clients: string[];
|
|
123
132
|
}
|
|
124
133
|
export interface RoomLmidsOutput {
|
|
125
134
|
lmids: Record<string, number>;
|
|
126
135
|
}
|
|
136
|
+
/** `/cover-check` (RINDLE-REALTIME-QUERY-ENABLEMENT §2.3, slice G-iv-b): is `query`'s wire AST
|
|
137
|
+
* provably covered by the unwindowed room `footprint` AST? Pure — the daemon runs
|
|
138
|
+
* `rindle_cover::footprint_covers` inline (no engine command, no DB read). */
|
|
139
|
+
export interface CoverQueryInput {
|
|
140
|
+
footprint: unknown;
|
|
141
|
+
query: unknown;
|
|
142
|
+
}
|
|
143
|
+
/** The verdict: sound / no false positives — every `covered: false` is a safe "serve from the
|
|
144
|
+
* daemon", with human-readable `reasons` for the api-server's one-time diagnostic. */
|
|
145
|
+
export interface CoverQueryOutput {
|
|
146
|
+
covered: boolean;
|
|
147
|
+
reasons?: string[];
|
|
148
|
+
}
|
|
127
149
|
/** `/mutate-session/begin` (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1): open an interactive write
|
|
128
150
|
* transaction on the master, held open across round trips under the daemon-owned deadline.
|
|
129
151
|
* Client-attributed sessions (`clientID` + `mid`) get mid dedup/gap resolution UP FRONT — an
|
|
@@ -224,6 +246,10 @@ export interface QueryOnceInput {
|
|
|
224
246
|
ast: unknown;
|
|
225
247
|
visibilityKey?: string;
|
|
226
248
|
ttlMs?: number;
|
|
249
|
+
/** The browser's opaque follower-affinity ticket — see {@link MaterializeInput.affinity}. Lifted
|
|
250
|
+
* into the `Rindle-Affinity` header so an SSR / one-shot read co-locates on the same pinned
|
|
251
|
+
* follower the browser's ws is (or will be) on. */
|
|
252
|
+
affinity?: string;
|
|
227
253
|
}
|
|
228
254
|
/** The `POST /query` response: assembled `rows` (nested by name, ready to hydrate without an
|
|
229
255
|
* engine), the `cvMin` baseline they reflect, the per-query `schema` hello, and `queryKey`. */
|
|
@@ -236,10 +262,6 @@ export interface QueryOnceOutput {
|
|
|
236
262
|
cols: Record<string, WireValue>;
|
|
237
263
|
[rel: string]: unknown;
|
|
238
264
|
}>;
|
|
239
|
-
/** The follower this one-shot read warmed (READ-ROUTER-DESIGN.md §2.4) — the SSR loader injects
|
|
240
|
-
* it into the bootstrap so the booting client opens its ws to the same follower the warm
|
|
241
|
-
* pipeline lives on (the warm handoff). Absent ⇒ single-daemon. Stamped by the read router. */
|
|
242
|
-
wsEndpoint?: string;
|
|
243
265
|
}
|
|
244
266
|
/** One column in a {@link SchemaTable}: its name and the daemon's `ColType` wire name. */
|
|
245
267
|
export interface SchemaColumn {
|
|
@@ -302,6 +324,11 @@ export interface RindleDaemonClient {
|
|
|
302
324
|
claimRoomEpoch?(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
303
325
|
/** The room's boot probe (§3.3). Optional, same contract as {@link claimRoomEpoch}. */
|
|
304
326
|
roomLmids?(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
327
|
+
/** The §2.3 serve-proof (RINDLE-REALTIME-QUERY-ENABLEMENT G-iv-b): is `query` provably covered
|
|
328
|
+
* by the unwindowed room `footprint`? Optional, same contract as {@link claimRoomEpoch}: only
|
|
329
|
+
* daemons hosting the covering checker implement it, and the api-server's lease path FAILS
|
|
330
|
+
* OPEN (serves from the daemon, exactly as today) when its configured client lacks it. */
|
|
331
|
+
coverQuery?(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
305
332
|
}
|
|
306
333
|
export interface HttpRindleDaemonClientPaths {
|
|
307
334
|
materialize: string;
|
|
@@ -315,6 +342,7 @@ export interface HttpRindleDaemonClientPaths {
|
|
|
315
342
|
schema: string;
|
|
316
343
|
claimRoomEpoch: string;
|
|
317
344
|
roomLmids: string;
|
|
345
|
+
coverQuery: string;
|
|
318
346
|
mutateSessionBegin: string;
|
|
319
347
|
mutateSessionExec: string;
|
|
320
348
|
mutateSessionQuery: string;
|
|
@@ -373,6 +401,7 @@ export declare class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
373
401
|
applyRowChangeTxn(input: RowChangeTxn): Promise<RowChangeTxnOutput>;
|
|
374
402
|
claimRoomEpoch(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
375
403
|
roomLmids(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
404
|
+
coverQuery(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
376
405
|
rejectMutation(input: MutationRejection): Promise<MutationRejectionOutput>;
|
|
377
406
|
beginMutationSession(input: MutationSessionBegin): Promise<MutationSessionBeginOutput>;
|
|
378
407
|
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,6 +15,7 @@ const defaultPaths = {
|
|
|
10
15
|
schema: "/schema",
|
|
11
16
|
claimRoomEpoch: "/claim-room-epoch",
|
|
12
17
|
roomLmids: "/room-lmids",
|
|
18
|
+
coverQuery: "/cover-check",
|
|
13
19
|
mutateSessionBegin: "/mutate-session/begin",
|
|
14
20
|
mutateSessionExec: "/mutate-session/exec",
|
|
15
21
|
mutateSessionQuery: "/mutate-session/query",
|
|
@@ -43,7 +49,11 @@ export class HttpRindleDaemonClient {
|
|
|
43
49
|
this.onBootId = opts.onBootId;
|
|
44
50
|
}
|
|
45
51
|
materialize(input) {
|
|
46
|
-
|
|
52
|
+
// The affinity ticket rides the `Rindle-Affinity` HEADER, not the body (the fleet edge reads it
|
|
53
|
+
// pre-dispatch to `fly-replay` this POST to the pinned follower). Strip it from the body so the
|
|
54
|
+
// daemon's `MaterializeInput` deserialization never sees an unknown field.
|
|
55
|
+
const { affinity, ...body } = input;
|
|
56
|
+
return this.post(this.paths.materialize, body, affinity);
|
|
47
57
|
}
|
|
48
58
|
dematerialize(input) {
|
|
49
59
|
return this.post(this.paths.dematerialize, input);
|
|
@@ -66,6 +76,9 @@ export class HttpRindleDaemonClient {
|
|
|
66
76
|
roomLmids(input) {
|
|
67
77
|
return this.post(this.paths.roomLmids, input);
|
|
68
78
|
}
|
|
79
|
+
coverQuery(input) {
|
|
80
|
+
return this.post(this.paths.coverQuery, input);
|
|
81
|
+
}
|
|
69
82
|
rejectMutation(input) {
|
|
70
83
|
return this.post(this.paths.rejectMutation, input);
|
|
71
84
|
}
|
|
@@ -85,7 +98,8 @@ export class HttpRindleDaemonClient {
|
|
|
85
98
|
return this.post(this.paths.mutateSessionRollback, input);
|
|
86
99
|
}
|
|
87
100
|
query(input) {
|
|
88
|
-
|
|
101
|
+
const { affinity, ...body } = input;
|
|
102
|
+
return this.post(this.paths.query, body, affinity);
|
|
89
103
|
}
|
|
90
104
|
migrate(input) {
|
|
91
105
|
return this.post(this.paths.migrate, input);
|
|
@@ -104,8 +118,13 @@ export class HttpRindleDaemonClient {
|
|
|
104
118
|
schema() {
|
|
105
119
|
return this.get(this.paths.schema);
|
|
106
120
|
}
|
|
107
|
-
async post(path, input) {
|
|
121
|
+
async post(path, input, affinity) {
|
|
108
122
|
const headers = await this.resolveHeaders();
|
|
123
|
+
// The api-server → fleet control-plane affinity ticket rides as a header on top of the usual
|
|
124
|
+
// bearer/content headers (FOLLOWER-AFFINITY-DESIGN.md §5); the fleet edge reads it to `fly-replay`
|
|
125
|
+
// to the pinned follower. Only `/materialize` + `/query` carry one.
|
|
126
|
+
if (affinity !== undefined)
|
|
127
|
+
headers[AFFINITY_HEADER] = affinity;
|
|
109
128
|
const res = await this.fetchImpl(urlJoin(this.baseUrl, path), {
|
|
110
129
|
method: "POST",
|
|
111
130
|
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":"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"}
|
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 {
|
|
@@ -116,14 +122,31 @@ export interface ClaimRoomEpochOutput {
|
|
|
116
122
|
epoch: number;
|
|
117
123
|
}
|
|
118
124
|
|
|
119
|
-
/** `/room-lmids` (§3.3): the ledger's lmid per client — the
|
|
125
|
+
/** `/room-lmids` (§3.3): the domain-scoped ledger's lmid per client under `doc` — the
|
|
126
|
+
* room's boot probe. `doc` scopes the read to `_rindle_room_client_mutations` (§7.1), so a
|
|
127
|
+
* client's room stream never aliases its slow-path daemon stream. */
|
|
120
128
|
export interface RoomLmidsInput {
|
|
129
|
+
doc: string;
|
|
121
130
|
clients: string[];
|
|
122
131
|
}
|
|
123
132
|
export interface RoomLmidsOutput {
|
|
124
133
|
lmids: Record<string, number>;
|
|
125
134
|
}
|
|
126
135
|
|
|
136
|
+
/** `/cover-check` (RINDLE-REALTIME-QUERY-ENABLEMENT §2.3, slice G-iv-b): is `query`'s wire AST
|
|
137
|
+
* provably covered by the unwindowed room `footprint` AST? Pure — the daemon runs
|
|
138
|
+
* `rindle_cover::footprint_covers` inline (no engine command, no DB read). */
|
|
139
|
+
export interface CoverQueryInput {
|
|
140
|
+
footprint: unknown;
|
|
141
|
+
query: unknown;
|
|
142
|
+
}
|
|
143
|
+
/** The verdict: sound / no false positives — every `covered: false` is a safe "serve from the
|
|
144
|
+
* daemon", with human-readable `reasons` for the api-server's one-time diagnostic. */
|
|
145
|
+
export interface CoverQueryOutput {
|
|
146
|
+
covered: boolean;
|
|
147
|
+
reasons?: string[];
|
|
148
|
+
}
|
|
149
|
+
|
|
127
150
|
/** `/mutate-session/begin` (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1): open an interactive write
|
|
128
151
|
* transaction on the master, held open across round trips under the daemon-owned deadline.
|
|
129
152
|
* Client-attributed sessions (`clientID` + `mid`) get mid dedup/gap resolution UP FRONT — an
|
|
@@ -232,6 +255,10 @@ export interface QueryOnceInput {
|
|
|
232
255
|
ast: unknown;
|
|
233
256
|
visibilityKey?: string;
|
|
234
257
|
ttlMs?: number;
|
|
258
|
+
/** The browser's opaque follower-affinity ticket — see {@link MaterializeInput.affinity}. Lifted
|
|
259
|
+
* into the `Rindle-Affinity` header so an SSR / one-shot read co-locates on the same pinned
|
|
260
|
+
* follower the browser's ws is (or will be) on. */
|
|
261
|
+
affinity?: string;
|
|
235
262
|
}
|
|
236
263
|
|
|
237
264
|
/** The `POST /query` response: assembled `rows` (nested by name, ready to hydrate without an
|
|
@@ -242,10 +269,6 @@ export interface QueryOnceOutput {
|
|
|
242
269
|
bootId?: string;
|
|
243
270
|
schema?: unknown;
|
|
244
271
|
rows: Array<{ cols: Record<string, WireValue>; [rel: string]: unknown }>;
|
|
245
|
-
/** The follower this one-shot read warmed (READ-ROUTER-DESIGN.md §2.4) — the SSR loader injects
|
|
246
|
-
* it into the bootstrap so the booting client opens its ws to the same follower the warm
|
|
247
|
-
* pipeline lives on (the warm handoff). Absent ⇒ single-daemon. Stamped by the read router. */
|
|
248
|
-
wsEndpoint?: string;
|
|
249
272
|
}
|
|
250
273
|
|
|
251
274
|
/** One column in a {@link SchemaTable}: its name and the daemon's `ColType` wire name. */
|
|
@@ -312,6 +335,11 @@ export interface RindleDaemonClient {
|
|
|
312
335
|
claimRoomEpoch?(input: ClaimRoomEpochInput): Promise<ClaimRoomEpochOutput>;
|
|
313
336
|
/** The room's boot probe (§3.3). Optional, same contract as {@link claimRoomEpoch}. */
|
|
314
337
|
roomLmids?(input: RoomLmidsInput): Promise<RoomLmidsOutput>;
|
|
338
|
+
/** The §2.3 serve-proof (RINDLE-REALTIME-QUERY-ENABLEMENT G-iv-b): is `query` provably covered
|
|
339
|
+
* by the unwindowed room `footprint`? Optional, same contract as {@link claimRoomEpoch}: only
|
|
340
|
+
* daemons hosting the covering checker implement it, and the api-server's lease path FAILS
|
|
341
|
+
* OPEN (serves from the daemon, exactly as today) when its configured client lacks it. */
|
|
342
|
+
coverQuery?(input: CoverQueryInput): Promise<CoverQueryOutput>;
|
|
315
343
|
}
|
|
316
344
|
|
|
317
345
|
export interface HttpRindleDaemonClientPaths {
|
|
@@ -326,6 +354,7 @@ export interface HttpRindleDaemonClientPaths {
|
|
|
326
354
|
schema: string;
|
|
327
355
|
claimRoomEpoch: string;
|
|
328
356
|
roomLmids: string;
|
|
357
|
+
coverQuery: string;
|
|
329
358
|
mutateSessionBegin: string;
|
|
330
359
|
mutateSessionExec: string;
|
|
331
360
|
mutateSessionQuery: string;
|
|
@@ -365,6 +394,12 @@ export interface HttpRindleDaemonClientOptions {
|
|
|
365
394
|
onBootId?: (bootId: string) => void;
|
|
366
395
|
}
|
|
367
396
|
|
|
397
|
+
/** The api-server → fleet control-plane header carrying the browser's opaque affinity ticket on
|
|
398
|
+
* `/materialize` and `/query` (FOLLOWER-AFFINITY-DESIGN.md §5). Inlined (not imported from
|
|
399
|
+
* `@rindle/affinity`'s `HEADER_NAME`) to keep this client free of that crate's `node:crypto`
|
|
400
|
+
* dependency — an api-server may run on a Worker. Keep the two spellings in lock-step. */
|
|
401
|
+
const AFFINITY_HEADER = "Rindle-Affinity";
|
|
402
|
+
|
|
368
403
|
const defaultPaths: HttpRindleDaemonClientPaths = {
|
|
369
404
|
materialize: "/materialize",
|
|
370
405
|
dematerialize: "/dematerialize",
|
|
@@ -377,6 +412,7 @@ const defaultPaths: HttpRindleDaemonClientPaths = {
|
|
|
377
412
|
schema: "/schema",
|
|
378
413
|
claimRoomEpoch: "/claim-room-epoch",
|
|
379
414
|
roomLmids: "/room-lmids",
|
|
415
|
+
coverQuery: "/cover-check",
|
|
380
416
|
mutateSessionBegin: "/mutate-session/begin",
|
|
381
417
|
mutateSessionExec: "/mutate-session/exec",
|
|
382
418
|
mutateSessionQuery: "/mutate-session/query",
|
|
@@ -415,7 +451,11 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
415
451
|
}
|
|
416
452
|
|
|
417
453
|
materialize(input: MaterializeInput): Promise<MaterializeOutput> {
|
|
418
|
-
|
|
454
|
+
// The affinity ticket rides the `Rindle-Affinity` HEADER, not the body (the fleet edge reads it
|
|
455
|
+
// pre-dispatch to `fly-replay` this POST to the pinned follower). Strip it from the body so the
|
|
456
|
+
// daemon's `MaterializeInput` deserialization never sees an unknown field.
|
|
457
|
+
const { affinity, ...body } = input;
|
|
458
|
+
return this.post(this.paths.materialize, body, affinity);
|
|
419
459
|
}
|
|
420
460
|
|
|
421
461
|
dematerialize(input: DematerializeInput): Promise<DematerializeOutput> {
|
|
@@ -445,6 +485,10 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
445
485
|
return this.post(this.paths.roomLmids, input);
|
|
446
486
|
}
|
|
447
487
|
|
|
488
|
+
coverQuery(input: CoverQueryInput): Promise<CoverQueryOutput> {
|
|
489
|
+
return this.post(this.paths.coverQuery, input);
|
|
490
|
+
}
|
|
491
|
+
|
|
448
492
|
rejectMutation(input: MutationRejection): Promise<MutationRejectionOutput> {
|
|
449
493
|
return this.post(this.paths.rejectMutation, input);
|
|
450
494
|
}
|
|
@@ -470,7 +514,8 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
470
514
|
}
|
|
471
515
|
|
|
472
516
|
query(input: QueryOnceInput): Promise<QueryOnceOutput> {
|
|
473
|
-
|
|
517
|
+
const { affinity, ...body } = input;
|
|
518
|
+
return this.post(this.paths.query, body, affinity);
|
|
474
519
|
}
|
|
475
520
|
|
|
476
521
|
migrate(input: MigrateInput): Promise<MigrateOutput> {
|
|
@@ -493,8 +538,12 @@ export class HttpRindleDaemonClient implements RindleDaemonClient {
|
|
|
493
538
|
return this.get(this.paths.schema);
|
|
494
539
|
}
|
|
495
540
|
|
|
496
|
-
private async post<T>(path: string, input: unknown): Promise<T> {
|
|
541
|
+
private async post<T>(path: string, input: unknown, affinity?: string): Promise<T> {
|
|
497
542
|
const headers = await this.resolveHeaders();
|
|
543
|
+
// The api-server → fleet control-plane affinity ticket rides as a header on top of the usual
|
|
544
|
+
// bearer/content headers (FOLLOWER-AFFINITY-DESIGN.md §5); the fleet edge reads it to `fly-replay`
|
|
545
|
+
// to the pinned follower. Only `/materialize` + `/query` carry one.
|
|
546
|
+
if (affinity !== undefined) headers[AFFINITY_HEADER] = affinity;
|
|
498
547
|
const res = await this.fetchImpl(urlJoin(this.baseUrl, path), {
|
|
499
548
|
method: "POST",
|
|
500
549
|
headers: { "content-type": "application/json", ...headers },
|