foldkit-remote 0.14.1 → 0.16.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.
- package/README.md +30 -1
- package/dist/{index-CXAGo7Dz.d.mts → index-eVkkbhPA.d.mts} +1624 -1610
- package/dist/index-eVkkbhPA.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -2
- package/dist/port.d.mts +2 -2
- package/dist/port.d.mts.map +1 -1
- package/dist/port.mjs +1 -1
- package/dist/{src-CcPPtNuH.mjs → src-oVKXbiTu.mjs} +84 -49
- package/dist/src-oVKXbiTu.mjs.map +1 -0
- package/package.json +12 -11
- package/dist/index-CXAGo7Dz.d.mts.map +0 -1
- package/dist/src-CcPPtNuH.mjs.map +0 -1
|
@@ -7,57 +7,91 @@ import { EntryWithoutKeepAlive } from "foldkit/subscription";
|
|
|
7
7
|
import { ActiveSurface, Contract, Invalid, Metadata, ModelRef, Projection, Surface, SurfaceSource, Wiring } from "foldkit-surface";
|
|
8
8
|
import { Rpc, RpcClientError, RpcGroup } from "effect/rpc";
|
|
9
9
|
import * as Update from "foldkit/update";
|
|
10
|
-
//#region
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
readonly
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
10
|
+
//#region src/store.d.ts
|
|
11
|
+
type EntityKey = string;
|
|
12
|
+
interface EntityEntry {
|
|
13
|
+
readonly values: Readonly<Record<string, unknown>>;
|
|
14
|
+
readonly present: ReadonlySet<string>;
|
|
15
|
+
/** Present fields whose value may be outdated (revalidation needed). */
|
|
16
|
+
readonly stale: ReadonlySet<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Fields the server settled without a value: asked for, and answered without
|
|
19
|
+
* them, whatever the reason. Not planned again until a refresh asks; a later
|
|
20
|
+
* write of the field clears it.
|
|
21
|
+
*/
|
|
22
|
+
readonly unavailable: ReadonlySet<string>;
|
|
23
|
+
/** The entity is known to be absent; a later write clears this. */
|
|
24
|
+
readonly tombstone: boolean;
|
|
25
|
+
/** Injected clock reading of the last write; never read from ambient state. */
|
|
26
|
+
readonly updatedAt: number;
|
|
27
|
+
/**
|
|
28
|
+
* The canonical window each present field was fetched with (`""` for none).
|
|
29
|
+
* A later request with a *known, different* window is planned as missing.
|
|
30
|
+
*/
|
|
31
|
+
readonly windows: Readonly<Record<string, string>>;
|
|
32
|
+
}
|
|
33
|
+
type EntityStore = Readonly<Record<EntityKey, EntityEntry>>;
|
|
34
|
+
/** The separator keeps an untrusted id from colliding with a prototype key. */
|
|
35
|
+
declare const entityKey: (entity: string, id: string) => EntityKey;
|
|
36
|
+
declare const emptyStore: EntityStore;
|
|
37
|
+
interface EntityWrite {
|
|
38
|
+
readonly key: EntityKey;
|
|
39
|
+
readonly values: Readonly<Record<string, unknown>>;
|
|
40
|
+
/** The canonical window each written relation field was fetched with. */
|
|
41
|
+
readonly windows?: Readonly<Record<string, string>> | undefined;
|
|
42
|
+
/** When this write dates the entity, instead of the batch's `now`. */
|
|
43
|
+
readonly updatedAt?: number | undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Merges known values into many entities, copying the store once. Every
|
|
47
|
+
* written field becomes present and non-stale; a tombstone is cleared because
|
|
48
|
+
* the entity is evidently not absent.
|
|
49
|
+
*/
|
|
50
|
+
declare const writeEntities: (store: EntityStore, writes: ReadonlyArray<EntityWrite>, now?: number) => EntityStore;
|
|
51
|
+
/** `writeEntities` for one entity. */
|
|
52
|
+
declare const writeEntity: (store: EntityStore, key: EntityKey, values: Readonly<Record<string, unknown>>, now?: number, windows?: Readonly<Record<string, string>>) => EntityStore;
|
|
53
|
+
/**
|
|
54
|
+
* Marks present fields stale (`true`) or ends their staleness (`false`) across
|
|
55
|
+
* many entities, copying the store once. A field never present stays missing;
|
|
56
|
+
* an unknown entity is left alone.
|
|
57
|
+
*/
|
|
58
|
+
declare const setStale: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, stale: boolean) => EntityStore;
|
|
59
|
+
/** Marks present fields stale; fields that were never present stay missing. */
|
|
60
|
+
declare const markStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
|
|
61
|
+
/** Ends a refresh that did not land: the fields are present again as they were. */
|
|
62
|
+
declare const clearStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
|
|
63
|
+
/**
|
|
64
|
+
* Records fields the server settled without a value. A present field is left
|
|
65
|
+
* as it is: the answer that settled it was not about the value it holds.
|
|
66
|
+
* `false` forgets the marks, which is how a refresh asks again.
|
|
67
|
+
*/
|
|
68
|
+
declare const setUnavailable: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, unavailable: boolean) => EntityStore;
|
|
69
|
+
/** Whether the server settled this field without a value, and nothing has written it since. */
|
|
70
|
+
declare const isFieldUnavailable: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
71
|
+
/** Records that the entity is known to be absent, so it is not refetched. */
|
|
72
|
+
declare const tombstone: (store: EntityStore, key: EntityKey) => EntityStore;
|
|
73
|
+
/** Forgets everything known about the entity, including a tombstone. */
|
|
74
|
+
declare const remove: (store: EntityStore, key: EntityKey) => EntityStore;
|
|
75
|
+
declare const entry: (store: EntityStore, key: EntityKey) => Option.Option<EntityEntry>;
|
|
76
|
+
declare const isTombstone: (store: EntityStore, key: EntityKey) => boolean;
|
|
77
|
+
/** A field is known only if it is present and not stale. */
|
|
78
|
+
declare const hasField: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
79
|
+
/** A present field whose value may be outdated; absent fields are not stale. */
|
|
80
|
+
declare const isFieldStale: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Reads a present field, stale or not. Absence and a tombstone both yield
|
|
83
|
+
* `Option.none()`; a present `undefined`/`null` yields `Option.some`.
|
|
84
|
+
*/
|
|
85
|
+
declare const readField: (store: EntityStore, key: EntityKey, field: string) => Option.Option<unknown>;
|
|
86
|
+
/**
|
|
87
|
+
* The fields the planner must fetch. A tombstone makes every field known
|
|
88
|
+
* (absent), so it returns an empty list and the entity is not refetched, and a
|
|
89
|
+
* field the server settled without a value is known the same way. A
|
|
90
|
+
* requested window that differs from the one a field was fetched with also
|
|
91
|
+
* marks it missing, but only when the stored window is known (never `""`), so a
|
|
92
|
+
* writer that does not record windows cannot cause a refetch loop.
|
|
93
|
+
*/
|
|
94
|
+
declare const missingFields: (store: EntityStore, key: EntityKey, fields: Iterable<string>, windows?: Readonly<Record<string, string>>) => ReadonlyArray<string>;
|
|
61
95
|
//#endregion
|
|
62
96
|
//#region src/connection.d.ts
|
|
63
97
|
interface EdgeRef {
|
|
@@ -208,92 +242,6 @@ declare const RemoteData: {
|
|
|
208
242
|
map: <A, B>(data: RemoteData<A>, f: (value: A) => B) => RemoteData<B>;
|
|
209
243
|
};
|
|
210
244
|
//#endregion
|
|
211
|
-
//#region src/store.d.ts
|
|
212
|
-
type EntityKey = string;
|
|
213
|
-
interface EntityEntry {
|
|
214
|
-
readonly values: Readonly<Record<string, unknown>>;
|
|
215
|
-
readonly present: ReadonlySet<string>;
|
|
216
|
-
/** Present fields whose value may be outdated (revalidation needed). */
|
|
217
|
-
readonly stale: ReadonlySet<string>;
|
|
218
|
-
/**
|
|
219
|
-
* Fields the server settled without a value: asked for, and answered without
|
|
220
|
-
* them, whatever the reason. Not planned again until a refresh asks; a later
|
|
221
|
-
* write of the field clears it.
|
|
222
|
-
*/
|
|
223
|
-
readonly unavailable: ReadonlySet<string>;
|
|
224
|
-
/** The entity is known to be absent; a later write clears this. */
|
|
225
|
-
readonly tombstone: boolean;
|
|
226
|
-
/** Injected clock reading of the last write; never read from ambient state. */
|
|
227
|
-
readonly updatedAt: number;
|
|
228
|
-
/**
|
|
229
|
-
* The canonical window each present field was fetched with (`""` for none).
|
|
230
|
-
* A later request with a *known, different* window is planned as missing.
|
|
231
|
-
*/
|
|
232
|
-
readonly windows: Readonly<Record<string, string>>;
|
|
233
|
-
}
|
|
234
|
-
type EntityStore = Readonly<Record<EntityKey, EntityEntry>>;
|
|
235
|
-
/** The separator keeps an untrusted id from colliding with a prototype key. */
|
|
236
|
-
declare const entityKey: (entity: string, id: string) => EntityKey;
|
|
237
|
-
declare const emptyStore: EntityStore;
|
|
238
|
-
interface EntityWrite {
|
|
239
|
-
readonly key: EntityKey;
|
|
240
|
-
readonly values: Readonly<Record<string, unknown>>;
|
|
241
|
-
/** The canonical window each written relation field was fetched with. */
|
|
242
|
-
readonly windows?: Readonly<Record<string, string>> | undefined;
|
|
243
|
-
/** When this write dates the entity, instead of the batch's `now`. */
|
|
244
|
-
readonly updatedAt?: number | undefined;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Merges known values into many entities, copying the store once. Every
|
|
248
|
-
* written field becomes present and non-stale; a tombstone is cleared because
|
|
249
|
-
* the entity is evidently not absent.
|
|
250
|
-
*/
|
|
251
|
-
declare const writeEntities: (store: EntityStore, writes: ReadonlyArray<EntityWrite>, now?: number) => EntityStore;
|
|
252
|
-
/** `writeEntities` for one entity. */
|
|
253
|
-
declare const writeEntity: (store: EntityStore, key: EntityKey, values: Readonly<Record<string, unknown>>, now?: number, windows?: Readonly<Record<string, string>>) => EntityStore;
|
|
254
|
-
/**
|
|
255
|
-
* Marks present fields stale (`true`) or ends their staleness (`false`) across
|
|
256
|
-
* many entities, copying the store once. A field never present stays missing;
|
|
257
|
-
* an unknown entity is left alone.
|
|
258
|
-
*/
|
|
259
|
-
declare const setStale: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, stale: boolean) => EntityStore;
|
|
260
|
-
/** Marks present fields stale; fields that were never present stay missing. */
|
|
261
|
-
declare const markStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
|
|
262
|
-
/** Ends a refresh that did not land: the fields are present again as they were. */
|
|
263
|
-
declare const clearStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
|
|
264
|
-
/**
|
|
265
|
-
* Records fields the server settled without a value. A present field is left
|
|
266
|
-
* as it is: the answer that settled it was not about the value it holds.
|
|
267
|
-
* `false` forgets the marks, which is how a refresh asks again.
|
|
268
|
-
*/
|
|
269
|
-
declare const setUnavailable: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, unavailable: boolean) => EntityStore;
|
|
270
|
-
/** Whether the server settled this field without a value, and nothing has written it since. */
|
|
271
|
-
declare const isFieldUnavailable: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
272
|
-
/** Records that the entity is known to be absent, so it is not refetched. */
|
|
273
|
-
declare const tombstone: (store: EntityStore, key: EntityKey) => EntityStore;
|
|
274
|
-
/** Forgets everything known about the entity, including a tombstone. */
|
|
275
|
-
declare const remove: (store: EntityStore, key: EntityKey) => EntityStore;
|
|
276
|
-
declare const entry: (store: EntityStore, key: EntityKey) => Option.Option<EntityEntry>;
|
|
277
|
-
declare const isTombstone: (store: EntityStore, key: EntityKey) => boolean;
|
|
278
|
-
/** A field is known only if it is present and not stale. */
|
|
279
|
-
declare const hasField: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
280
|
-
/** A present field whose value may be outdated; absent fields are not stale. */
|
|
281
|
-
declare const isFieldStale: (store: EntityStore, key: EntityKey, field: string) => boolean;
|
|
282
|
-
/**
|
|
283
|
-
* Reads a present field, stale or not. Absence and a tombstone both yield
|
|
284
|
-
* `Option.none()`; a present `undefined`/`null` yields `Option.some`.
|
|
285
|
-
*/
|
|
286
|
-
declare const readField: (store: EntityStore, key: EntityKey, field: string) => Option.Option<unknown>;
|
|
287
|
-
/**
|
|
288
|
-
* The fields the planner must fetch. A tombstone makes every field known
|
|
289
|
-
* (absent), so it returns an empty list and the entity is not refetched, and a
|
|
290
|
-
* field the server settled without a value is known the same way. A
|
|
291
|
-
* requested window that differs from the one a field was fetched with also
|
|
292
|
-
* marks it missing, but only when the stored window is known (never `""`), so a
|
|
293
|
-
* writer that does not record windows cannot cause a refetch loop.
|
|
294
|
-
*/
|
|
295
|
-
declare const missingFields: (store: EntityStore, key: EntityKey, fields: Iterable<string>, windows?: Readonly<Record<string, string>>) => ReadonlyArray<string>;
|
|
296
|
-
//#endregion
|
|
297
245
|
//#region src/mutation.d.ts
|
|
298
246
|
interface NormalizedPatch {
|
|
299
247
|
readonly entity: string;
|
|
@@ -429,59 +377,171 @@ declare const Mutation: {
|
|
|
429
377
|
}) => MutationDescriptor<Name, TypeOf<Input>, TypeOf<Output>, Refused>;
|
|
430
378
|
};
|
|
431
379
|
//#endregion
|
|
432
|
-
//#region src/
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
readonly
|
|
436
|
-
readonly append?: LiveInsertion;
|
|
437
|
-
}
|
|
438
|
-
interface ConnectionSpec<Entity extends string = string> {
|
|
439
|
-
readonly entity: Entity;
|
|
440
|
-
readonly edgeKey?: Schema.Schema<unknown>;
|
|
441
|
-
readonly live?: LivePolicy;
|
|
442
|
-
}
|
|
443
|
-
interface QueryWindow {
|
|
444
|
-
readonly first?: number | undefined;
|
|
445
|
-
readonly last?: number | undefined;
|
|
446
|
-
readonly after?: Cursor | undefined;
|
|
447
|
-
readonly before?: Cursor | undefined;
|
|
448
|
-
}
|
|
449
|
-
interface QueryRef<Name extends string, Input> {
|
|
450
|
-
readonly query: Name;
|
|
451
|
-
readonly input: Input;
|
|
452
|
-
/** The input codec, so a `QueryRef` can encode itself without its descriptor. */
|
|
453
|
-
readonly Input: Schema.Codec<Input>;
|
|
454
|
-
readonly window: QueryWindow;
|
|
455
|
-
/** Connection identity: descriptor + canonical input, excluding the window. */
|
|
456
|
-
readonly identity: string;
|
|
457
|
-
}
|
|
458
|
-
interface QueryDescriptor<Name extends string, Input, Result> {
|
|
459
|
-
readonly name: Name;
|
|
460
|
-
readonly Input: Schema.Codec<Input>;
|
|
461
|
-
readonly Result: Result;
|
|
462
|
-
readonly ref: (input: Input) => QueryRef<Name, Input>;
|
|
463
|
-
/**
|
|
464
|
-
* What the query means, when it was declared with `Query.define`: the rows it
|
|
465
|
-
* is about, as a value an interpreter can compile. A descriptor from
|
|
466
|
-
* `Query.make` has none — its meaning lives in whatever the server registered
|
|
467
|
-
* to answer it — and a source is free to answer either.
|
|
468
|
-
*/
|
|
469
|
-
readonly body?: AnyQuery | undefined;
|
|
380
|
+
//#region src/optimistic.d.ts
|
|
381
|
+
interface EntityLayer {
|
|
382
|
+
readonly id: string;
|
|
383
|
+
readonly patches: ReadonlyArray<NormalizedPatch>;
|
|
470
384
|
}
|
|
471
385
|
/**
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
386
|
+
* Edges placed outside a connection's server-known region (`prepend`,
|
|
387
|
+
* `append`) or hidden from it (`remove`), owned by the request or live event
|
|
388
|
+
* that produced them.
|
|
475
389
|
*/
|
|
476
|
-
|
|
390
|
+
interface ConnectionOverlay {
|
|
391
|
+
readonly id: string;
|
|
392
|
+
readonly connection: string;
|
|
393
|
+
readonly edges: ReadonlyArray<Edge>;
|
|
394
|
+
readonly position: 'prepend' | 'append' | 'remove';
|
|
395
|
+
}
|
|
396
|
+
/** A connection change a request makes optimistically or a mutation result confirms. */
|
|
397
|
+
type ConnectionChange = {
|
|
398
|
+
readonly _tag: 'Insert';
|
|
399
|
+
readonly connection: string;
|
|
400
|
+
readonly position: 'prepend' | 'append';
|
|
401
|
+
readonly edge: Edge;
|
|
402
|
+
} | {
|
|
403
|
+
readonly _tag: 'Remove';
|
|
404
|
+
readonly connection: string;
|
|
405
|
+
readonly edge: Edge;
|
|
406
|
+
};
|
|
407
|
+
/** What a request changes before the server answers: entity patches and connection changes. */
|
|
408
|
+
type OptimisticOperation = NormalizedPatch | ConnectionChange;
|
|
409
|
+
/** A connection, by identity string or by anything that carries one (a `QueryRef`). */
|
|
410
|
+
type ConnectionIdentity = string | {
|
|
411
|
+
readonly identity: string;
|
|
412
|
+
};
|
|
413
|
+
declare const connectionIdentity: (connection: ConnectionIdentity) => string;
|
|
477
414
|
/**
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
415
|
+
* Constructors for connection changes: what a request shows optimistically
|
|
416
|
+
* (`MutateOptions.optimistic`) and what a mutation source reports it made
|
|
417
|
+
* (`MutationOutcome.connections`).
|
|
418
|
+
*/
|
|
419
|
+
declare const ConnectionChange: {
|
|
420
|
+
/** Show `ref` at the front of the connection until the request settles. */
|
|
421
|
+
prepend: (connection: ConnectionIdentity, ref: {
|
|
422
|
+
readonly entity: string;
|
|
423
|
+
readonly id: string;
|
|
424
|
+
}) => ConnectionChange;
|
|
425
|
+
/** Show `ref` at the end of the connection until the request settles. */
|
|
426
|
+
append: (connection: ConnectionIdentity, ref: {
|
|
427
|
+
readonly entity: string;
|
|
428
|
+
readonly id: string;
|
|
429
|
+
}) => ConnectionChange;
|
|
430
|
+
/** Hide `ref` from the connection until the request settles. */
|
|
431
|
+
remove: (connection: ConnectionIdentity, ref: {
|
|
432
|
+
readonly entity: string;
|
|
433
|
+
readonly id: string;
|
|
434
|
+
}) => ConnectionChange;
|
|
435
|
+
};
|
|
436
|
+
/**
|
|
437
|
+
* Applies a request's operations: its patches become one layer and its
|
|
438
|
+
* connection changes become overlays, all owned by `requestId` so settling
|
|
439
|
+
* removes every one of them together.
|
|
440
|
+
*/
|
|
441
|
+
declare const beginOptimistic: (optimistic: OptimisticState, requestId: string, operations: ReadonlyArray<OptimisticOperation>) => OptimisticState;
|
|
442
|
+
/** Pending entity layers and connection overlays over the base store. */
|
|
443
|
+
interface OptimisticState {
|
|
444
|
+
readonly layers: ReadonlyArray<EntityLayer>;
|
|
445
|
+
readonly overlays: ReadonlyArray<ConnectionOverlay>;
|
|
446
|
+
}
|
|
447
|
+
declare const emptyOptimistic: OptimisticState;
|
|
448
|
+
declare const addLayer: (optimistic: OptimisticState, layer: EntityLayer) => OptimisticState;
|
|
449
|
+
declare const removeLayer: (optimistic: OptimisticState, id: string) => OptimisticState;
|
|
450
|
+
declare const addOverlay: (optimistic: OptimisticState, overlay: ConnectionOverlay) => OptimisticState;
|
|
451
|
+
declare const removeOverlay: (optimistic: OptimisticState, id: string) => OptimisticState;
|
|
452
|
+
/**
|
|
453
|
+
* Base store with every layer applied in order. Later layers win. A patch is
|
|
454
|
+
* not news from the server, so it keeps the date of the value under it; an
|
|
455
|
+
* entity only a request holds (a temporary id) is not the server's to age, and
|
|
456
|
+
* is dated `Infinity`, so freshness never plans or times it.
|
|
457
|
+
*/
|
|
458
|
+
declare const visibleStore: (base: EntityStore, optimistic: OptimisticState) => EntityStore;
|
|
459
|
+
/**
|
|
460
|
+
* A fresh page is newer than any settled overlay it covers: an edge the page
|
|
461
|
+
* carries no longer needs an insert overlay, and a `remove` overlay hiding it
|
|
462
|
+
* is stale (the server says it is back). A pending request's overlays are
|
|
463
|
+
* left alone; they settle with the request.
|
|
464
|
+
*/
|
|
465
|
+
declare const pruneOverlays: (optimistic: OptimisticState, connection: string, covered: ReadonlySet<string>, pending: ReadonlySet<string>) => OptimisticState;
|
|
466
|
+
/**
|
|
467
|
+
* Applies a result idempotently and releases the request's layer and overlays:
|
|
468
|
+
* a later layer re-wins on rebase. Confirmed connection changes are recorded
|
|
469
|
+
* once per request, as overlays the request no longer owns.
|
|
470
|
+
*/
|
|
471
|
+
declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, answer: MutationAnswer & {
|
|
472
|
+
/** Connection changes the server confirmed; they replace the request's own. */
|
|
473
|
+
readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
|
|
474
|
+
}) => {
|
|
475
|
+
readonly store: EntityStore;
|
|
476
|
+
readonly state: MutationState;
|
|
477
|
+
readonly optimistic: OptimisticState;
|
|
478
|
+
};
|
|
479
|
+
/** A failed request's layer and overlays are dropped; the base was never mutated. */
|
|
480
|
+
declare const settleFailure: (optimistic: OptimisticState, requestId: string) => OptimisticState;
|
|
481
|
+
/**
|
|
482
|
+
* Visible edges for one connection: applicable overlays are placed outside the
|
|
483
|
+
* server-known segments and de-duplicated by edge identity (across overlays too),
|
|
484
|
+
* so a pending insert never corrupts server-known ordering; a `remove` overlay
|
|
485
|
+
* hides its edges wherever they are, and so does a tombstone on the edge's
|
|
486
|
+
* target when `store` is given. A later prepend lands before an earlier one, a
|
|
487
|
+
* later append after, so pending inserts read in the order they were made.
|
|
488
|
+
* Boundaries still come from the connection's segments.
|
|
489
|
+
*/
|
|
490
|
+
declare const visibleItems: (connection: Connection, connectionId: string, overlays: ReadonlyArray<ConnectionOverlay>, store?: EntityStore) => ReadonlyArray<Edge>;
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region src/query.d.ts
|
|
493
|
+
type LiveInsertion = 'visible' | 'boundary' | 'invalidate' | 'ignore';
|
|
494
|
+
interface LivePolicy {
|
|
495
|
+
readonly prepend?: LiveInsertion;
|
|
496
|
+
readonly append?: LiveInsertion;
|
|
497
|
+
}
|
|
498
|
+
interface ConnectionSpec<Entity extends string = string> {
|
|
499
|
+
readonly entity: Entity;
|
|
500
|
+
readonly edgeKey?: Schema.Schema<unknown>;
|
|
501
|
+
readonly live?: LivePolicy;
|
|
502
|
+
}
|
|
503
|
+
interface QueryWindow {
|
|
504
|
+
readonly first?: number | undefined;
|
|
505
|
+
readonly last?: number | undefined;
|
|
506
|
+
readonly after?: Cursor | undefined;
|
|
507
|
+
readonly before?: Cursor | undefined;
|
|
508
|
+
}
|
|
509
|
+
interface QueryRef<Name extends string, Input> {
|
|
510
|
+
readonly query: Name;
|
|
511
|
+
readonly input: Input;
|
|
512
|
+
/** The input codec, so a `QueryRef` can encode itself without its descriptor. */
|
|
513
|
+
readonly Input: Schema.Codec<Input>;
|
|
514
|
+
readonly window: QueryWindow;
|
|
515
|
+
/** Connection identity: descriptor + canonical input, excluding the window. */
|
|
516
|
+
readonly identity: string;
|
|
517
|
+
}
|
|
518
|
+
interface QueryDescriptor<Name extends string, Input, Result> {
|
|
519
|
+
readonly name: Name;
|
|
520
|
+
readonly Input: Schema.Codec<Input>;
|
|
521
|
+
readonly Result: Result;
|
|
522
|
+
readonly ref: (input: Input) => QueryRef<Name, Input>;
|
|
523
|
+
/**
|
|
524
|
+
* What the query means, when it was declared with `Query.define`: the rows it
|
|
525
|
+
* is about, as a value an interpreter can compile. A descriptor from
|
|
526
|
+
* `Query.make` has none — its meaning lives in whatever the server registered
|
|
527
|
+
* to answer it — and a source is free to answer either.
|
|
528
|
+
*/
|
|
529
|
+
readonly body?: AnyQuery | undefined;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* The inputs of a definition's body: one placeholder per key of `Input`, typed
|
|
533
|
+
* as that key's value. A body is built once, so these stand for what the query
|
|
534
|
+
* will be given rather than being it.
|
|
535
|
+
*/
|
|
536
|
+
type QueryInputs<Input> = { readonly [K in keyof Input & string]: InputExpr<Input[K]>; };
|
|
537
|
+
/**
|
|
538
|
+
* What separates a query's name from its canonical encoded input in a
|
|
539
|
+
* connection identity.
|
|
540
|
+
*
|
|
541
|
+
* NUL, because `JSON.stringify` escapes it inside a string (`\u0000`) and a
|
|
542
|
+
* query name is a TypeScript identifier — so the first occurrence is always the
|
|
543
|
+
* boundary, and a name or an input value cannot forge one. Anything recovering
|
|
544
|
+
* the query from an identity splits here.
|
|
485
545
|
*/
|
|
486
546
|
declare const IDENTITY_SEPARATOR = "\0";
|
|
487
547
|
/** Stable stringify: object keys sorted, undefined-valued keys dropped, so equal inputs encode equally. */
|
|
@@ -497,6 +557,14 @@ type ResultOf<Result> = Result extends {
|
|
|
497
557
|
/** A relational `Query` over one Entity, as `Query.define`'s body returns. */
|
|
498
558
|
type RelationalQueryOf<E extends AnyEntity> = ReturnType<typeof Query.from<E>>;
|
|
499
559
|
declare const Query$1: {
|
|
560
|
+
from: <E extends AnyEntity>(entity: E) => Query<E>;
|
|
561
|
+
where: (...predicates: ReadonlyArray<import("foldkit-entity").Predicate>) => <E extends AnyEntity>(self: Query<E>) => Query<E>;
|
|
562
|
+
orderBy: (...terms: ReadonlyArray<import("foldkit-entity").Ordering>) => <E extends AnyEntity>(self: Query<E>) => Query<E>;
|
|
563
|
+
orderFor: (self: AnyQuery, input: Readonly<Record<string, unknown>>) => ReadonlyArray<import("foldkit-entity").OrderTerm>;
|
|
564
|
+
placement: (self: AnyQuery, input: Readonly<Record<string, unknown>>) => import("foldkit-entity").Placement;
|
|
565
|
+
dependencies: (self: AnyQuery) => import("foldkit-entity").QueryDependencies;
|
|
566
|
+
unsupported: (self: AnyQuery, supported: ReadonlyArray<import("foldkit-entity").Operation>) => ReadonlyArray<import("foldkit-entity").Operation>;
|
|
567
|
+
show: (self: AnyQuery) => string;
|
|
500
568
|
/** Declares the entity and options a query's result is a connection over. */
|
|
501
569
|
connection: <Entity extends string>(entity: {
|
|
502
570
|
readonly name: Entity;
|
|
@@ -542,19 +610,11 @@ declare const Query$1: {
|
|
|
542
610
|
}) => RelationalQueryOf<E>, options?: {
|
|
543
611
|
readonly edgeKey?: Schema.Schema<unknown>;
|
|
544
612
|
readonly live?: LivePolicy;
|
|
545
|
-
}) => QueryDescriptor<Name, TypeOf<Input>, ConnectionSpec<E[
|
|
613
|
+
}) => QueryDescriptor<Name, TypeOf<Input>, ConnectionSpec<E['name']>>;
|
|
546
614
|
first: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
|
|
547
615
|
last: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
|
|
548
616
|
after: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
|
|
549
617
|
before: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
|
|
550
|
-
from: <E extends AnyEntity>(entity: E) => Query<E>;
|
|
551
|
-
where: (...predicates: ReadonlyArray<import("foldkit-entity").Predicate>) => <E extends AnyEntity>(self: Query<E>) => Query<E>;
|
|
552
|
-
orderBy: (...terms: ReadonlyArray<import("foldkit-entity").Ordering>) => <E extends AnyEntity>(self: Query<E>) => Query<E>;
|
|
553
|
-
orderFor: (self: AnyQuery, input: Readonly<Record<string, unknown>>) => ReadonlyArray<import("foldkit-entity").OrderTerm>;
|
|
554
|
-
placement: (self: AnyQuery, input: Readonly<Record<string, unknown>>) => import("foldkit-entity").Placement;
|
|
555
|
-
dependencies: (self: AnyQuery) => import("foldkit-entity").QueryDependencies;
|
|
556
|
-
unsupported: (self: AnyQuery, supported: ReadonlyArray<import("foldkit-entity").Operation>) => ReadonlyArray<import("foldkit-entity").Operation>;
|
|
557
|
-
show: (self: AnyQuery) => string;
|
|
558
618
|
};
|
|
559
619
|
//#endregion
|
|
560
620
|
//#region src/requirement.d.ts
|
|
@@ -604,9 +664,9 @@ declare const Requirement: {
|
|
|
604
664
|
mergeConnections: typeof mergeConnections;
|
|
605
665
|
};
|
|
606
666
|
/** Remote's entity requirements on a Projection, unioned per entity and id as nodes compose. */
|
|
607
|
-
declare const RemoteRequirements: MetadataKey<Requirement>;
|
|
667
|
+
declare const RemoteRequirements: import("foldkit-metadata").MetadataKey<Requirement>;
|
|
608
668
|
/** Remote's query connections on a Projection, unioned per connection and window. */
|
|
609
|
-
declare const RemoteConnections: MetadataKey<ConnectionRequirement>;
|
|
669
|
+
declare const RemoteConnections: import("foldkit-metadata").MetadataKey<ConnectionRequirement>;
|
|
610
670
|
/** The entity requirements a Projection carries. */
|
|
611
671
|
declare const requirementsOf: (projection: {
|
|
612
672
|
readonly metadata: Metadata;
|
|
@@ -616,372 +676,67 @@ declare const connectionsOf: (projection: {
|
|
|
616
676
|
readonly metadata: Metadata;
|
|
617
677
|
}) => ReadonlyArray<ConnectionRequirement>;
|
|
618
678
|
//#endregion
|
|
619
|
-
//#region src/
|
|
620
|
-
interface EntityLayer {
|
|
621
|
-
readonly id: string;
|
|
622
|
-
readonly patches: ReadonlyArray<NormalizedPatch>;
|
|
623
|
-
}
|
|
679
|
+
//#region src/wire.d.ts
|
|
624
680
|
/**
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
681
|
+
* The read/live protocol version. A batch names the version it speaks and the
|
|
682
|
+
* server refuses a mismatch with `RemoteProtocolError`, so a shape change never
|
|
683
|
+
* drifts silently: bump it whenever `ReadRequest` or `LiveRequirement` change.
|
|
628
684
|
*/
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
readonly
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
readonly
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
readonly
|
|
643
|
-
|
|
644
|
-
readonly edge: Edge;
|
|
645
|
-
};
|
|
646
|
-
/** What a request changes before the server answers: entity patches and connection changes. */
|
|
647
|
-
type OptimisticOperation = NormalizedPatch | ConnectionChange;
|
|
648
|
-
/** A connection, by identity string or by anything that carries one (a `QueryRef`). */
|
|
649
|
-
type ConnectionIdentity = string | {
|
|
650
|
-
readonly identity: string;
|
|
651
|
-
};
|
|
652
|
-
declare const connectionIdentity: (connection: ConnectionIdentity) => string;
|
|
685
|
+
declare const REMOTE_PROTOCOL_VERSION = 4;
|
|
686
|
+
declare const RemoteReadError_base: Schema.Class<RemoteReadError, Schema.TaggedStruct<"RemoteReadError", {
|
|
687
|
+
readonly message: Schema.String;
|
|
688
|
+
}>, import("effect/Cause").YieldableError>;
|
|
689
|
+
declare class RemoteReadError extends RemoteReadError_base {}
|
|
690
|
+
declare const RemoteMutationError_base: Schema.Class<RemoteMutationError, Schema.TaggedStruct<"RemoteMutationError", {
|
|
691
|
+
readonly message: Schema.String;
|
|
692
|
+
/** The mutation's own `Refusal`, encoded, when the server refused it as one. */
|
|
693
|
+
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
694
|
+
}>, import("effect/Cause").YieldableError>;
|
|
695
|
+
declare class RemoteMutationError extends RemoteMutationError_base {}
|
|
696
|
+
declare const RemoteForbidden_base: Schema.Class<RemoteForbidden, Schema.TaggedStruct<"Forbidden", {
|
|
697
|
+
readonly message: Schema.String;
|
|
698
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
699
|
+
}>, import("effect/Cause").YieldableError>;
|
|
653
700
|
/**
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
701
|
+
* The server refused who is asking: they may not do this, and asking again
|
|
702
|
+
* as the same principal is refused again. `reason` is the application's own
|
|
703
|
+
* words for the person who asked; without it the refusal says nothing of why.
|
|
657
704
|
*/
|
|
658
|
-
declare
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
declare const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
* not news from the server, so it keeps the date of the value under it; an
|
|
694
|
-
* entity only a request holds (a temporary id) is not the server's to age, and
|
|
695
|
-
* is dated `Infinity`, so freshness never plans or times it.
|
|
696
|
-
*/
|
|
697
|
-
declare const visibleStore: (base: EntityStore, optimistic: OptimisticState) => EntityStore;
|
|
698
|
-
/**
|
|
699
|
-
* A fresh page is newer than any settled overlay it covers: an edge the page
|
|
700
|
-
* carries no longer needs an insert overlay, and a `remove` overlay hiding it
|
|
701
|
-
* is stale (the server says it is back). A pending request's overlays are
|
|
702
|
-
* left alone; they settle with the request.
|
|
703
|
-
*/
|
|
704
|
-
declare const pruneOverlays: (optimistic: OptimisticState, connection: string, covered: ReadonlySet<string>, pending: ReadonlySet<string>) => OptimisticState;
|
|
705
|
-
/**
|
|
706
|
-
* Applies a result idempotently and releases the request's layer and overlays:
|
|
707
|
-
* a later layer re-wins on rebase. Confirmed connection changes are recorded
|
|
708
|
-
* once per request, as overlays the request no longer owns.
|
|
709
|
-
*/
|
|
710
|
-
declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, answer: MutationAnswer & {
|
|
711
|
-
/** Connection changes the server confirmed; they replace the request's own. */
|
|
712
|
-
readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
|
|
713
|
-
}) => {
|
|
714
|
-
readonly store: EntityStore;
|
|
715
|
-
readonly state: MutationState;
|
|
716
|
-
readonly optimistic: OptimisticState;
|
|
717
|
-
};
|
|
718
|
-
/** A failed request's layer and overlays are dropped; the base was never mutated. */
|
|
719
|
-
declare const settleFailure: (optimistic: OptimisticState, requestId: string) => OptimisticState;
|
|
720
|
-
/**
|
|
721
|
-
* Visible edges for one connection: applicable overlays are placed outside the
|
|
722
|
-
* server-known segments and de-duplicated by edge identity (across overlays too),
|
|
723
|
-
* so a pending insert never corrupts server-known ordering; a `remove` overlay
|
|
724
|
-
* hides its edges wherever they are, and so does a tombstone on the edge's
|
|
725
|
-
* target when `store` is given. A later prepend lands before an earlier one, a
|
|
726
|
-
* later append after, so pending inserts read in the order they were made.
|
|
727
|
-
* Boundaries still come from the connection's segments.
|
|
728
|
-
*/
|
|
729
|
-
declare const visibleItems: (connection: Connection, connectionId: string, overlays: ReadonlyArray<ConnectionOverlay>, store?: EntityStore) => ReadonlyArray<Edge>;
|
|
730
|
-
//#endregion
|
|
731
|
-
//#region src/live.d.ts
|
|
732
|
-
type LiveCursor = number;
|
|
733
|
-
type LiveEvent = {
|
|
734
|
-
readonly _tag: 'EntityPatched';
|
|
735
|
-
readonly ref: EdgeRef;
|
|
736
|
-
readonly values: Readonly<Record<string, unknown>>;
|
|
737
|
-
readonly changed: ReadonlyArray<string>;
|
|
738
|
-
readonly cursor: LiveCursor;
|
|
739
|
-
} | {
|
|
740
|
-
readonly _tag: 'EntityDeleted';
|
|
741
|
-
readonly ref: EdgeRef;
|
|
742
|
-
readonly cursor: LiveCursor;
|
|
743
|
-
} | {
|
|
744
|
-
readonly _tag: 'ConnectionInsert';
|
|
745
|
-
readonly connection: string;
|
|
746
|
-
readonly position: 'prepend' | 'append';
|
|
747
|
-
readonly edge: Edge;
|
|
748
|
-
readonly cursor: LiveCursor;
|
|
749
|
-
} | {
|
|
750
|
-
readonly _tag: 'ConnectionRemove';
|
|
751
|
-
readonly connection: string;
|
|
752
|
-
readonly edge: Edge;
|
|
753
|
-
readonly cursor: LiveCursor;
|
|
754
|
-
} | {
|
|
755
|
-
readonly _tag: 'ConnectionInvalidate';
|
|
756
|
-
readonly connection: string;
|
|
757
|
-
readonly cursor: LiveCursor;
|
|
758
|
-
};
|
|
759
|
-
interface BoundaryCounts {
|
|
760
|
-
readonly before: number;
|
|
761
|
-
readonly after: number;
|
|
762
|
-
}
|
|
763
|
-
interface LiveState {
|
|
764
|
-
/** Last applied cursor for this stream. */
|
|
765
|
-
readonly cursor: LiveCursor;
|
|
766
|
-
/** Edges recorded outside the loaded boundary, not visible in `items`. */
|
|
767
|
-
readonly boundary: Readonly<Record<string, BoundaryCounts>>;
|
|
768
|
-
}
|
|
769
|
-
declare const emptyLiveState: LiveState;
|
|
770
|
-
type LiveOutcome = 'applied' | 'duplicate' | 'gap';
|
|
771
|
-
/**
|
|
772
|
-
* Ordering per stream: at most the next cursor; ahead is a gap. Cursor `0` means
|
|
773
|
-
* "no baseline yet" (cursors are 1-based), so the first event of a stream is
|
|
774
|
-
* accepted whatever its cursor — otherwise a stream not starting at 1 would be a
|
|
775
|
-
* spurious gap.
|
|
776
|
-
*/
|
|
777
|
-
declare const classifyLive: (state: LiveState, cursor: LiveCursor) => LiveOutcome;
|
|
778
|
-
interface EntityApplied {
|
|
779
|
-
readonly state: LiveState;
|
|
780
|
-
readonly store: EntityStore;
|
|
781
|
-
readonly outcome: LiveOutcome;
|
|
782
|
-
}
|
|
783
|
-
declare const applyEntityEvent: (state: LiveState, store: EntityStore, event: Extract<LiveEvent, {
|
|
784
|
-
_tag: "EntityPatched" | "EntityDeleted";
|
|
785
|
-
}>, now?: number) => EntityApplied;
|
|
786
|
-
interface ConnectionApplied {
|
|
787
|
-
readonly state: LiveState;
|
|
788
|
-
readonly optimistic: OptimisticState;
|
|
789
|
-
readonly outcome: LiveOutcome;
|
|
790
|
-
/**
|
|
791
|
-
* A connection the event says to refetch. Reported rather than recorded here,
|
|
792
|
-
* because staleness lives on the connection in the Model — which is what the
|
|
793
|
-
* planner and every read consult. It used to be written into a set on this
|
|
794
|
-
* live state that nothing read, so an invalidating event did nothing at all.
|
|
795
|
-
*/
|
|
796
|
-
readonly invalidated?: string | undefined;
|
|
797
|
-
}
|
|
798
|
-
declare const applyConnectionEvent: (state: LiveState, optimistic: OptimisticState, event: Extract<LiveEvent, {
|
|
799
|
-
_tag: "ConnectionInsert" | "ConnectionRemove" | "ConnectionInvalidate";
|
|
800
|
-
}>, policy?: LivePolicy) => ConnectionApplied;
|
|
801
|
-
/** `hasPrevious` accounting for edges recorded outside the loaded boundary. */
|
|
802
|
-
declare const liveHasPrevious: (connection: Connection, state: LiveState, connectionId: string) => boolean;
|
|
803
|
-
/** `hasNext` accounting for edges recorded outside the loaded boundary. */
|
|
804
|
-
declare const liveHasNext: (connection: Connection, state: LiveState, connectionId: string) => boolean;
|
|
805
|
-
//#endregion
|
|
806
|
-
//#region src/retain.d.ts
|
|
807
|
-
/** A connection to keep: its identity, and what a page of it selects of each item, if a projection reads it. */
|
|
808
|
-
interface ConnectionRoot {
|
|
809
|
-
readonly identity: string;
|
|
810
|
-
readonly select?: RelationRequirement | undefined;
|
|
811
|
-
}
|
|
812
|
-
interface RetentionRoots {
|
|
813
|
-
readonly requirements: ReadonlyArray<Requirement>;
|
|
814
|
-
/** Connections (`QueryRef.identity`) to keep, with their edges' targets and what `select` reaches through them. */
|
|
815
|
-
readonly connections: ReadonlyArray<ConnectionRoot>;
|
|
816
|
-
}
|
|
817
|
-
interface Retained {
|
|
818
|
-
readonly entities: EntityStore;
|
|
819
|
-
readonly connections: Readonly<Record<string, Connection>>;
|
|
820
|
-
readonly optimistic: OptimisticState;
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* The entity keys the roots reach: each root entity, the targets its retained
|
|
824
|
-
* fields refer to, and recursively the targets a nested relation selects.
|
|
825
|
-
*/
|
|
826
|
-
declare const reachable: (store: EntityStore, roots: RetentionRoots, connections: Readonly<Record<string, Connection>>, optimistic: OptimisticState, pending: ReadonlySet<string>) => ReadonlySet<EntityKey>;
|
|
827
|
-
/**
|
|
828
|
-
* Drops every entity the roots do not reach, every connection they do not
|
|
829
|
-
* name, and every settled overlay on a dropped connection, keeping whatever a
|
|
830
|
-
* pending request's layer or overlays touch. Pure.
|
|
831
|
-
*/
|
|
832
|
-
declare const gc: (state: Retained & {
|
|
833
|
-
readonly mutations: MutationState;
|
|
834
|
-
}, roots: RetentionRoots) => Retained;
|
|
835
|
-
//#endregion
|
|
836
|
-
//#region src/persistence.d.ts
|
|
837
|
-
/** Bump when the serialized shape changes; a mismatch discards the cache. */
|
|
838
|
-
declare const REMOTE_CACHE_VERSION = 5;
|
|
839
|
-
/**
|
|
840
|
-
* What survives a reload: the entity cache, and the connections an application
|
|
841
|
-
* **declared** should come back.
|
|
842
|
-
*
|
|
843
|
-
* Connections are session state by default and stay that way — `snapshotOf`
|
|
844
|
-
* takes none unless asked. What a declared one keeps is its **edges and
|
|
845
|
-
* nothing else**, which is not a simplification but the rule: a connection's
|
|
846
|
-
* boundaries are cursors the server minted, and a cursor may name server state
|
|
847
|
-
* that no longer exists. Restoring one would be claiming to know where the
|
|
848
|
-
* page ends. The shape has nowhere to put a cursor, so that cannot be got
|
|
849
|
-
* wrong later.
|
|
850
|
-
*/
|
|
851
|
-
interface Snapshot {
|
|
852
|
-
readonly entities: EntityStore;
|
|
853
|
-
/**
|
|
854
|
-
* By connection identity: its **segments**, each a run of edges. No
|
|
855
|
-
* boundaries.
|
|
856
|
-
*
|
|
857
|
-
* Segments rather than one flat list, because the gaps between them are
|
|
858
|
-
* knowledge too. A connection paged from both ends holds a head and a tail
|
|
859
|
-
* with an unfetched middle; flattening those into one run would claim the
|
|
860
|
-
* tail's first row follows the head's last, which is a thing the client was
|
|
861
|
-
* never told.
|
|
862
|
-
*/
|
|
863
|
-
readonly connections: Readonly<Record<string, ReadonlyArray<ReadonlyArray<Edge>>>>;
|
|
864
|
-
}
|
|
865
|
-
interface SnapshotOptions {
|
|
866
|
-
/**
|
|
867
|
-
* Who or what the snapshot is for (a user id, a tenant, a build). A snapshot
|
|
868
|
-
* taken under another scope is discarded rather than shown to the wrong
|
|
869
|
-
* reader. Default: unscoped, which only matches unscoped.
|
|
870
|
-
*/
|
|
871
|
-
readonly scope?: string | undefined;
|
|
872
|
-
/** Snapshots larger than this many bytes are not written and not read. */
|
|
873
|
-
readonly maxBytes?: number | undefined;
|
|
874
|
-
}
|
|
875
|
-
/** How a snapshot meets a store that already has entries. */
|
|
876
|
-
type MergePolicy = 'replace' | 'preserve-existing';
|
|
877
|
-
/**
|
|
878
|
-
* The snapshot text, or `undefined` when it would exceed `maxBytes`. Build the
|
|
879
|
-
* snapshot with `snapshotOf`, which is where the connections that survive are
|
|
880
|
-
* named; runtime state — optimistic layers, live cursors, gaps, the mutation
|
|
881
|
-
* ledger — is never in one.
|
|
882
|
-
*/
|
|
883
|
-
declare function dehydrate(snapshot: Snapshot, options?: SnapshotOptions & {
|
|
884
|
-
readonly maxBytes?: undefined;
|
|
885
|
-
}): string;
|
|
886
|
-
declare function dehydrate(snapshot: Snapshot, options?: SnapshotOptions): string | undefined;
|
|
887
|
-
declare const RemotePersistence: {
|
|
888
|
-
/** The snapshot text, or `undefined` when it would exceed `maxBytes`. */
|
|
889
|
-
dehydrate: typeof dehydrate;
|
|
890
|
-
/** What a snapshot text holds, or `undefined` when it is refused. */
|
|
891
|
-
hydrate: (raw: string | undefined | null, options?: SnapshotOptions) => Snapshot | undefined;
|
|
892
|
-
/**
|
|
893
|
-
* What to keep of a Model, naming the connections that should survive a
|
|
894
|
-
* reload. Naming none is the default and is what Remote always did.
|
|
895
|
-
*/
|
|
896
|
-
snapshotOf: (model: {
|
|
897
|
-
readonly entities: EntityStore;
|
|
898
|
-
readonly connections: Readonly<Record<string, Connection>>;
|
|
899
|
-
}, options?: {
|
|
900
|
-
readonly connections?: ReadonlyArray<ConnectionIdentity> | undefined;
|
|
901
|
-
}) => Snapshot;
|
|
902
|
-
/** A snapshot's entities brought into a store by policy. */
|
|
903
|
-
mergeStores: (current: EntityStore, snapshot: EntityStore, policy: MergePolicy) => EntityStore;
|
|
904
|
-
/** The cache as a fresh session has it; what a refused `restore` yields. */
|
|
905
|
-
emptySnapshot: Snapshot;
|
|
906
|
-
/**
|
|
907
|
-
* Writes the snapshot under `key`, or removes the key when the store would
|
|
908
|
-
* exceed `maxBytes`, so a stale smaller snapshot cannot outlive a larger
|
|
909
|
-
* store it no longer describes.
|
|
910
|
-
*/
|
|
911
|
-
save: (snapshot: Snapshot, options: {
|
|
912
|
-
readonly key: string;
|
|
913
|
-
} & SnapshotOptions) => Effect.Effect<void, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
|
|
914
|
-
/**
|
|
915
|
-
* Reads the cache. A missing key yields `emptySnapshot`; anything `hydrate`
|
|
916
|
-
* refuses yields `emptySnapshot` and removes the key, so the next `restore`
|
|
917
|
-
* is clean and the planner refetches.
|
|
918
|
-
*/
|
|
919
|
-
restore: (options: {
|
|
920
|
-
readonly key: string;
|
|
921
|
-
} & SnapshotOptions) => Effect.Effect<Snapshot, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
|
|
922
|
-
};
|
|
923
|
-
//#endregion
|
|
924
|
-
//#region src/wire.d.ts
|
|
925
|
-
/**
|
|
926
|
-
* The read/live protocol version. A batch names the version it speaks and the
|
|
927
|
-
* server refuses a mismatch with `RemoteProtocolError`, so a shape change never
|
|
928
|
-
* drifts silently: bump it whenever `ReadRequest` or `LiveRequirement` change.
|
|
929
|
-
*/
|
|
930
|
-
declare const REMOTE_PROTOCOL_VERSION = 4;
|
|
931
|
-
declare const RemoteReadError_base: Schema.Class<RemoteReadError, Schema.TaggedStruct<"RemoteReadError", {
|
|
932
|
-
readonly message: Schema.String;
|
|
933
|
-
}>, import("effect/Cause").YieldableError>;
|
|
934
|
-
declare class RemoteReadError extends RemoteReadError_base {}
|
|
935
|
-
declare const RemoteMutationError_base: Schema.Class<RemoteMutationError, Schema.TaggedStruct<"RemoteMutationError", {
|
|
936
|
-
readonly message: Schema.String;
|
|
937
|
-
/** The mutation's own `Refusal`, encoded, when the server refused it as one. */
|
|
938
|
-
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
939
|
-
}>, import("effect/Cause").YieldableError>;
|
|
940
|
-
declare class RemoteMutationError extends RemoteMutationError_base {}
|
|
941
|
-
declare const RemoteForbidden_base: Schema.Class<RemoteForbidden, Schema.TaggedStruct<"Forbidden", {
|
|
942
|
-
readonly message: Schema.String;
|
|
943
|
-
readonly reason: Schema.optional<Schema.String>;
|
|
944
|
-
}>, import("effect/Cause").YieldableError>;
|
|
945
|
-
/**
|
|
946
|
-
* The server refused who is asking: they may not do this, and asking again
|
|
947
|
-
* as the same principal is refused again. `reason` is the application's own
|
|
948
|
-
* words for the person who asked; without it the refusal says nothing of why.
|
|
949
|
-
*/
|
|
950
|
-
declare class RemoteForbidden extends RemoteForbidden_base {}
|
|
951
|
-
declare const RemoteLiveError_base: Schema.Class<RemoteLiveError, Schema.TaggedStruct<"RemoteLiveError", {
|
|
952
|
-
readonly message: Schema.String;
|
|
953
|
-
}>, import("effect/Cause").YieldableError>;
|
|
954
|
-
declare class RemoteLiveError extends RemoteLiveError_base {}
|
|
955
|
-
declare const RemoteProtocolError_base: Schema.Class<RemoteProtocolError, Schema.TaggedStruct<"RemoteProtocolError", {
|
|
956
|
-
readonly message: Schema.String;
|
|
957
|
-
readonly expected: Schema.Number;
|
|
958
|
-
readonly received: Schema.Number;
|
|
959
|
-
}>, import("effect/Cause").YieldableError>;
|
|
960
|
-
/** The peer speaks another protocol version; nothing was read. */
|
|
961
|
-
declare class RemoteProtocolError extends RemoteProtocolError_base {}
|
|
962
|
-
/** A page size: a non-negative integer, refused at decode otherwise rather than defaulted. */
|
|
963
|
-
declare const PageSize: Schema.Number;
|
|
964
|
-
declare const WindowSchema: Schema.Struct<{
|
|
965
|
-
readonly first: Schema.optional<Schema.Number>;
|
|
966
|
-
readonly last: Schema.optional<Schema.Number>;
|
|
967
|
-
readonly after: Schema.optional<Schema.String>;
|
|
968
|
-
readonly before: Schema.optional<Schema.String>;
|
|
969
|
-
}>;
|
|
970
|
-
/** A request may not name more fields of one entity than this; a selection never does. */
|
|
971
|
-
declare const MAX_FIELDS_PER_REQUEST = 256;
|
|
972
|
-
/** A selection may not nest relations deeper than this; the wire refuses more. */
|
|
973
|
-
declare const MAX_RELATION_DEPTH = 8;
|
|
974
|
-
declare const RelationRequest: Schema.Codec<RelationRequirement, RelationRequirement, never, never>;
|
|
975
|
-
declare const ReadRequest: Schema.Codec<Requirement, Requirement>;
|
|
976
|
-
declare const ReadBatch: Schema.Struct<{
|
|
977
|
-
readonly version: Schema.Number;
|
|
978
|
-
readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
979
|
-
}>;
|
|
980
|
-
declare const NormalizedEntity: Schema.Struct<{
|
|
981
|
-
readonly entity: Schema.String;
|
|
982
|
-
readonly id: Schema.String;
|
|
983
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
984
|
-
}>;
|
|
705
|
+
declare class RemoteForbidden extends RemoteForbidden_base {}
|
|
706
|
+
declare const RemoteLiveError_base: Schema.Class<RemoteLiveError, Schema.TaggedStruct<"RemoteLiveError", {
|
|
707
|
+
readonly message: Schema.String;
|
|
708
|
+
}>, import("effect/Cause").YieldableError>;
|
|
709
|
+
declare class RemoteLiveError extends RemoteLiveError_base {}
|
|
710
|
+
declare const RemoteProtocolError_base: Schema.Class<RemoteProtocolError, Schema.TaggedStruct<"RemoteProtocolError", {
|
|
711
|
+
readonly message: Schema.String;
|
|
712
|
+
readonly expected: Schema.Number;
|
|
713
|
+
readonly received: Schema.Number;
|
|
714
|
+
}>, import("effect/Cause").YieldableError>;
|
|
715
|
+
/** The peer speaks another protocol version; nothing was read. */
|
|
716
|
+
declare class RemoteProtocolError extends RemoteProtocolError_base {}
|
|
717
|
+
/** A page size: a non-negative integer, refused at decode otherwise rather than defaulted. */
|
|
718
|
+
declare const PageSize: Schema.Number;
|
|
719
|
+
declare const WindowSchema: Schema.Struct<{
|
|
720
|
+
readonly first: Schema.optional<Schema.Number>;
|
|
721
|
+
readonly last: Schema.optional<Schema.Number>;
|
|
722
|
+
readonly after: Schema.optional<Schema.String>;
|
|
723
|
+
readonly before: Schema.optional<Schema.String>;
|
|
724
|
+
}>;
|
|
725
|
+
/** A request may not name more fields of one entity than this; a selection never does. */
|
|
726
|
+
declare const MAX_FIELDS_PER_REQUEST = 256;
|
|
727
|
+
/** A selection may not nest relations deeper than this; the wire refuses more. */
|
|
728
|
+
declare const MAX_RELATION_DEPTH = 8;
|
|
729
|
+
declare const RelationRequest: Schema.Codec<RelationRequirement, RelationRequirement, never, never>;
|
|
730
|
+
declare const ReadRequest: Schema.Codec<Requirement, Requirement>;
|
|
731
|
+
declare const ReadBatch: Schema.Struct<{
|
|
732
|
+
readonly version: Schema.Number;
|
|
733
|
+
readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
734
|
+
}>;
|
|
735
|
+
declare const NormalizedEntity: Schema.Struct<{
|
|
736
|
+
readonly entity: Schema.String;
|
|
737
|
+
readonly id: Schema.String;
|
|
738
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
739
|
+
}>;
|
|
985
740
|
/**
|
|
986
741
|
* Fields a read asked for that the server answered without, and will not
|
|
987
742
|
* answer with: the client stops asking. It says nothing about why, so a rule
|
|
@@ -1333,21 +1088,47 @@ declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
|
|
|
1333
1088
|
readonly fields: Schema.$Array<Schema.String>;
|
|
1334
1089
|
}>>>;
|
|
1335
1090
|
}>, typeof RemoteQueryError, never, never>;
|
|
1336
|
-
declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"
|
|
1091
|
+
declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
|
|
1337
1092
|
readonly version: Schema.Number;
|
|
1338
|
-
readonly
|
|
1093
|
+
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1094
|
+
/** Resume cursor; events at or before it are duplicates. */
|
|
1095
|
+
readonly after: Schema.Number;
|
|
1096
|
+
}>, import("effect/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
|
|
1097
|
+
readonly _tag: Schema.Literal<"EntityPatched">;
|
|
1098
|
+
readonly cursor: Schema.Number;
|
|
1099
|
+
readonly entity: Schema.String;
|
|
1100
|
+
readonly id: Schema.String;
|
|
1101
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1102
|
+
readonly changed: Schema.$Array<Schema.String>;
|
|
1339
1103
|
}>, Schema.Struct<{
|
|
1340
|
-
readonly
|
|
1104
|
+
readonly _tag: Schema.Literal<"EntityDeleted">;
|
|
1105
|
+
readonly cursor: Schema.Number;
|
|
1106
|
+
readonly entity: Schema.String;
|
|
1107
|
+
readonly id: Schema.String;
|
|
1108
|
+
}>, Schema.Struct<{
|
|
1109
|
+
readonly _tag: Schema.Literal<"ConnectionInsert">;
|
|
1110
|
+
readonly cursor: Schema.Number;
|
|
1111
|
+
readonly connection: Schema.String;
|
|
1112
|
+
readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
|
|
1113
|
+
readonly edge: Schema.Struct<{
|
|
1341
1114
|
readonly entity: Schema.String;
|
|
1342
1115
|
readonly id: Schema.String;
|
|
1343
|
-
readonly
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1116
|
+
readonly key: Schema.String;
|
|
1117
|
+
}>;
|
|
1118
|
+
}>, Schema.Struct<{
|
|
1119
|
+
readonly _tag: Schema.Literal<"ConnectionRemove">;
|
|
1120
|
+
readonly cursor: Schema.Number;
|
|
1121
|
+
readonly connection: Schema.String;
|
|
1122
|
+
readonly edge: Schema.Struct<{
|
|
1346
1123
|
readonly entity: Schema.String;
|
|
1347
1124
|
readonly id: Schema.String;
|
|
1348
|
-
readonly
|
|
1349
|
-
}
|
|
1350
|
-
}>, Schema.
|
|
1125
|
+
readonly key: Schema.String;
|
|
1126
|
+
}>;
|
|
1127
|
+
}>, Schema.Struct<{
|
|
1128
|
+
readonly _tag: Schema.Literal<"ConnectionInvalidate">;
|
|
1129
|
+
readonly cursor: Schema.Number;
|
|
1130
|
+
readonly connection: Schema.String;
|
|
1131
|
+
}>]>, Schema.Union<readonly [typeof RemoteLiveError, typeof RemoteProtocolError]>>, Schema.Never, never, never> | Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
|
|
1351
1132
|
/** Stable across transport retries so a mutation is not applied twice. */
|
|
1352
1133
|
readonly requestId: Schema.String;
|
|
1353
1134
|
readonly mutation: Schema.String;
|
|
@@ -1385,47 +1166,7 @@ declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", Schema.S
|
|
|
1385
1166
|
readonly entity: Schema.String;
|
|
1386
1167
|
readonly id: Schema.String;
|
|
1387
1168
|
}>>>;
|
|
1388
|
-
}>, Schema.Union<readonly [typeof RemoteMutationError, typeof RemoteForbidden]>, never, never> | Rpc.Rpc<"
|
|
1389
|
-
readonly version: Schema.Number;
|
|
1390
|
-
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1391
|
-
/** Resume cursor; events at or before it are duplicates. */
|
|
1392
|
-
readonly after: Schema.Number;
|
|
1393
|
-
}>, import("effect/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
|
|
1394
|
-
readonly _tag: Schema.Literal<"EntityPatched">;
|
|
1395
|
-
readonly cursor: Schema.Number;
|
|
1396
|
-
readonly entity: Schema.String;
|
|
1397
|
-
readonly id: Schema.String;
|
|
1398
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1399
|
-
readonly changed: Schema.$Array<Schema.String>;
|
|
1400
|
-
}>, Schema.Struct<{
|
|
1401
|
-
readonly _tag: Schema.Literal<"EntityDeleted">;
|
|
1402
|
-
readonly cursor: Schema.Number;
|
|
1403
|
-
readonly entity: Schema.String;
|
|
1404
|
-
readonly id: Schema.String;
|
|
1405
|
-
}>, Schema.Struct<{
|
|
1406
|
-
readonly _tag: Schema.Literal<"ConnectionInsert">;
|
|
1407
|
-
readonly cursor: Schema.Number;
|
|
1408
|
-
readonly connection: Schema.String;
|
|
1409
|
-
readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
|
|
1410
|
-
readonly edge: Schema.Struct<{
|
|
1411
|
-
readonly entity: Schema.String;
|
|
1412
|
-
readonly id: Schema.String;
|
|
1413
|
-
readonly key: Schema.String;
|
|
1414
|
-
}>;
|
|
1415
|
-
}>, Schema.Struct<{
|
|
1416
|
-
readonly _tag: Schema.Literal<"ConnectionRemove">;
|
|
1417
|
-
readonly cursor: Schema.Number;
|
|
1418
|
-
readonly connection: Schema.String;
|
|
1419
|
-
readonly edge: Schema.Struct<{
|
|
1420
|
-
readonly entity: Schema.String;
|
|
1421
|
-
readonly id: Schema.String;
|
|
1422
|
-
readonly key: Schema.String;
|
|
1423
|
-
}>;
|
|
1424
|
-
}>, Schema.Struct<{
|
|
1425
|
-
readonly _tag: Schema.Literal<"ConnectionInvalidate">;
|
|
1426
|
-
readonly cursor: Schema.Number;
|
|
1427
|
-
readonly connection: Schema.String;
|
|
1428
|
-
}>]>, Schema.Union<readonly [typeof RemoteLiveError, typeof RemoteProtocolError]>>, Schema.Never, never, never> | Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
|
|
1169
|
+
}>, Schema.Union<readonly [typeof RemoteMutationError, typeof RemoteForbidden]>, never, never> | Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
|
|
1429
1170
|
readonly query: Schema.String;
|
|
1430
1171
|
readonly input: Schema.Unknown;
|
|
1431
1172
|
readonly window: Schema.Struct<{
|
|
@@ -1467,1022 +1208,1204 @@ declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", Schema.S
|
|
|
1467
1208
|
* returns. Absent from a server that predates payload planning: the client
|
|
1468
1209
|
* reads it as empty and fetches fields as before.
|
|
1469
1210
|
*/
|
|
1470
|
-
readonly entities: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1471
|
-
readonly entity: Schema.String;
|
|
1472
|
-
readonly id: Schema.String;
|
|
1473
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1474
|
-
}>>>;
|
|
1475
|
-
readonly settled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1476
|
-
readonly entity: Schema.String;
|
|
1477
|
-
readonly id: Schema.String;
|
|
1478
|
-
readonly fields: Schema.$Array<Schema.String>;
|
|
1479
|
-
}>>>;
|
|
1480
|
-
}>, typeof RemoteQueryError, never, never
|
|
1211
|
+
readonly entities: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1212
|
+
readonly entity: Schema.String;
|
|
1213
|
+
readonly id: Schema.String;
|
|
1214
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1215
|
+
}>>>;
|
|
1216
|
+
readonly settled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1217
|
+
readonly entity: Schema.String;
|
|
1218
|
+
readonly id: Schema.String;
|
|
1219
|
+
readonly fields: Schema.$Array<Schema.String>;
|
|
1220
|
+
}>>>;
|
|
1221
|
+
}>, typeof RemoteQueryError, never, never> | Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
|
|
1222
|
+
readonly version: Schema.Number;
|
|
1223
|
+
readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1224
|
+
}>, Schema.Struct<{
|
|
1225
|
+
readonly entities: Schema.$Array<Schema.Struct<{
|
|
1226
|
+
readonly entity: Schema.String;
|
|
1227
|
+
readonly id: Schema.String;
|
|
1228
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1229
|
+
}>>;
|
|
1230
|
+
readonly settled: Schema.$Array<Schema.Struct<{
|
|
1231
|
+
readonly entity: Schema.String;
|
|
1232
|
+
readonly id: Schema.String;
|
|
1233
|
+
readonly fields: Schema.$Array<Schema.String>;
|
|
1234
|
+
}>>;
|
|
1235
|
+
}>, Schema.Union<readonly [typeof RemoteReadError, typeof RemoteProtocolError]>, never, never>>;
|
|
1236
|
+
//#endregion
|
|
1237
|
+
//#region src/coalesce.d.ts
|
|
1238
|
+
type Batch = Schema.Schema.Type<typeof ReadBatch>;
|
|
1239
|
+
type BatchResult = Schema.Schema.Type<typeof ReadBatchResult>;
|
|
1240
|
+
type ReadError = RemoteReadError | RemoteProtocolError;
|
|
1241
|
+
type BatchRead = (batch: Batch) => Effect.Effect<BatchResult, ReadError>;
|
|
1242
|
+
type QueryRequestValue = Schema.Schema.Type<typeof QueryRequest>;
|
|
1243
|
+
type QueryResultValue = Schema.Schema.Type<typeof QueryResult>;
|
|
1244
|
+
type QueryRun = (request: QueryRequestValue) => Effect.Effect<QueryResultValue, RemoteQueryError>;
|
|
1245
|
+
interface CoalesceOptions {
|
|
1246
|
+
/**
|
|
1247
|
+
* How long a batch waits to collect more requirements before it runs.
|
|
1248
|
+
* Requirements issued concurrently coalesce even at the default of no wait.
|
|
1249
|
+
*/
|
|
1250
|
+
readonly window?: Duration.Input | undefined;
|
|
1251
|
+
}
|
|
1252
|
+
/** A stable key for a requirement, so an equal requirement in flight is joined. */
|
|
1253
|
+
declare const requirementKey: (requirement: Requirement) => string;
|
|
1254
|
+
/**
|
|
1255
|
+
* Wraps a raw query so that an identical query in flight (same query, input,
|
|
1256
|
+
* and window) is joined rather than run again; distinct queries run
|
|
1257
|
+
* concurrently. A page answers exactly one window, so nothing is batched.
|
|
1258
|
+
*/
|
|
1259
|
+
declare const coalesceQueries: (query: QueryRun, options?: CoalesceOptions) => Effect.Effect<QueryRun>;
|
|
1260
|
+
/**
|
|
1261
|
+
* Wraps a raw batch read so that requirements are batched and deduplicated.
|
|
1262
|
+
* Every waiter receives the whole batch result; `Remote.writeRead` is
|
|
1263
|
+
* idempotent, so writing it more than once is harmless.
|
|
1264
|
+
*/
|
|
1265
|
+
declare const coalesceReads: (read: BatchRead, options?: CoalesceOptions) => Effect.Effect<BatchRead>;
|
|
1481
1266
|
//#endregion
|
|
1482
|
-
//#region src/
|
|
1267
|
+
//#region src/live.d.ts
|
|
1268
|
+
type LiveCursor = number;
|
|
1269
|
+
type LiveEvent = {
|
|
1270
|
+
readonly _tag: 'EntityPatched';
|
|
1271
|
+
readonly ref: EdgeRef;
|
|
1272
|
+
readonly values: Readonly<Record<string, unknown>>;
|
|
1273
|
+
readonly changed: ReadonlyArray<string>;
|
|
1274
|
+
readonly cursor: LiveCursor;
|
|
1275
|
+
} | {
|
|
1276
|
+
readonly _tag: 'EntityDeleted';
|
|
1277
|
+
readonly ref: EdgeRef;
|
|
1278
|
+
readonly cursor: LiveCursor;
|
|
1279
|
+
} | {
|
|
1280
|
+
readonly _tag: 'ConnectionInsert';
|
|
1281
|
+
readonly connection: string;
|
|
1282
|
+
readonly position: 'prepend' | 'append';
|
|
1283
|
+
readonly edge: Edge;
|
|
1284
|
+
readonly cursor: LiveCursor;
|
|
1285
|
+
} | {
|
|
1286
|
+
readonly _tag: 'ConnectionRemove';
|
|
1287
|
+
readonly connection: string;
|
|
1288
|
+
readonly edge: Edge;
|
|
1289
|
+
readonly cursor: LiveCursor;
|
|
1290
|
+
} | {
|
|
1291
|
+
readonly _tag: 'ConnectionInvalidate';
|
|
1292
|
+
readonly connection: string;
|
|
1293
|
+
readonly cursor: LiveCursor;
|
|
1294
|
+
};
|
|
1295
|
+
interface BoundaryCounts {
|
|
1296
|
+
readonly before: number;
|
|
1297
|
+
readonly after: number;
|
|
1298
|
+
}
|
|
1299
|
+
interface LiveState {
|
|
1300
|
+
/** Last applied cursor for this stream. */
|
|
1301
|
+
readonly cursor: LiveCursor;
|
|
1302
|
+
/** Edges recorded outside the loaded boundary, not visible in `items`. */
|
|
1303
|
+
readonly boundary: Readonly<Record<string, BoundaryCounts>>;
|
|
1304
|
+
}
|
|
1305
|
+
declare const emptyLiveState: LiveState;
|
|
1306
|
+
type LiveOutcome = 'applied' | 'duplicate' | 'gap';
|
|
1483
1307
|
/**
|
|
1484
|
-
*
|
|
1485
|
-
*
|
|
1308
|
+
* Ordering per stream: at most the next cursor; ahead is a gap. Cursor `0` means
|
|
1309
|
+
* "no baseline yet" (cursors are 1-based), so the first event of a stream is
|
|
1310
|
+
* accepted whatever its cursor — otherwise a stream not starting at 1 would be a
|
|
1311
|
+
* spurious gap.
|
|
1486
1312
|
*/
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
readonly
|
|
1490
|
-
|
|
1491
|
-
readonly
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
readonly
|
|
1498
|
-
/** Optimistic entity layers and connection overlays over the base store. */
|
|
1313
|
+
declare const classifyLive: (state: LiveState, cursor: LiveCursor) => LiveOutcome;
|
|
1314
|
+
interface EntityApplied {
|
|
1315
|
+
readonly state: LiveState;
|
|
1316
|
+
readonly store: EntityStore;
|
|
1317
|
+
readonly outcome: LiveOutcome;
|
|
1318
|
+
}
|
|
1319
|
+
declare const applyEntityEvent: (state: LiveState, store: EntityStore, event: Extract<LiveEvent, {
|
|
1320
|
+
_tag: 'EntityPatched' | 'EntityDeleted';
|
|
1321
|
+
}>, now?: number) => EntityApplied;
|
|
1322
|
+
interface ConnectionApplied {
|
|
1323
|
+
readonly state: LiveState;
|
|
1499
1324
|
readonly optimistic: OptimisticState;
|
|
1500
|
-
|
|
1501
|
-
readonly live: Readonly<Record<string, LiveState>>;
|
|
1502
|
-
/** Mutation pending/applied/failed ledger. */
|
|
1503
|
-
readonly mutations: MutationState;
|
|
1504
|
-
/**
|
|
1505
|
-
* Streams that broke, by an error or by an event ahead of their cursor, and
|
|
1506
|
-
* have not resubscribed since: changes after the break are missed until the
|
|
1507
|
-
* live entry restarts them and refetches what they cover.
|
|
1508
|
-
*/
|
|
1509
|
-
readonly gaps: ReadonlySet<string>;
|
|
1510
|
-
/** Each live stream that has ever broken, by stream key. One that never broke is absent. */
|
|
1511
|
-
readonly streams: Readonly<Record<string, StreamHealth>>;
|
|
1512
|
-
/**
|
|
1513
|
-
* The `entity\0id\0field` marks a read is currently fetching. A field absent
|
|
1514
|
-
* from the store reads as `Loading` while its mark is here and `Initial`
|
|
1515
|
-
* otherwise, which is what separates "being fetched" from "nothing is
|
|
1516
|
-
* fetching this".
|
|
1517
|
-
*/
|
|
1518
|
-
readonly loading: ReadonlySet<string>;
|
|
1519
|
-
/**
|
|
1520
|
-
* `Remote.refresh` generations, held per field rather than for the store as a
|
|
1521
|
-
* whole. A read entry restarts when the generation over the fields it plans
|
|
1522
|
-
* moves, so a read sent before a refresh of its own fields cannot land after
|
|
1523
|
-
* it, and a refresh of one field leaves every other entry's read alone.
|
|
1524
|
-
*/
|
|
1525
|
-
readonly refresh: RefreshState;
|
|
1526
|
-
/**
|
|
1527
|
-
* The reads that failed and have not been settled since, so a read can say
|
|
1528
|
-
* `Failed` rather than `Initial`.
|
|
1529
|
-
*
|
|
1530
|
-
* Without them a read that failed before anything loaded read exactly like
|
|
1531
|
-
* one nobody had asked for, and nothing asked again: a read entry restarts
|
|
1532
|
-
* only when what it plans changes, and a failure changed nothing. What failed
|
|
1533
|
-
* is not planned again on its own either, so a persistent error is not
|
|
1534
|
-
* retried every time an unrelated read restarts the entry. `Remote.refresh`
|
|
1535
|
-
* is how a view retries.
|
|
1536
|
-
*/
|
|
1537
|
-
readonly failures: Failures;
|
|
1538
|
-
/**
|
|
1539
|
-
* The storage key the cache was last restored from, through `Hydrated`'s
|
|
1540
|
-
* `from`. `Data.persistence` saves under a key only once its own snapshot is
|
|
1541
|
-
* in, so a save at startup cannot write the empty store over it.
|
|
1542
|
-
*/
|
|
1543
|
-
readonly restoredFrom: Option.Option<string>;
|
|
1325
|
+
readonly outcome: LiveOutcome;
|
|
1544
1326
|
/**
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1547
|
-
*
|
|
1327
|
+
* A connection the event says to refetch. Reported rather than recorded here,
|
|
1328
|
+
* because staleness lives on the connection in the Model — which is what the
|
|
1329
|
+
* planner and every read consult. It used to be written into a set on this
|
|
1330
|
+
* live state that nothing read, so an invalidating event did nothing at all.
|
|
1548
1331
|
*/
|
|
1549
|
-
readonly
|
|
1550
|
-
/** Under `verifyPlacement`, each placement the server's page disagreed with. */
|
|
1551
|
-
readonly placementMismatches: ReadonlyArray<PlacementMismatch>;
|
|
1332
|
+
readonly invalidated?: string | undefined;
|
|
1552
1333
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1334
|
+
declare const applyConnectionEvent: (state: LiveState, optimistic: OptimisticState, event: Extract<LiveEvent, {
|
|
1335
|
+
_tag: 'ConnectionInsert' | 'ConnectionRemove' | 'ConnectionInvalidate';
|
|
1336
|
+
}>, policy?: LivePolicy) => ConnectionApplied;
|
|
1337
|
+
/** `hasPrevious` accounting for edges recorded outside the loaded boundary. */
|
|
1338
|
+
declare const liveHasPrevious: (connection: Connection, state: LiveState, connectionId: string) => boolean;
|
|
1339
|
+
/** `hasNext` accounting for edges recorded outside the loaded boundary. */
|
|
1340
|
+
declare const liveHasNext: (connection: Connection, state: LiveState, connectionId: string) => boolean;
|
|
1341
|
+
//#endregion
|
|
1342
|
+
//#region src/client.d.ts
|
|
1343
|
+
declare const RemoteClient_base: Context.ServiceClass<RemoteClient, "foldkit-remote/RemoteClient", {
|
|
1344
|
+
readonly read: (batch: Schema.Schema.Type<typeof ReadBatch>) => Effect.Effect<Schema.Schema.Type<typeof ReadBatchResult>, RemoteReadError | RemoteProtocolError>;
|
|
1345
|
+
readonly query: (request: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError>;
|
|
1346
|
+
readonly mutate: (request: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError | RemoteForbidden>;
|
|
1347
|
+
readonly live: (request: {
|
|
1348
|
+
readonly requirements: ReadonlyArray<Requirement>;
|
|
1349
|
+
readonly after: LiveCursor;
|
|
1350
|
+
}) => Stream.Stream<LiveEvent, RemoteLiveError | RemoteProtocolError>;
|
|
1351
|
+
}>;
|
|
1352
|
+
/**
|
|
1353
|
+
* The transport boundary. `foldkit-remote` never talks to a transport directly;
|
|
1354
|
+
* it depends on this Effect service, which a later phase wires to Effect RPC.
|
|
1355
|
+
*/
|
|
1356
|
+
declare class RemoteClient extends RemoteClient_base {}
|
|
1357
|
+
/**
|
|
1358
|
+
* The methods an Effect RPC client for `RemoteRpc` exposes. `R` is the
|
|
1359
|
+
* environment a handler needs; it defaults to `never`, which is what a real
|
|
1360
|
+
* transport client satisfies. `RemoteServer.handlers` returns this type with its
|
|
1361
|
+
* own `R`, so the two sides cannot drift apart.
|
|
1362
|
+
*
|
|
1363
|
+
* `TransportError` is what the transport itself may fail with on top of the
|
|
1364
|
+
* declared errors: `RpcClientError` for the client `RpcClient.make` builds,
|
|
1365
|
+
* `never` for in-process handlers.
|
|
1366
|
+
*/
|
|
1367
|
+
interface RemoteRpcClient<R = never, TransportError = never> {
|
|
1368
|
+
readonly FoldkitRemoteRead: (payload: Schema.Schema.Type<typeof ReadBatch>) => Effect.Effect<Schema.Schema.Type<typeof ReadBatchResult>, RemoteReadError | RemoteProtocolError | TransportError, R>;
|
|
1369
|
+
readonly FoldkitRemoteQuery: (payload: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError | TransportError, R>;
|
|
1370
|
+
readonly FoldkitRemoteMutate: (payload: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError | RemoteForbidden | TransportError, R>;
|
|
1371
|
+
readonly FoldkitRemoteLive: (payload: Schema.Schema.Type<typeof LiveRequirement>) => Stream.Stream<Schema.Schema.Type<typeof LiveChange>, RemoteLiveError | RemoteProtocolError | TransportError, R>;
|
|
1557
1372
|
}
|
|
1558
|
-
/**
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
readonly
|
|
1373
|
+
/** Reconstructs the client's `ConnectionChange` from the wire's flattened edge. */
|
|
1374
|
+
declare const connectionChangeOf: (change: Schema.Schema.Type<typeof ConnectionChangeSchema>) => ConnectionChange;
|
|
1375
|
+
/** Reconstructs the client's `LiveEvent` from the wire's flattened `LiveChange`. */
|
|
1376
|
+
declare const liveEventOf: (change: Schema.Schema.Type<typeof LiveChange>) => LiveEvent;
|
|
1377
|
+
declare const remoteError: (error: {
|
|
1378
|
+
readonly _tag: string;
|
|
1379
|
+
readonly message: string;
|
|
1380
|
+
readonly refusal?: unknown;
|
|
1381
|
+
readonly reason?: string | undefined;
|
|
1382
|
+
}) => RemoteError;
|
|
1383
|
+
declare const coalescedLayer: <E, R>(layer: Layer.Layer<RemoteClient, E, R>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, E, R>;
|
|
1384
|
+
/**
|
|
1385
|
+
* `Remote.mutate` as a standalone effect, so `Remote.mutateInto` can reuse it
|
|
1386
|
+
* without the object literal referencing itself.
|
|
1387
|
+
*/
|
|
1388
|
+
declare const mutateRemote: <Name extends string, Input, Output>(mutation: MutationDescriptor<Name, Input, Output, unknown>, input: Input, requestId: string, keys?: readonly string[] | undefined) => Effect.Effect<{
|
|
1389
|
+
output: Output;
|
|
1390
|
+
entities: readonly {
|
|
1391
|
+
readonly entity: string;
|
|
1392
|
+
readonly id: string;
|
|
1393
|
+
readonly values: {
|
|
1394
|
+
readonly [x: string]: unknown;
|
|
1395
|
+
};
|
|
1396
|
+
}[];
|
|
1397
|
+
connections: ConnectionChange[];
|
|
1398
|
+
deleted: readonly {
|
|
1399
|
+
readonly entity: string;
|
|
1400
|
+
readonly id: string;
|
|
1401
|
+
}[];
|
|
1402
|
+
}, RemoteForbidden | RemoteMutationError, RemoteClient>;
|
|
1403
|
+
//#endregion
|
|
1404
|
+
//#region src/relation.d.ts
|
|
1405
|
+
interface RefParts {
|
|
1406
|
+
readonly entity: string;
|
|
1407
|
+
readonly id: string;
|
|
1565
1408
|
}
|
|
1566
|
-
/**
|
|
1567
|
-
interface
|
|
1568
|
-
|
|
1569
|
-
readonly
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1409
|
+
/** A page of refs as the wire and the store hold it. */
|
|
1410
|
+
interface RefPageValue {
|
|
1411
|
+
readonly refs: ReadonlyArray<string>;
|
|
1412
|
+
readonly hasNext: boolean;
|
|
1413
|
+
readonly hasPrevious: boolean;
|
|
1414
|
+
}
|
|
1415
|
+
/** Marks the codec `Entity.ref`/`Entity.refPage` produce, so a Selection can tell the field's shape. */
|
|
1416
|
+
declare const RelationAnnotation = "foldkitRemoteRelation";
|
|
1417
|
+
/** The target entity's name on the same codec, so a nested selection of another entity is refused. */
|
|
1418
|
+
declare const RelationEntityAnnotation = "foldkitRemoteRelationEntity";
|
|
1419
|
+
type RelationKind = 'one' | 'many' | 'page';
|
|
1420
|
+
interface RelationShape {
|
|
1421
|
+
readonly kind: RelationKind;
|
|
1422
|
+
readonly nullable: boolean;
|
|
1423
|
+
readonly entity: string;
|
|
1574
1424
|
}
|
|
1575
1425
|
/**
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
* settling it: if that read fails too, the failure is simply recorded again.
|
|
1426
|
+
* A page of a relation that is a whole list is read under a name of its own, the
|
|
1427
|
+
* field's name and the page's size: `comments@first=10`. It is a field like any
|
|
1428
|
+
* other to the store, the planner, and the wire, so the whole list and a page of
|
|
1429
|
+
* it are held side by side, merged, marked stale, and persisted each on its own.
|
|
1430
|
+
* The server reads the name apart, reads the relation with the window, and
|
|
1431
|
+
* answers under the alias. A cursor is not part of the name: a page read from a
|
|
1432
|
+
* cursor merges onto the page it continues.
|
|
1584
1433
|
*/
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1434
|
+
declare const RELATION_ALIAS = "@";
|
|
1435
|
+
/** The alias a relation field is read under, for a window of this size. */
|
|
1436
|
+
declare const relationAlias: (field: string, window: {
|
|
1437
|
+
readonly first?: number | undefined;
|
|
1438
|
+
readonly last?: number | undefined;
|
|
1439
|
+
readonly after?: string | undefined;
|
|
1440
|
+
readonly before?: string | undefined;
|
|
1441
|
+
}) => string;
|
|
1442
|
+
/** The field an alias reads; a name that is no alias is its own field. */
|
|
1443
|
+
declare const aliasedField: (name: string) => string;
|
|
1444
|
+
/** Splits a ref key (`"Entity:id"`, the store key too) back into its parts. */
|
|
1445
|
+
declare const refParts: (encoded: string) => RefParts;
|
|
1590
1446
|
/**
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
1593
|
-
* is the generation each field's read last began under. Holding them per field
|
|
1594
|
-
* is what keeps one Projection's refresh from restarting every read entry.
|
|
1447
|
+
* The refs a relation value carries, in order. Anything that is not a ref key,
|
|
1448
|
+
* an array of them, or a page of them contributes nothing.
|
|
1595
1449
|
*/
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1450
|
+
declare const refsIn: (value: unknown) => ReadonlyArray<RefParts>;
|
|
1451
|
+
/** The refs in a relation value that name the relation's target entity, and no other. */
|
|
1452
|
+
declare const targetsOf: (value: unknown, relation: RelationRequirement) => ReadonlyArray<RefParts>;
|
|
1453
|
+
declare const isRefPage: (value: unknown) => value is RefPageValue;
|
|
1454
|
+
/**
|
|
1455
|
+
* The relation shape an entity field schema declares: a ref (`one`), a nullable
|
|
1456
|
+
* ref, an array of refs (`many`), or a page of refs (`page`). `undefined` for a
|
|
1457
|
+
* scalar field, which cannot take a nested selection.
|
|
1458
|
+
*/
|
|
1459
|
+
declare const relationShape: (schema: Schema.Top) => RelationShape | undefined;
|
|
1460
|
+
//#endregion
|
|
1461
|
+
//#region src/selection.d.ts
|
|
1462
|
+
/** One page of a paginated relation with each target assembled through a nested selection. */
|
|
1463
|
+
interface Page<Item> {
|
|
1464
|
+
readonly items: ReadonlyArray<Item>;
|
|
1465
|
+
readonly hasNext: boolean;
|
|
1466
|
+
readonly hasPrevious: boolean;
|
|
1606
1467
|
}
|
|
1607
|
-
declare const emptyRefresh: RefreshState;
|
|
1608
1468
|
/**
|
|
1609
|
-
* The
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
* sequence is kept, so request ids stay unique, and a mutation in flight is
|
|
1613
|
-
* treated as applied: its answer, when it comes, writes nothing here.
|
|
1469
|
+
* The fields a projection reads of one entity, plus the slice it reads of each
|
|
1470
|
+
* relation's target. `Shape` tells a parent selection whether this one is a
|
|
1471
|
+
* paginated relation (`connection`) or a plain entity slice (`entity`).
|
|
1614
1472
|
*/
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
/**
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
readonly
|
|
1622
|
-
|
|
1623
|
-
readonly
|
|
1624
|
-
|
|
1625
|
-
readonly
|
|
1626
|
-
|
|
1627
|
-
readonly
|
|
1473
|
+
interface Selection<Value, Name extends string = string, Shape extends 'entity' | 'connection' = 'entity' | 'connection'> {
|
|
1474
|
+
readonly entity: Name;
|
|
1475
|
+
readonly fields: readonly string[];
|
|
1476
|
+
/** A pure codec: entity fields carry no decoding or encoding services. */
|
|
1477
|
+
readonly schema: Schema.Codec<Value, unknown, never, never>;
|
|
1478
|
+
/** Pagination windows for nested relation fields, keyed by field name. */
|
|
1479
|
+
readonly connections?: Readonly<Record<string, QueryWindow>> | undefined;
|
|
1480
|
+
/** The slice required of each nested relation's target, keyed by field name. */
|
|
1481
|
+
readonly relations?: Readonly<Record<string, RelationRequirement>> | undefined;
|
|
1482
|
+
/** Present when this selection is itself a paginated relation. */
|
|
1483
|
+
readonly window?: QueryWindow | undefined;
|
|
1484
|
+
/** Phantom: see `Shape`. */
|
|
1485
|
+
readonly shape?: Shape | undefined;
|
|
1486
|
+
}
|
|
1487
|
+
/** Flattens a mapped type so hovers show the picked fields, not the machinery. */
|
|
1488
|
+
type Simplify<T> = T extends (infer O) ? { readonly [K in keyof O]: O[K]; } : never;
|
|
1489
|
+
/** The value a Selection reads: `Selection.Value<typeof ProjectCard>`. */
|
|
1490
|
+
type SelectionValueOf<S> = S extends Selection<infer V, any, any> ? V : never;
|
|
1491
|
+
/** The nested selections a relation field admits: of its target entity, in the shapes its value takes. */
|
|
1492
|
+
type NestedFor<Field> = Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef<infer Name, any>> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends RefPage<infer Name, any> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends EntityRef<infer Name, any> ? Selection<unknown, Name, 'entity'> : never;
|
|
1493
|
+
/** What a selection of an entity with fields `F` may pick: `true` per scalar, a nested selection per relation. */
|
|
1494
|
+
type SelectionOf<F extends Schema.Struct.Fields> = { readonly [K in keyof F]?: true | NestedFor<Schema.Schema.Type<F[K]>>; };
|
|
1495
|
+
/** `T | null` when the field admits `null` or `undefined` (both assemble to `null`). */
|
|
1496
|
+
type Nullable<Field, T> = [Extract<Field, null | undefined>] extends [never] ? T : T | null;
|
|
1497
|
+
/** A nested selection's value takes the shape of the field it selects through. */
|
|
1498
|
+
type NestedValue<Field, Sel> = Sel extends Selection<infer V, string, 'connection'> ? Nullable<Field, V> : Sel extends Selection<infer V, string, 'entity'> ? Nullable<Field, Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef<any, any>> ? ReadonlyArray<V> : Exclude<Field, null | undefined> extends RefPage<any, any> ? Page<V> : V> : never;
|
|
1499
|
+
/** The value a selection `Sel` of fields `F` reads. */
|
|
1500
|
+
type SelectionValue<F extends Schema.Struct.Fields, Sel> = Simplify<{ readonly [K in keyof Sel & keyof F]: Sel[K] extends true ? Schema.Schema.Type<F[K]> : NestedValue<Schema.Schema.Type<F[K]>, Sel[K]>; }>;
|
|
1501
|
+
declare const pageSchema: (item: AnySchema) => AnySchema;
|
|
1502
|
+
/** The requirement a nested selection contributes for its relation's target. */
|
|
1503
|
+
declare const relationOf: (selection: Selection<unknown>) => RelationRequirement;
|
|
1504
|
+
declare const Selection: {
|
|
1628
1505
|
/**
|
|
1629
|
-
* The
|
|
1630
|
-
*
|
|
1631
|
-
* recorded as a gap, since changes after it are missed until the live
|
|
1632
|
-
* entry restarts it.
|
|
1506
|
+
* The Remote Selection of a `foldkit-entity` Selection: the same members, read
|
|
1507
|
+
* from Remote's store. `true` on a relation reads its refs, as it does here.
|
|
1633
1508
|
*/
|
|
1634
|
-
|
|
1635
|
-
} |
|
|
1636
|
-
/** A refetch of present fields began; they read as `Refreshing` until it lands. */
|
|
1637
|
-
{
|
|
1638
|
-
readonly _tag: 'RefreshStarted';
|
|
1639
|
-
readonly requests: readonly Requirement[];
|
|
1640
|
-
} |
|
|
1641
|
-
/** A read began; the fields it asks for that the store lacks read as `Loading`. */
|
|
1642
|
-
{
|
|
1643
|
-
readonly _tag: 'ReadStarted';
|
|
1644
|
-
readonly requests: readonly Requirement[];
|
|
1645
|
-
/** The refresh generation the read was planned under. */
|
|
1646
|
-
readonly refresh?: number | undefined;
|
|
1647
|
-
} |
|
|
1648
|
-
/**
|
|
1649
|
-
* Queries for these connections were sent. One with nothing to show reads
|
|
1650
|
-
* `Loading` until its page or its failure arrives, which is what separates
|
|
1651
|
-
* "being fetched" from `Initial`, "nothing is fetching this".
|
|
1652
|
-
*/
|
|
1653
|
-
{
|
|
1654
|
-
readonly _tag: 'QueryStarted';
|
|
1655
|
-
readonly connections: readonly string[];
|
|
1656
|
-
} |
|
|
1657
|
-
/** The active Surfaces' roots changed; everything they do not reach is collected. */
|
|
1658
|
-
{
|
|
1659
|
-
readonly _tag: 'RetentionChanged';
|
|
1660
|
-
readonly roots: RetentionRoots;
|
|
1661
|
-
} |
|
|
1662
|
-
/** A restored snapshot meets the store; runtime state is untouched. */
|
|
1663
|
-
{
|
|
1664
|
-
readonly _tag: 'Hydrated';
|
|
1665
|
-
readonly entities: EntityStore;
|
|
1509
|
+
from: <Name extends string, S extends Schema.Constraint>(selection: Domain.Selection<Name, unknown, S>) => Selection<S['Type'], Name, 'entity'>;
|
|
1666
1510
|
/**
|
|
1667
|
-
* The
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1670
|
-
* may name server state that is gone.
|
|
1511
|
+
* The fields to read of `entity`. A nested `Selection` on a relation field
|
|
1512
|
+
* reads through the ref (or refs, or page of refs) the field holds into the
|
|
1513
|
+
* target's fields; a scalar field cannot take one.
|
|
1671
1514
|
*/
|
|
1672
|
-
|
|
1673
|
-
readonly merge: MergePolicy;
|
|
1674
|
-
/** The storage key the snapshot was read from, when it was: `restoredFrom`. */
|
|
1675
|
-
readonly from?: string | undefined;
|
|
1676
|
-
} |
|
|
1677
|
-
/** A mutation began; its optimistic operations show until it settles. */
|
|
1678
|
-
{
|
|
1679
|
-
readonly _tag: 'MutationStarted';
|
|
1680
|
-
readonly requestId: string;
|
|
1681
|
-
readonly optimistic?: ReadonlyArray<OptimisticOperation> | undefined;
|
|
1682
|
-
} | {
|
|
1683
|
-
readonly _tag: 'MutationSucceeded';
|
|
1684
|
-
readonly requestId: string;
|
|
1685
|
-
readonly entities: readonly NormalizedPatch[];
|
|
1686
|
-
/** Connection changes the server confirmed; they replace the request's own. */
|
|
1687
|
-
readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
|
|
1688
|
-
/** Entities the mutation deleted: tombstoned, which hides them from every connection. */
|
|
1689
|
-
readonly deleted?: ReadonlyArray<{
|
|
1690
|
-
readonly entity: string;
|
|
1691
|
-
readonly id: string;
|
|
1692
|
-
}> | undefined;
|
|
1693
|
-
/** Injected clock reading of the answer: how fresh the written entities are. */
|
|
1694
|
-
readonly now: number;
|
|
1695
|
-
} | {
|
|
1696
|
-
readonly _tag: 'MutationFailed';
|
|
1697
|
-
readonly requestId: string;
|
|
1698
|
-
readonly error: RemoteError;
|
|
1699
|
-
} |
|
|
1700
|
-
/**
|
|
1701
|
-
* Operations shown over the store with no request behind them, until they are
|
|
1702
|
-
* lifted: a preview of a change nobody has made. Showing an id again replaces
|
|
1703
|
-
* what it showed.
|
|
1704
|
-
*/
|
|
1705
|
-
{
|
|
1706
|
-
readonly _tag: 'OverlayShown';
|
|
1707
|
-
readonly id: string;
|
|
1708
|
-
readonly optimistic: ReadonlyArray<OptimisticOperation>;
|
|
1709
|
-
} | {
|
|
1710
|
-
readonly _tag: 'OverlayLifted';
|
|
1711
|
-
readonly id: string;
|
|
1712
|
-
} |
|
|
1713
|
-
/** `Data.more`: a read's window, by `windowGrowthKey`, now shows `size` rows. */
|
|
1714
|
-
{
|
|
1715
|
-
readonly _tag: 'WindowGrown';
|
|
1716
|
-
readonly window: string;
|
|
1717
|
-
readonly size: number;
|
|
1718
|
-
} | {
|
|
1719
|
-
readonly _tag: 'LiveReceived';
|
|
1720
|
-
readonly stream: string;
|
|
1721
|
-
readonly event: LiveEvent;
|
|
1722
|
-
readonly policy?: LivePolicy;
|
|
1723
|
-
readonly now: number;
|
|
1724
|
-
} | {
|
|
1725
|
-
readonly _tag: 'GapCleared';
|
|
1726
|
-
readonly stream: string;
|
|
1727
|
-
} | {
|
|
1728
|
-
readonly _tag: 'ConnectionMerged';
|
|
1729
|
-
readonly connection: string;
|
|
1730
|
-
readonly page: Segment;
|
|
1731
|
-
/** The page answers the connection's refresh, so the merge also clears `stale`. */
|
|
1732
|
-
readonly refreshes?: boolean | undefined;
|
|
1515
|
+
make: <Name extends string, F extends Schema.Struct.Fields, const Sel extends SelectionOf<F>>(entity: EntityDescriptor<Name, F>, selection: Sel) => Selection<SelectionValue<F, Sel>, Name, 'entity'>;
|
|
1733
1516
|
/**
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
* that predates payload planning, which carries edges only.
|
|
1517
|
+
* A paginated relation: one page of refs to `entity` with a window, or, with
|
|
1518
|
+
* a nested selection, one page of targets assembled through it.
|
|
1737
1519
|
*/
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
readonly entity: string;
|
|
1748
|
-
readonly id: string;
|
|
1749
|
-
readonly fields: ReadonlyArray<string>;
|
|
1750
|
-
}> | undefined;
|
|
1751
|
-
/** Injected clock reading of the answer, dating what the payload writes. */
|
|
1752
|
-
readonly now?: number | undefined;
|
|
1753
|
-
} | {
|
|
1754
|
-
readonly _tag: 'ConnectionInvalidated';
|
|
1755
|
-
readonly connection: string;
|
|
1756
|
-
} | {
|
|
1757
|
-
readonly _tag: 'ConnectionRefreshed';
|
|
1758
|
-
readonly connection: string;
|
|
1759
|
-
} |
|
|
1520
|
+
connection: {
|
|
1521
|
+
<Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>, window: QueryWindow): Selection<RefPage<Name, F>, Name, 'connection'>;
|
|
1522
|
+
<Name extends string, F extends Schema.Struct.Fields, Item>(entity: EntityDescriptor<Name, F>, window: QueryWindow, selection: Selection<Item, NoInfer<Name>, 'entity'>): Selection<Page<Item>, Name, 'connection'>;
|
|
1523
|
+
};
|
|
1524
|
+
};
|
|
1525
|
+
interface Assembled {
|
|
1526
|
+
readonly values: unknown;
|
|
1527
|
+
readonly refreshing: boolean;
|
|
1528
|
+
}
|
|
1760
1529
|
/**
|
|
1761
|
-
*
|
|
1762
|
-
*
|
|
1763
|
-
*
|
|
1530
|
+
* Reads an entity's selected fields out of the store, following each nested
|
|
1531
|
+
* relation into its targets. `undefined` means some field, at any depth, is
|
|
1532
|
+
* not present yet. A tombstoned target reads as `null` (or is dropped from a
|
|
1533
|
+
* list), so the Selection's codec decides whether that is a failure.
|
|
1764
1534
|
*/
|
|
1765
|
-
|
|
1766
|
-
readonly _tag: 'QueryFailed';
|
|
1767
|
-
readonly connection: string;
|
|
1768
|
-
readonly error: RemoteError;
|
|
1769
|
-
};
|
|
1770
|
-
declare const retentionRootsSchema: Schema.Struct<{
|
|
1771
|
-
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1772
|
-
readonly connections: Schema.$Array<Schema.Struct<{
|
|
1773
|
-
readonly identity: Schema.String;
|
|
1774
|
-
readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
1775
|
-
}>>;
|
|
1776
|
-
}>;
|
|
1535
|
+
declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement) => Assembled | undefined;
|
|
1777
1536
|
/**
|
|
1778
|
-
* The
|
|
1779
|
-
*
|
|
1537
|
+
* The first field `requirement` reads, at any depth, that the server settled
|
|
1538
|
+
* without a value, as `Entity:id.field`. A read that consults it says why it
|
|
1539
|
+
* cannot assemble rather than waiting on a field nothing will fetch.
|
|
1780
1540
|
*/
|
|
1781
|
-
declare const
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
readonly entity: Schema.String;
|
|
1787
|
-
readonly id: Schema.String;
|
|
1788
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1789
|
-
}>>;
|
|
1790
|
-
readonly settled: Schema.$Array<Schema.Struct<{
|
|
1791
|
-
readonly entity: Schema.String;
|
|
1792
|
-
readonly id: Schema.String;
|
|
1793
|
-
readonly fields: Schema.$Array<Schema.String>;
|
|
1794
|
-
}>>;
|
|
1795
|
-
}>;
|
|
1796
|
-
now: Schema.Number;
|
|
1797
|
-
};
|
|
1798
|
-
ReadFailed: {
|
|
1799
|
-
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1800
|
-
error: Schema.Struct<{
|
|
1801
|
-
readonly _tag: Schema.String;
|
|
1802
|
-
readonly message: Schema.String;
|
|
1803
|
-
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
1804
|
-
readonly reason: Schema.optional<Schema.String>;
|
|
1805
|
-
}>;
|
|
1806
|
-
stream: Schema.optional<Schema.String>;
|
|
1807
|
-
};
|
|
1808
|
-
RefreshStarted: {
|
|
1809
|
-
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1810
|
-
};
|
|
1811
|
-
ReadStarted: {
|
|
1812
|
-
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1813
|
-
refresh: Schema.optional<Schema.Number>;
|
|
1814
|
-
};
|
|
1815
|
-
QueryStarted: {
|
|
1816
|
-
connections: Schema.$Array<Schema.String>;
|
|
1817
|
-
};
|
|
1818
|
-
RetentionChanged: {
|
|
1819
|
-
roots: Schema.Struct<{
|
|
1820
|
-
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
1821
|
-
readonly connections: Schema.$Array<Schema.Struct<{
|
|
1822
|
-
readonly identity: Schema.String;
|
|
1823
|
-
readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
1824
|
-
}>>;
|
|
1825
|
-
}>;
|
|
1826
|
-
};
|
|
1827
|
-
Hydrated: {
|
|
1828
|
-
connections: Schema.optional<Schema.Unknown>;
|
|
1829
|
-
from: Schema.optional<Schema.String>;
|
|
1830
|
-
entities: Schema.Unknown;
|
|
1831
|
-
merge: Schema.Union<readonly [Schema.Literal<"replace">, Schema.Literal<"preserve-existing">]>;
|
|
1832
|
-
};
|
|
1833
|
-
MutationStarted: {
|
|
1834
|
-
requestId: Schema.String;
|
|
1835
|
-
optimistic: Schema.optional<Schema.$Array<Schema.Unknown>>;
|
|
1836
|
-
};
|
|
1837
|
-
MutationSucceeded: {
|
|
1838
|
-
requestId: Schema.String;
|
|
1839
|
-
entities: Schema.$Array<Schema.Struct<{
|
|
1840
|
-
readonly entity: Schema.String;
|
|
1841
|
-
readonly id: Schema.String;
|
|
1842
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1843
|
-
}>>;
|
|
1844
|
-
connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
|
|
1845
|
-
deleted: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1846
|
-
readonly entity: Schema.String;
|
|
1847
|
-
readonly id: Schema.String;
|
|
1848
|
-
}>>>;
|
|
1849
|
-
now: Schema.Number;
|
|
1850
|
-
};
|
|
1851
|
-
MutationFailed: {
|
|
1852
|
-
requestId: Schema.String;
|
|
1853
|
-
error: Schema.Struct<{
|
|
1854
|
-
readonly _tag: Schema.String;
|
|
1855
|
-
readonly message: Schema.String;
|
|
1856
|
-
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
1857
|
-
readonly reason: Schema.optional<Schema.String>;
|
|
1858
|
-
}>;
|
|
1859
|
-
};
|
|
1860
|
-
OverlayShown: {
|
|
1861
|
-
id: Schema.String;
|
|
1862
|
-
optimistic: Schema.$Array<Schema.Unknown>;
|
|
1863
|
-
};
|
|
1864
|
-
OverlayLifted: {
|
|
1865
|
-
id: Schema.String;
|
|
1866
|
-
};
|
|
1867
|
-
WindowGrown: {
|
|
1868
|
-
window: Schema.String;
|
|
1869
|
-
size: Schema.Number;
|
|
1870
|
-
};
|
|
1871
|
-
LiveReceived: {
|
|
1872
|
-
stream: Schema.String;
|
|
1873
|
-
event: Schema.Unknown;
|
|
1874
|
-
policy: Schema.optional<Schema.Unknown>;
|
|
1875
|
-
now: Schema.Number;
|
|
1876
|
-
};
|
|
1877
|
-
GapCleared: {
|
|
1878
|
-
stream: Schema.String;
|
|
1879
|
-
};
|
|
1880
|
-
ConnectionMerged: {
|
|
1881
|
-
connection: Schema.String;
|
|
1882
|
-
page: Schema.Unknown;
|
|
1883
|
-
refreshes: Schema.optional<Schema.Boolean>;
|
|
1884
|
-
select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
1885
|
-
entities: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1886
|
-
readonly entity: Schema.String;
|
|
1887
|
-
readonly id: Schema.String;
|
|
1888
|
-
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
1889
|
-
}>>>;
|
|
1890
|
-
settled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1891
|
-
readonly entity: Schema.String;
|
|
1892
|
-
readonly id: Schema.String;
|
|
1893
|
-
readonly fields: Schema.$Array<Schema.String>;
|
|
1894
|
-
}>>>;
|
|
1895
|
-
now: Schema.optional<Schema.Number>;
|
|
1896
|
-
};
|
|
1897
|
-
ConnectionInvalidated: {
|
|
1898
|
-
connection: Schema.String;
|
|
1899
|
-
};
|
|
1900
|
-
ConnectionRefreshed: {
|
|
1901
|
-
connection: Schema.String;
|
|
1902
|
-
};
|
|
1903
|
-
QueryFailed: {
|
|
1904
|
-
connection: Schema.String;
|
|
1905
|
-
error: Schema.Struct<{
|
|
1906
|
-
readonly _tag: Schema.String;
|
|
1907
|
-
readonly message: Schema.String;
|
|
1908
|
-
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
1909
|
-
readonly reason: Schema.optional<Schema.String>;
|
|
1910
|
-
}>;
|
|
1911
|
-
};
|
|
1912
|
-
};
|
|
1913
|
-
type RemoteMessageTag = RemoteMessage['_tag'];
|
|
1541
|
+
declare const unavailableOf: (store: EntityStore, key: string, requirement: RelationRequirement) => string | undefined;
|
|
1542
|
+
//#endregion
|
|
1543
|
+
//#region src/entity.d.ts
|
|
1544
|
+
type AnySchema = Schema.Schema<unknown>;
|
|
1545
|
+
declare const entityRefFields: unique symbol;
|
|
1914
1546
|
/**
|
|
1915
|
-
* A
|
|
1916
|
-
* `
|
|
1917
|
-
* slots (`entities`, `event`, `page`) typed `unknown` by their schemas.
|
|
1547
|
+
* A normalized reference to an entity. `F` is a phantom carrying the entity's
|
|
1548
|
+
* fields so `Entity.patch` can type its patch; it is absent at runtime.
|
|
1918
1549
|
*/
|
|
1919
|
-
|
|
1920
|
-
readonly
|
|
1921
|
-
|
|
1550
|
+
interface EntityRef<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
|
|
1551
|
+
readonly entity: Name;
|
|
1552
|
+
readonly id: string;
|
|
1553
|
+
readonly [entityRefFields]?: F;
|
|
1554
|
+
}
|
|
1555
|
+
interface EntityDescriptor<Name extends string, F extends Schema.Struct.Fields> {
|
|
1556
|
+
readonly name: Name;
|
|
1557
|
+
readonly schema: Schema.Struct<F>;
|
|
1558
|
+
readonly fields: F;
|
|
1559
|
+
ref(id: Schema.Schema.Type<F['id']>): EntityRef<Name, F>;
|
|
1560
|
+
/** The fields a Surface reads of this entity; `Selection.make(entity, …)` with the entity as receiver. */
|
|
1561
|
+
select<const Sel extends SelectionOf<F>>(selection: Sel): Selection<SelectionValue<F, Sel>, Name, 'entity'>;
|
|
1562
|
+
/** A patch of this entity's wire-shaped values; `Entity.patch(entity.ref(id), values)`. */
|
|
1563
|
+
patch(id: Schema.Schema.Type<F['id']>, values: Partial<Schema.Struct.Encoded<F>>): EntityPatch<Name, F>;
|
|
1564
|
+
}
|
|
1922
1565
|
/**
|
|
1923
|
-
*
|
|
1924
|
-
*
|
|
1566
|
+
* Relations are **references**, never inline target schemas: a ref cannot
|
|
1567
|
+
* reconstruct a full entity, and dereferencing is a store concern. Because the
|
|
1568
|
+
* target schema is not inlined, recursive relations cannot arise through the
|
|
1569
|
+
* schema graph.
|
|
1925
1570
|
*/
|
|
1926
|
-
declare const isRemoteMessage: <M extends {
|
|
1927
|
-
readonly _tag: string;
|
|
1928
|
-
}>(message: M) => message is Extract<M, {
|
|
1929
|
-
readonly _tag: RemoteMessageTag;
|
|
1930
|
-
}>;
|
|
1931
|
-
declare const remoteMessageSchema: Schema.Schema<RemoteMessage>;
|
|
1932
|
-
/** The ids `OverlayShown` shows now, each once, in the order they are drawn. */
|
|
1933
|
-
declare const overlaysOf: (model: RemoteModel) => ReadonlyArray<string>;
|
|
1934
|
-
/** The key a grown window is kept under: its connection and the window first asked for. */
|
|
1935
|
-
declare const windowGrowthKey: (identity: string, window: string) => string;
|
|
1936
1571
|
/**
|
|
1937
|
-
*
|
|
1938
|
-
*
|
|
1939
|
-
*
|
|
1572
|
+
* A ref as the wire carries it: the target's name, a colon, and its id. Typed
|
|
1573
|
+
* with the name, so a relation to `User` takes `'User:u1'` and not a ref to
|
|
1574
|
+
* some other entity, which would read as a row that does not exist.
|
|
1940
1575
|
*/
|
|
1941
|
-
|
|
1942
|
-
/** Whether a query for this connection is in flight. */
|
|
1943
|
-
declare const isQueryLoading: (model: RemoteModel, identity: string) => boolean;
|
|
1576
|
+
type RefKey<Name extends string> = `${Name}:${string}`;
|
|
1944
1577
|
/**
|
|
1945
|
-
*
|
|
1946
|
-
*
|
|
1947
|
-
* dependency, so it restarts when what it observes is refreshed and not when
|
|
1948
|
-
* anything else is.
|
|
1578
|
+
* A patch in wire shape: the values the store holds, so a relation is its ref
|
|
1579
|
+
* key (`Entity.refKey`), not an `EntityRef`.
|
|
1949
1580
|
*/
|
|
1950
|
-
|
|
1581
|
+
interface EntityPatch<Name extends string, F extends Schema.Struct.Fields> {
|
|
1582
|
+
readonly entity: Name;
|
|
1583
|
+
readonly id: string;
|
|
1584
|
+
readonly values: Partial<Schema.Struct.Encoded<F>>;
|
|
1585
|
+
}
|
|
1951
1586
|
/**
|
|
1952
|
-
*
|
|
1953
|
-
*
|
|
1587
|
+
* One authoritative page of a paginated relation: refs (never inline entities)
|
|
1588
|
+
* plus whether more exist. The adapter does not hold segmentation state; the
|
|
1589
|
+
* client merges pages.
|
|
1954
1590
|
*/
|
|
1955
|
-
|
|
1591
|
+
interface RefPage<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
|
|
1592
|
+
readonly refs: ReadonlyArray<EntityRef<Name, F>>;
|
|
1593
|
+
readonly hasNext: boolean;
|
|
1594
|
+
readonly hasPrevious: boolean;
|
|
1595
|
+
}
|
|
1596
|
+
/** The ref codec a `foldkit-entity` relation becomes: one ref, a nullable ref, or an array of refs. */
|
|
1597
|
+
type RelationField<Spec> = Spec extends Domain.RelationSpec<infer Target, infer Cardinality, infer Optional> ? Cardinality extends 'many' ? Schema.$Array<Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>>> : Optional extends true ? Schema.NullOr<Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>>> : Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>> : never;
|
|
1598
|
+
/**
|
|
1599
|
+
* The fields Remote stores for a `foldkit-entity` Entity: its own fields, its
|
|
1600
|
+
* derived members (the server supplies them like any field), and each relation
|
|
1601
|
+
* as refs.
|
|
1602
|
+
*/
|
|
1603
|
+
type FieldsFrom<E> = E extends Domain.Entity<any, infer Fields, infer Relations, infer Derived> ? Fields & { readonly [K in keyof Derived]: Derived[K]['schema']; } & { readonly [K in keyof Relations]: RelationField<Relations[K]>; } : never;
|
|
1604
|
+
declare const Entity$2: {
|
|
1605
|
+
/**
|
|
1606
|
+
* The Remote descriptor of a `foldkit-entity` Entity. Relations declared with
|
|
1607
|
+
* `Entity.relate` become ref fields, so the store, the planner, and the server
|
|
1608
|
+
* treat it as they treat an `Entity.make` descriptor.
|
|
1609
|
+
*/
|
|
1610
|
+
from: <E extends Domain.AnyEntity>(entity: E & {
|
|
1611
|
+
readonly fields: {
|
|
1612
|
+
readonly id: unknown;
|
|
1613
|
+
};
|
|
1614
|
+
}) => EntityDescriptor<E['name'], FieldsFrom<E>>;
|
|
1615
|
+
make: <const Name extends string, const F extends Schema.Struct.Fields & {
|
|
1616
|
+
readonly id: Schema.Schema<unknown>;
|
|
1617
|
+
}>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
|
|
1618
|
+
/** A relation to a known entity, decoded as a reference. */
|
|
1619
|
+
ref: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<EntityRef<Name, F>, RefKey<Name>>;
|
|
1620
|
+
/** A relation by name, for recursive or forward references. */
|
|
1621
|
+
refTo: <Name extends string>(name: Name) => Schema.Codec<EntityRef<Name>, RefKey<Name>>;
|
|
1622
|
+
/**
|
|
1623
|
+
* The wire key a relation field carries (`"Entity:id"`). Adapters that read a
|
|
1624
|
+
* foreign key emit this so the ref codec can decode it on the client.
|
|
1625
|
+
*/
|
|
1626
|
+
refKey: (ref: {
|
|
1627
|
+
readonly entity: string;
|
|
1628
|
+
readonly id: string;
|
|
1629
|
+
}) => string;
|
|
1630
|
+
/** Splits a ref key back into its entity and id. */
|
|
1631
|
+
refParts: typeof refParts;
|
|
1632
|
+
/** A relation value of one authoritative page of refs. */
|
|
1633
|
+
refPage: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<RefPage<Name, F>, {
|
|
1634
|
+
readonly refs: ReadonlyArray<string>;
|
|
1635
|
+
readonly hasNext: boolean;
|
|
1636
|
+
readonly hasPrevious: boolean;
|
|
1637
|
+
}>;
|
|
1638
|
+
/**
|
|
1639
|
+
* A normalized patch for an entity, typed against its fields' wire shape:
|
|
1640
|
+
* write a relation as its ref key (`Entity.refKey`), as the server does.
|
|
1641
|
+
*/
|
|
1642
|
+
patch: <Name extends string, F extends Schema.Struct.Fields>(ref: EntityRef<Name, F>, patch: Partial<Schema.Struct.Encoded<F>>) => EntityPatch<Name, F>;
|
|
1643
|
+
};
|
|
1644
|
+
//#endregion
|
|
1645
|
+
//#region src/matching.d.ts
|
|
1956
1646
|
/**
|
|
1957
|
-
*
|
|
1958
|
-
*
|
|
1959
|
-
*
|
|
1647
|
+
* An answer over the rows the client holds — never over the rows that exist.
|
|
1648
|
+
*
|
|
1649
|
+
* `complete` is the whole reason this is its own type rather than a `Page`. A
|
|
1650
|
+
* `Page` carries `hasNext`/`hasPrevious`, which are facts the *server* stated
|
|
1651
|
+
* about rows beyond the ones it delivered; a local answer has no such facts and
|
|
1652
|
+
* cannot invent them. What it can say is whether the population it judged was
|
|
1653
|
+
* all of it, which is decidable: a connection terminal at both ends is wholly
|
|
1654
|
+
* held, and nothing was skipped for a missing field.
|
|
1655
|
+
*
|
|
1656
|
+
* An incomplete answer is not wrong — it is an answer about less than the
|
|
1657
|
+
* caller may have meant, and the flag is what lets a view say "3 so far" rather
|
|
1658
|
+
* than "3", or a caller decide to ask the server.
|
|
1960
1659
|
*/
|
|
1961
|
-
|
|
1660
|
+
interface Matched<A> {
|
|
1661
|
+
readonly items: ReadonlyArray<A>;
|
|
1662
|
+
/** Whether every row the answer is about was judged. */
|
|
1663
|
+
readonly complete: boolean;
|
|
1664
|
+
}
|
|
1962
1665
|
/**
|
|
1963
|
-
*
|
|
1964
|
-
*
|
|
1965
|
-
*
|
|
1966
|
-
*
|
|
1666
|
+
* What the rows the client holds had to say about a body.
|
|
1667
|
+
*
|
|
1668
|
+
* `skipped` is the honest half. A row missing a field the body reads cannot be
|
|
1669
|
+
* judged — it is neither a match nor a non-match — and dropping it silently
|
|
1670
|
+
* would turn "I could not tell" into "no". Naming it lets a caller decide:
|
|
1671
|
+
* fetch the field, ask the server, or say the answer is partial.
|
|
1967
1672
|
*/
|
|
1968
|
-
|
|
1673
|
+
interface Judged {
|
|
1674
|
+
/** Keys of the rows that satisfy the body, in the order the body asks for. */
|
|
1675
|
+
readonly matched: ReadonlyArray<EntityKey>;
|
|
1676
|
+
/** Keys of rows held but missing a field the body reads, so not judged either way. */
|
|
1677
|
+
readonly skipped: ReadonlyArray<EntityKey>;
|
|
1678
|
+
}
|
|
1679
|
+
interface MatchingOptions {
|
|
1680
|
+
/**
|
|
1681
|
+
* Judge only these keys. Without it every row of the body's Entity in the
|
|
1682
|
+
* store is a candidate, which is what a filter over a loaded list wants; with
|
|
1683
|
+
* it, a caller narrows to a connection's own edges.
|
|
1684
|
+
*/
|
|
1685
|
+
readonly among?: ReadonlyArray<EntityKey> | undefined;
|
|
1686
|
+
}
|
|
1969
1687
|
/**
|
|
1970
|
-
*
|
|
1971
|
-
*
|
|
1972
|
-
*
|
|
1688
|
+
* The rows of `descriptor`'s Entity that the store holds and the body matches.
|
|
1689
|
+
*
|
|
1690
|
+
* The input is given **decoded**, as an application writes it, and encoded here
|
|
1691
|
+
* through the descriptor's own `Input` codec. That is deliberate and is the
|
|
1692
|
+
* whole reason this takes a descriptor rather than a bare body: a store holds
|
|
1693
|
+
* wire values, so an input has to be in that space to be compared against them,
|
|
1694
|
+
* and handing an interpreter a decoded value is a mistake **no runtime error
|
|
1695
|
+
* catches** — the reference interpreter answers "no rows", which reads exactly
|
|
1696
|
+
* like a correct answer. Doing it here means a caller cannot get it wrong.
|
|
1697
|
+
*
|
|
1698
|
+
* Literals in the body are deliberately *not* encoded. A literal written in
|
|
1699
|
+
* domain terms is already broken against the server, which binds it to a column
|
|
1700
|
+
* the same way; accepting it here would make the client quietly more permissive
|
|
1701
|
+
* than the thing it has to agree with.
|
|
1973
1702
|
*/
|
|
1974
|
-
declare const
|
|
1703
|
+
declare const matching: <Name extends string, Input>(store: EntityStore, descriptor: QueryDescriptor<Name, Input, unknown>, input: Input, options?: MatchingOptions) => Judged;
|
|
1975
1704
|
/**
|
|
1976
|
-
*
|
|
1977
|
-
*
|
|
1978
|
-
*
|
|
1979
|
-
*
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
*
|
|
1983
|
-
*
|
|
1705
|
+
* Whether one row belongs to a query, as far as the client can tell.
|
|
1706
|
+
*
|
|
1707
|
+
* Three answers, and the third is the one that makes this usable. `'unknown'`
|
|
1708
|
+
* is a row the store never fetched, or holds without a field the body reads —
|
|
1709
|
+
* a caller that collapses it into `'no'` has turned "I could not tell" into an
|
|
1710
|
+
* answer, which is the mistake this whole module is shaped against.
|
|
1711
|
+
*
|
|
1712
|
+
* **Membership is decidable where position is not.** Whether a row satisfies
|
|
1713
|
+
* `eq`, `isNull` or `contains` needs no collation: equality on text is exact
|
|
1714
|
+
* and `contains` folds ASCII, both stated in §6.0.1. *Where* a row sorts needs
|
|
1715
|
+
* text collation, which is the backend's and deliberately outside the
|
|
1716
|
+
* conformant subset — so this answers the half that is always answerable, and
|
|
1717
|
+
* ordering stays the server's until a query can declare its collation.
|
|
1984
1718
|
*/
|
|
1985
|
-
|
|
1986
|
-
/** Whether this field's last read failed and nothing has settled it since. */
|
|
1987
|
-
declare const isFieldFailed: (model: RemoteModel, entity: string, id: string, field: string) => boolean;
|
|
1719
|
+
type Belongs = 'yes' | 'no' | 'unknown';
|
|
1988
1720
|
/**
|
|
1989
|
-
*
|
|
1990
|
-
*
|
|
1991
|
-
*
|
|
1721
|
+
* Takes the input **encoded**, because its one caller holds it that way: a
|
|
1722
|
+
* connection identity carries the canonical encoded input, and making it decode
|
|
1723
|
+
* only for this to encode again would be a round trip that can fail.
|
|
1724
|
+
*
|
|
1725
|
+
* A decoded-input sibling was written first and deleted: nothing called it. The
|
|
1726
|
+
* asymmetry with `matching`, which takes a decoded input, is the shape of the
|
|
1727
|
+
* two real callers rather than an oversight.
|
|
1992
1728
|
*/
|
|
1993
|
-
declare const
|
|
1729
|
+
declare const belongsEncoded: <Name extends string, Input>(store: EntityStore, descriptor: QueryDescriptor<Name, Input, unknown>, encoded: Readonly<Record<string, unknown>>, key: EntityKey) => Belongs;
|
|
1730
|
+
//#endregion
|
|
1731
|
+
//#region src/retain.d.ts
|
|
1732
|
+
/** A connection to keep: its identity, and what a page of it selects of each item, if a projection reads it. */
|
|
1733
|
+
interface ConnectionRoot {
|
|
1734
|
+
readonly identity: string;
|
|
1735
|
+
readonly select?: RelationRequirement | undefined;
|
|
1736
|
+
}
|
|
1737
|
+
interface RetentionRoots {
|
|
1738
|
+
readonly requirements: ReadonlyArray<Requirement>;
|
|
1739
|
+
/** Connections (`QueryRef.identity`) to keep, with their edges' targets and what `select` reaches through them. */
|
|
1740
|
+
readonly connections: ReadonlyArray<ConnectionRoot>;
|
|
1741
|
+
}
|
|
1742
|
+
interface Retained {
|
|
1743
|
+
readonly entities: EntityStore;
|
|
1744
|
+
readonly connections: Readonly<Record<string, Connection>>;
|
|
1745
|
+
readonly optimistic: OptimisticState;
|
|
1746
|
+
}
|
|
1994
1747
|
/**
|
|
1995
|
-
* The
|
|
1996
|
-
*
|
|
1997
|
-
* that consults it shows `Failed` for a related entity's failure too, rather
|
|
1998
|
-
* than waiting on a field nothing will fetch.
|
|
1748
|
+
* The entity keys the roots reach: each root entity, the targets its retained
|
|
1749
|
+
* fields refer to, and recursively the targets a nested relation selects.
|
|
1999
1750
|
*/
|
|
2000
|
-
declare const
|
|
1751
|
+
declare const reachable: (store: EntityStore, roots: RetentionRoots, connections: Readonly<Record<string, Connection>>, optimistic: OptimisticState, pending: ReadonlySet<string>) => ReadonlySet<EntityKey>;
|
|
2001
1752
|
/**
|
|
2002
|
-
*
|
|
2003
|
-
*
|
|
2004
|
-
*
|
|
2005
|
-
* accumulates rather than replaces. Every read path should use this rather than
|
|
2006
|
-
* reducing `writeEntity` by hand.
|
|
1753
|
+
* Drops every entity the roots do not reach, every connection they do not
|
|
1754
|
+
* name, and every settled overlay on a dropped connection, keeping whatever a
|
|
1755
|
+
* pending request's layer or overlays touch. Pure.
|
|
2007
1756
|
*/
|
|
2008
|
-
declare const
|
|
1757
|
+
declare const gc: (state: Retained & {
|
|
1758
|
+
readonly mutations: MutationState;
|
|
1759
|
+
}, roots: RetentionRoots) => Retained;
|
|
2009
1760
|
//#endregion
|
|
2010
|
-
//#region src/
|
|
1761
|
+
//#region src/persistence.d.ts
|
|
1762
|
+
/** Bump when the serialized shape changes; a mismatch discards the cache. */
|
|
1763
|
+
declare const REMOTE_CACHE_VERSION = 5;
|
|
2011
1764
|
/**
|
|
2012
|
-
*
|
|
2013
|
-
*
|
|
1765
|
+
* What survives a reload: the entity cache, and the connections an application
|
|
1766
|
+
* **declared** should come back.
|
|
1767
|
+
*
|
|
1768
|
+
* Connections are session state by default and stay that way — `snapshotOf`
|
|
1769
|
+
* takes none unless asked. What a declared one keeps is its **edges and
|
|
1770
|
+
* nothing else**, which is not a simplification but the rule: a connection's
|
|
1771
|
+
* boundaries are cursors the server minted, and a cursor may name server state
|
|
1772
|
+
* that no longer exists. Restoring one would be claiming to know where the
|
|
1773
|
+
* page ends. The shape has nowhere to put a cursor, so that cannot be got
|
|
1774
|
+
* wrong later.
|
|
2014
1775
|
*/
|
|
2015
|
-
interface
|
|
2016
|
-
readonly
|
|
2017
|
-
/** The metadata key names whose reads this part resumes. */
|
|
2018
|
-
readonly covers: ReadonlyArray<string>;
|
|
2019
|
-
readonly capture: (model: AppModel, projections: ReadonlyArray<{
|
|
2020
|
-
readonly metadata: Metadata;
|
|
2021
|
-
}>) => unknown;
|
|
2022
|
-
readonly restore: (model: AppModel, value: unknown) => Result.Result<AppModel, string>;
|
|
2023
|
-
/** Whether a Subscription entry is one of this domain's, which may start late. */
|
|
2024
|
-
readonly deferrable: (key: string, entry: unknown) => boolean;
|
|
2025
|
-
}
|
|
2026
|
-
//#endregion
|
|
2027
|
-
//#region src/coalesce.d.ts
|
|
2028
|
-
type Batch = Schema.Schema.Type<typeof ReadBatch>;
|
|
2029
|
-
type BatchResult = Schema.Schema.Type<typeof ReadBatchResult>;
|
|
2030
|
-
type ReadError = RemoteReadError | RemoteProtocolError;
|
|
2031
|
-
type BatchRead = (batch: Batch) => Effect.Effect<BatchResult, ReadError>;
|
|
2032
|
-
type QueryRequestValue = Schema.Schema.Type<typeof QueryRequest>;
|
|
2033
|
-
type QueryResultValue = Schema.Schema.Type<typeof QueryResult>;
|
|
2034
|
-
type QueryRun = (request: QueryRequestValue) => Effect.Effect<QueryResultValue, RemoteQueryError>;
|
|
2035
|
-
interface CoalesceOptions {
|
|
1776
|
+
interface Snapshot {
|
|
1777
|
+
readonly entities: EntityStore;
|
|
2036
1778
|
/**
|
|
2037
|
-
*
|
|
2038
|
-
*
|
|
1779
|
+
* By connection identity: its **segments**, each a run of edges. No
|
|
1780
|
+
* boundaries.
|
|
1781
|
+
*
|
|
1782
|
+
* Segments rather than one flat list, because the gaps between them are
|
|
1783
|
+
* knowledge too. A connection paged from both ends holds a head and a tail
|
|
1784
|
+
* with an unfetched middle; flattening those into one run would claim the
|
|
1785
|
+
* tail's first row follows the head's last, which is a thing the client was
|
|
1786
|
+
* never told.
|
|
2039
1787
|
*/
|
|
2040
|
-
readonly
|
|
1788
|
+
readonly connections: Readonly<Record<string, ReadonlyArray<ReadonlyArray<Edge>>>>;
|
|
2041
1789
|
}
|
|
2042
|
-
/** A stable key for a requirement, so an equal requirement in flight is joined. */
|
|
2043
|
-
declare const requirementKey: (requirement: Requirement) => string;
|
|
2044
|
-
/**
|
|
2045
|
-
* Wraps a raw query so that an identical query in flight (same query, input,
|
|
2046
|
-
* and window) is joined rather than run again; distinct queries run
|
|
2047
|
-
* concurrently. A page answers exactly one window, so nothing is batched.
|
|
2048
|
-
*/
|
|
2049
|
-
declare const coalesceQueries: (query: QueryRun, options?: CoalesceOptions) => Effect.Effect<QueryRun>;
|
|
2050
1790
|
/**
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
1791
|
+
* A snapshot of a Model, keeping the entity cache and only the connections
|
|
1792
|
+
* named.
|
|
1793
|
+
*
|
|
1794
|
+
* Naming none — the default — is exactly what Remote did before connections
|
|
1795
|
+
* could be kept at all: a disposable, server-derived cache.
|
|
2054
1796
|
*/
|
|
2055
|
-
declare const
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
readonly
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
1797
|
+
declare const snapshotOf: (model: {
|
|
1798
|
+
readonly entities: EntityStore;
|
|
1799
|
+
readonly connections: Readonly<Record<string, Connection>>;
|
|
1800
|
+
}, options?: {
|
|
1801
|
+
readonly connections?: ReadonlyArray<ConnectionIdentity> | undefined;
|
|
1802
|
+
}) => Snapshot;
|
|
1803
|
+
interface SnapshotOptions {
|
|
1804
|
+
/**
|
|
1805
|
+
* Who or what the snapshot is for (a user id, a tenant, a build). A snapshot
|
|
1806
|
+
* taken under another scope is discarded rather than shown to the wrong
|
|
1807
|
+
* reader. Default: unscoped, which only matches unscoped.
|
|
1808
|
+
*/
|
|
1809
|
+
readonly scope?: string | undefined;
|
|
1810
|
+
/** Snapshots larger than this many bytes are not written and not read. */
|
|
1811
|
+
readonly maxBytes?: number | undefined;
|
|
1812
|
+
}
|
|
1813
|
+
/** How a snapshot meets a store that already has entries. */
|
|
1814
|
+
type MergePolicy = 'replace' | 'preserve-existing';
|
|
2067
1815
|
/**
|
|
2068
|
-
* The
|
|
2069
|
-
*
|
|
1816
|
+
* The snapshot text, or `undefined` when it would exceed `maxBytes`. Build the
|
|
1817
|
+
* snapshot with `snapshotOf`, which is where the connections that survive are
|
|
1818
|
+
* named; runtime state — optimistic layers, live cursors, gaps, the mutation
|
|
1819
|
+
* ledger — is never in one.
|
|
2070
1820
|
*/
|
|
2071
|
-
declare
|
|
1821
|
+
declare function dehydrate(snapshot: Snapshot, options?: SnapshotOptions & {
|
|
1822
|
+
readonly maxBytes?: undefined;
|
|
1823
|
+
}): string;
|
|
1824
|
+
declare function dehydrate(snapshot: Snapshot, options?: SnapshotOptions): string | undefined;
|
|
2072
1825
|
/**
|
|
2073
|
-
* The
|
|
2074
|
-
*
|
|
2075
|
-
*
|
|
2076
|
-
* own `R`, so the two sides cannot drift apart.
|
|
2077
|
-
*
|
|
2078
|
-
* `TransportError` is what the transport itself may fail with on top of the
|
|
2079
|
-
* declared errors: `RpcClientError` for the client `RpcClient.make` builds,
|
|
2080
|
-
* `never` for in-process handlers.
|
|
1826
|
+
* The store a snapshot text holds, or `undefined` when the text is missing,
|
|
1827
|
+
* oversized, not this version, for another scope, or malformed. Hydrating the
|
|
1828
|
+
* same text twice yields equal stores.
|
|
2081
1829
|
*/
|
|
2082
|
-
|
|
2083
|
-
readonly FoldkitRemoteRead: (payload: Schema.Schema.Type<typeof ReadBatch>) => Effect.Effect<Schema.Schema.Type<typeof ReadBatchResult>, RemoteReadError | RemoteProtocolError | TransportError, R>;
|
|
2084
|
-
readonly FoldkitRemoteQuery: (payload: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError | TransportError, R>;
|
|
2085
|
-
readonly FoldkitRemoteMutate: (payload: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError | RemoteForbidden | TransportError, R>;
|
|
2086
|
-
readonly FoldkitRemoteLive: (payload: Schema.Schema.Type<typeof LiveRequirement>) => Stream.Stream<Schema.Schema.Type<typeof LiveChange>, RemoteLiveError | RemoteProtocolError | TransportError, R>;
|
|
2087
|
-
}
|
|
2088
|
-
/** Reconstructs the client's `ConnectionChange` from the wire's flattened edge. */
|
|
2089
|
-
declare const connectionChangeOf: (change: Schema.Schema.Type<typeof ConnectionChangeSchema>) => ConnectionChange;
|
|
2090
|
-
/** Reconstructs the client's `LiveEvent` from the wire's flattened `LiveChange`. */
|
|
2091
|
-
declare const liveEventOf: (change: Schema.Schema.Type<typeof LiveChange>) => LiveEvent;
|
|
2092
|
-
declare const remoteError: (error: {
|
|
2093
|
-
readonly _tag: string;
|
|
2094
|
-
readonly message: string;
|
|
2095
|
-
readonly refusal?: unknown;
|
|
2096
|
-
readonly reason?: string | undefined;
|
|
2097
|
-
}) => RemoteError;
|
|
2098
|
-
declare const coalescedLayer: <E, R>(layer: Layer.Layer<RemoteClient, E, R>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, E, R>;
|
|
1830
|
+
declare const hydrate: (raw: string | undefined | null, options?: SnapshotOptions) => Snapshot | undefined;
|
|
2099
1831
|
/**
|
|
2100
|
-
*
|
|
2101
|
-
*
|
|
1832
|
+
* Brings a snapshot into a store that may already hold entries. `replace`
|
|
1833
|
+
* takes the snapshot's entry for every key it has; `preserve-existing` keeps
|
|
1834
|
+
* an entry the current store already has (it is at least as fresh as a
|
|
1835
|
+
* snapshot taken earlier). Either way, keys only the current store has stay.
|
|
2102
1836
|
*/
|
|
2103
|
-
declare const
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
1837
|
+
declare const mergeStores: (current: EntityStore, snapshot: EntityStore, policy: MergePolicy) => EntityStore;
|
|
1838
|
+
declare const RemotePersistence: {
|
|
1839
|
+
/** The snapshot text, or `undefined` when it would exceed `maxBytes`. */
|
|
1840
|
+
dehydrate: typeof dehydrate;
|
|
1841
|
+
/** What a snapshot text holds, or `undefined` when it is refused. */
|
|
1842
|
+
hydrate: typeof hydrate;
|
|
1843
|
+
/**
|
|
1844
|
+
* What to keep of a Model, naming the connections that should survive a
|
|
1845
|
+
* reload. Naming none is the default and is what Remote always did.
|
|
1846
|
+
*/
|
|
1847
|
+
snapshotOf: typeof snapshotOf;
|
|
1848
|
+
/** A snapshot's entities brought into a store by policy. */
|
|
1849
|
+
mergeStores: typeof mergeStores;
|
|
1850
|
+
/** The cache as a fresh session has it; what a refused `restore` yields. */
|
|
1851
|
+
emptySnapshot: Snapshot;
|
|
1852
|
+
/**
|
|
1853
|
+
* Writes the snapshot under `key`, or removes the key when the store would
|
|
1854
|
+
* exceed `maxBytes`, so a stale smaller snapshot cannot outlive a larger
|
|
1855
|
+
* store it no longer describes.
|
|
1856
|
+
*/
|
|
1857
|
+
save: (snapshot: Snapshot, options: {
|
|
1858
|
+
readonly key: string;
|
|
1859
|
+
} & SnapshotOptions) => Effect.Effect<void, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
|
|
1860
|
+
/**
|
|
1861
|
+
* Reads the cache. A missing key yields `emptySnapshot`; anything `hydrate`
|
|
1862
|
+
* refuses yields `emptySnapshot` and removes the key, so the next `restore`
|
|
1863
|
+
* is clean and the planner refetches.
|
|
1864
|
+
*/
|
|
1865
|
+
restore: (options: {
|
|
1866
|
+
readonly key: string;
|
|
1867
|
+
} & SnapshotOptions) => Effect.Effect<Snapshot, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
|
|
1868
|
+
};
|
|
2118
1869
|
//#endregion
|
|
2119
|
-
//#region src/
|
|
2120
|
-
/** A request: which of Remote's calls, and its payload as the RPC protocol encodes it. */
|
|
2121
|
-
declare const RemoteJsonRequest: Schema.Struct<{
|
|
2122
|
-
readonly operation: Schema.Literals<readonly ["read", "query", "mutate"]>;
|
|
2123
|
-
readonly payload: Schema.Unknown;
|
|
2124
|
-
}>;
|
|
2125
|
-
type RemoteJsonRequest = typeof RemoteJsonRequest.Type;
|
|
2126
|
-
/** An answer: the call's result, or why there is none. */
|
|
2127
|
-
declare const RemoteJsonAnswer: Schema.Union<readonly [Schema.Struct<{
|
|
2128
|
-
readonly result: Schema.Unknown;
|
|
2129
|
-
}>, Schema.Struct<{
|
|
2130
|
-
readonly error: Schema.String;
|
|
2131
|
-
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
2132
|
-
/** Who is asking was refused, with the application's reason when it gave one. */
|
|
2133
|
-
readonly forbidden: Schema.optional<Schema.Struct<{
|
|
2134
|
-
readonly reason: Schema.optional<Schema.String>;
|
|
2135
|
-
}>>;
|
|
2136
|
-
}>]>;
|
|
2137
|
-
type RemoteJsonAnswer = typeof RemoteJsonAnswer.Type;
|
|
1870
|
+
//#region src/model.d.ts
|
|
2138
1871
|
/**
|
|
2139
|
-
*
|
|
2140
|
-
*
|
|
1872
|
+
* The normalized cache as a Foldkit Submodel. `Remote.define` returns a schema
|
|
1873
|
+
* and an `update` for this shape; `updateRemote` reconciles every producer.
|
|
2141
1874
|
*/
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
/**
|
|
2146
|
-
|
|
2147
|
-
/**
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
1875
|
+
interface RemoteModel {
|
|
1876
|
+
/** Entity values, presence, staleness, tombstones, and applied windows. */
|
|
1877
|
+
readonly entities: EntityStore;
|
|
1878
|
+
/** Normalized ordered connections, keyed by connection identity. */
|
|
1879
|
+
readonly connections: Readonly<Record<string, Connection>>;
|
|
1880
|
+
/**
|
|
1881
|
+
* How many rows `Data.more` has grown a read's window to, by
|
|
1882
|
+
* `windowGrowthKey`. A read shows at most its window, so this is what "load
|
|
1883
|
+
* more" changes; it lives here because a list holds no state of its own.
|
|
1884
|
+
*/
|
|
1885
|
+
readonly grown: Readonly<Record<string, number>>;
|
|
1886
|
+
/** Optimistic entity layers and connection overlays over the base store. */
|
|
1887
|
+
readonly optimistic: OptimisticState;
|
|
1888
|
+
/** Live cursor and boundary state, keyed by the subscription's stream key. */
|
|
1889
|
+
readonly live: Readonly<Record<string, LiveState>>;
|
|
1890
|
+
/** Mutation pending/applied/failed ledger. */
|
|
1891
|
+
readonly mutations: MutationState;
|
|
1892
|
+
/**
|
|
1893
|
+
* Streams that broke, by an error or by an event ahead of their cursor, and
|
|
1894
|
+
* have not resubscribed since: changes after the break are missed until the
|
|
1895
|
+
* live entry restarts them and refetches what they cover.
|
|
1896
|
+
*/
|
|
1897
|
+
readonly gaps: ReadonlySet<string>;
|
|
1898
|
+
/** Each live stream that has ever broken, by stream key. One that never broke is absent. */
|
|
1899
|
+
readonly streams: Readonly<Record<string, StreamHealth>>;
|
|
1900
|
+
/**
|
|
1901
|
+
* The `entity\0id\0field` marks a read is currently fetching. A field absent
|
|
1902
|
+
* from the store reads as `Loading` while its mark is here and `Initial`
|
|
1903
|
+
* otherwise, which is what separates "being fetched" from "nothing is
|
|
1904
|
+
* fetching this".
|
|
1905
|
+
*/
|
|
1906
|
+
readonly loading: ReadonlySet<string>;
|
|
1907
|
+
/**
|
|
1908
|
+
* `Remote.refresh` generations, held per field rather than for the store as a
|
|
1909
|
+
* whole. A read entry restarts when the generation over the fields it plans
|
|
1910
|
+
* moves, so a read sent before a refresh of its own fields cannot land after
|
|
1911
|
+
* it, and a refresh of one field leaves every other entry's read alone.
|
|
1912
|
+
*/
|
|
1913
|
+
readonly refresh: RefreshState;
|
|
1914
|
+
/**
|
|
1915
|
+
* The reads that failed and have not been settled since, so a read can say
|
|
1916
|
+
* `Failed` rather than `Initial`.
|
|
1917
|
+
*
|
|
1918
|
+
* Without them a read that failed before anything loaded read exactly like
|
|
1919
|
+
* one nobody had asked for, and nothing asked again: a read entry restarts
|
|
1920
|
+
* only when what it plans changes, and a failure changed nothing. What failed
|
|
1921
|
+
* is not planned again on its own either, so a persistent error is not
|
|
1922
|
+
* retried every time an unrelated read restarts the entry. `Remote.refresh`
|
|
1923
|
+
* is how a view retries.
|
|
1924
|
+
*/
|
|
1925
|
+
readonly failures: Failures;
|
|
1926
|
+
/**
|
|
1927
|
+
* The storage key the cache was last restored from, through `Hydrated`'s
|
|
1928
|
+
* `from`. `Data.persistence` saves under a key only once its own snapshot is
|
|
1929
|
+
* in, so a save at startup cannot write the empty store over it.
|
|
1930
|
+
*/
|
|
1931
|
+
readonly restoredFrom: Option.Option<string>;
|
|
1932
|
+
/**
|
|
1933
|
+
* Under `verifyPlacement`, the order each list was placed in, by edge key,
|
|
1934
|
+
* and the rows placing took out of its first page, until the server's page
|
|
1935
|
+
* for it arrives to be compared with them.
|
|
1936
|
+
*/
|
|
1937
|
+
readonly placed: Readonly<Record<string, PlacedOrder>>;
|
|
1938
|
+
/** Under `verifyPlacement`, each placement the server's page disagreed with. */
|
|
1939
|
+
readonly placementMismatches: ReadonlyArray<PlacementMismatch>;
|
|
2151
1940
|
}
|
|
2152
|
-
/**
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
* `http` sends them, live as `liveFetch` streams it, for `clientLayer`.
|
|
2157
|
-
*/
|
|
2158
|
-
declare const httpWithLive: (url: string, options?: LiveFetchOptions) => RemoteRpcClient;
|
|
2159
|
-
//#endregion
|
|
2160
|
-
//#region src/relation.d.ts
|
|
2161
|
-
interface RefParts {
|
|
2162
|
-
readonly entity: string;
|
|
2163
|
-
readonly id: string;
|
|
1941
|
+
/** A list's first page as the client placed it: its keys in order, and those it took out. */
|
|
1942
|
+
interface PlacedOrder {
|
|
1943
|
+
readonly order: ReadonlyArray<string>;
|
|
1944
|
+
readonly dropped: ReadonlyArray<string>;
|
|
2164
1945
|
}
|
|
2165
|
-
/** A
|
|
2166
|
-
interface
|
|
2167
|
-
readonly
|
|
2168
|
-
|
|
2169
|
-
readonly
|
|
1946
|
+
/** A list the client placed rows in one order and the server then listed in another. */
|
|
1947
|
+
interface PlacementMismatch {
|
|
1948
|
+
readonly connection: string;
|
|
1949
|
+
/** The keys as placed, as far as the server's page reached. */
|
|
1950
|
+
readonly placed: ReadonlyArray<string>;
|
|
1951
|
+
/** The keys of the server's first page. */
|
|
1952
|
+
readonly served: ReadonlyArray<string>;
|
|
2170
1953
|
}
|
|
2171
|
-
/**
|
|
2172
|
-
|
|
2173
|
-
/**
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
readonly
|
|
2179
|
-
readonly entity: string;
|
|
1954
|
+
/** How a live stream has fared, as its live entry restarts it. */
|
|
1955
|
+
interface StreamHealth {
|
|
1956
|
+
/** How many times it broke. The live entry restarts on each, so it only grows. */
|
|
1957
|
+
readonly restarts: number;
|
|
1958
|
+
/** Breaks since its last applied event: what the restart's backoff grows with. */
|
|
1959
|
+
readonly failures: number;
|
|
1960
|
+
/** Why it last broke; none for a gap, which is not an error. */
|
|
1961
|
+
readonly error: Option.Option<RemoteError>;
|
|
2180
1962
|
}
|
|
2181
1963
|
/**
|
|
2182
|
-
*
|
|
2183
|
-
*
|
|
2184
|
-
*
|
|
2185
|
-
*
|
|
2186
|
-
*
|
|
2187
|
-
*
|
|
2188
|
-
*
|
|
2189
|
-
|
|
2190
|
-
declare const RELATION_ALIAS = "@";
|
|
2191
|
-
/** The alias a relation field is read under, for a window of this size. */
|
|
2192
|
-
declare const relationAlias: (field: string, window: {
|
|
2193
|
-
readonly first?: number | undefined;
|
|
2194
|
-
readonly last?: number | undefined;
|
|
2195
|
-
readonly after?: string | undefined;
|
|
2196
|
-
readonly before?: string | undefined;
|
|
2197
|
-
}) => string;
|
|
2198
|
-
/** The field an alias reads; a name that is no alias is its own field. */
|
|
2199
|
-
declare const aliasedField: (name: string) => string;
|
|
2200
|
-
/** Splits a ref key (`"Entity:id"`, the store key too) back into its parts. */
|
|
2201
|
-
declare const refParts: (encoded: string) => RefParts;
|
|
2202
|
-
/**
|
|
2203
|
-
* The refs a relation value carries, in order. Anything that is not a ref key,
|
|
2204
|
-
* an array of them, or a page of them contributes nothing.
|
|
1964
|
+
* Failed reads, as the errors they failed with.
|
|
1965
|
+
*
|
|
1966
|
+
* `connections` is by connection identity, and is settled by a page arriving,
|
|
1967
|
+
* an invalidation, or retention dropping the connection. `fields` is by field
|
|
1968
|
+
* mark (`entity\0id\0field`, the marks `loading` uses), and is settled by the
|
|
1969
|
+
* field being written again, a refresh asking for it, or retention dropping the
|
|
1970
|
+
* entity. A read of it in flight reads `Loading` over the failure without
|
|
1971
|
+
* settling it: if that read fails too, the failure is simply recorded again.
|
|
2205
1972
|
*/
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
1973
|
+
interface Failures {
|
|
1974
|
+
readonly connections: Readonly<Record<string, RemoteError>>;
|
|
1975
|
+
readonly fields: Readonly<Record<string, RemoteError>>;
|
|
1976
|
+
}
|
|
1977
|
+
declare const noFailures: Failures;
|
|
2210
1978
|
/**
|
|
2211
|
-
*
|
|
2212
|
-
*
|
|
2213
|
-
*
|
|
1979
|
+
* `Remote.refresh` generations, per field mark. `generation` is the last one
|
|
1980
|
+
* handed out; `requested` is when each field was last refreshed, and `started`
|
|
1981
|
+
* is the generation each field's read last began under. Holding them per field
|
|
1982
|
+
* is what keeps one Projection's refresh from restarting every read entry.
|
|
2214
1983
|
*/
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
1984
|
+
interface RefreshState {
|
|
1985
|
+
readonly generation: number;
|
|
1986
|
+
readonly requested: ReadonlyMap<string, number>;
|
|
1987
|
+
readonly started: ReadonlyMap<string, number>;
|
|
1988
|
+
/**
|
|
1989
|
+
* The generation every entry is refreshed at, at least: `forgetRemote` moves
|
|
1990
|
+
* it, so every read and live entry restarts, and a read or stream begun for
|
|
1991
|
+
* the principal before is interrupted rather than landing after.
|
|
1992
|
+
*/
|
|
1993
|
+
readonly floor: number;
|
|
2223
1994
|
}
|
|
1995
|
+
declare const emptyRefresh: RefreshState;
|
|
2224
1996
|
/**
|
|
2225
|
-
* The
|
|
2226
|
-
*
|
|
2227
|
-
*
|
|
1997
|
+
* The Model with everything the server told it forgotten: values, tombstones,
|
|
1998
|
+
* unavailable fields, connections, live cursors, failures, and what is in
|
|
1999
|
+
* flight. For a change of principal, whose facts these were. The mutation
|
|
2000
|
+
* sequence is kept, so request ids stay unique, and a mutation in flight is
|
|
2001
|
+
* treated as applied: its answer, when it comes, writes nothing here.
|
|
2228
2002
|
*/
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
readonly
|
|
2236
|
-
|
|
2237
|
-
readonly
|
|
2238
|
-
|
|
2239
|
-
readonly
|
|
2240
|
-
|
|
2241
|
-
readonly
|
|
2242
|
-
}
|
|
2243
|
-
/** Flattens a mapped type so hovers show the picked fields, not the machinery. */
|
|
2244
|
-
type Simplify<T> = T extends (infer O) ? { readonly [K in keyof O]: O[K]; } : never;
|
|
2245
|
-
/** The value a Selection reads: `Selection.Value<typeof ProjectCard>`. */
|
|
2246
|
-
type SelectionValueOf<S> = S extends Selection<infer V, any, any> ? V : never;
|
|
2247
|
-
/** The nested selections a relation field admits: of its target entity, in the shapes its value takes. */
|
|
2248
|
-
type NestedFor<Field> = Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef<infer Name, any>> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends RefPage<infer Name, any> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends EntityRef<infer Name, any> ? Selection<unknown, Name, 'entity'> : never;
|
|
2249
|
-
/** What a selection of an entity with fields `F` may pick: `true` per scalar, a nested selection per relation. */
|
|
2250
|
-
type SelectionOf<F extends Schema.Struct.Fields> = { readonly [K in keyof F]?: true | NestedFor<Schema.Schema.Type<F[K]>>; };
|
|
2251
|
-
/** `T | null` when the field admits `null` or `undefined` (both assemble to `null`). */
|
|
2252
|
-
type Nullable<Field, T> = [Extract<Field, null | undefined>] extends [never] ? T : T | null;
|
|
2253
|
-
/** A nested selection's value takes the shape of the field it selects through. */
|
|
2254
|
-
type NestedValue<Field, Sel> = Sel extends Selection<infer V, string, 'connection'> ? Nullable<Field, V> : Sel extends Selection<infer V, string, 'entity'> ? Nullable<Field, Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef<any, any>> ? ReadonlyArray<V> : Exclude<Field, null | undefined> extends RefPage<any, any> ? Page<V> : V> : never;
|
|
2255
|
-
/** The value a selection `Sel` of fields `F` reads. */
|
|
2256
|
-
type SelectionValue<F extends Schema.Struct.Fields, Sel> = Simplify<{ readonly [K in keyof Sel & keyof F]: Sel[K] extends true ? Schema.Schema.Type<F[K]> : NestedValue<Schema.Schema.Type<F[K]>, Sel[K]>; }>;
|
|
2257
|
-
declare const pageSchema: (item: AnySchema) => AnySchema;
|
|
2258
|
-
/** The requirement a nested selection contributes for its relation's target. */
|
|
2259
|
-
declare const relationOf: (selection: Selection<unknown>) => RelationRequirement;
|
|
2260
|
-
declare const Selection: {
|
|
2003
|
+
declare const forgetRemote: (model: RemoteModel) => RemoteModel;
|
|
2004
|
+
declare const initialRemoteModel: RemoteModel;
|
|
2005
|
+
declare const remoteModelSchema: () => Schema.Codec<RemoteModel, unknown>;
|
|
2006
|
+
/** The submodel's Messages; each reduces to `RemoteModel` through `updateRemote`. */
|
|
2007
|
+
type RemoteMessage = {
|
|
2008
|
+
readonly _tag: 'ReadReceived';
|
|
2009
|
+
readonly requests: readonly Requirement[];
|
|
2010
|
+
readonly result: Schema.Schema.Type<typeof ReadBatchResult>;
|
|
2011
|
+
readonly now: number;
|
|
2012
|
+
} | {
|
|
2013
|
+
readonly _tag: 'ReadFailed';
|
|
2014
|
+
readonly requests: readonly Requirement[];
|
|
2015
|
+
readonly error: RemoteError;
|
|
2261
2016
|
/**
|
|
2262
|
-
* The
|
|
2263
|
-
*
|
|
2017
|
+
* The live stream whose subscription broke, when this is that rather
|
|
2018
|
+
* than a read. Nothing was being read, so no field failed: the stream is
|
|
2019
|
+
* recorded as a gap, since changes after it are missed until the live
|
|
2020
|
+
* entry restarts it.
|
|
2264
2021
|
*/
|
|
2265
|
-
|
|
2022
|
+
readonly stream?: string | undefined;
|
|
2023
|
+
} |
|
|
2024
|
+
/** A refetch of present fields began; they read as `Refreshing` until it lands. */
|
|
2025
|
+
{
|
|
2026
|
+
readonly _tag: 'RefreshStarted';
|
|
2027
|
+
readonly requests: readonly Requirement[];
|
|
2028
|
+
} |
|
|
2029
|
+
/** A read began; the fields it asks for that the store lacks read as `Loading`. */
|
|
2030
|
+
{
|
|
2031
|
+
readonly _tag: 'ReadStarted';
|
|
2032
|
+
readonly requests: readonly Requirement[];
|
|
2033
|
+
/** The refresh generation the read was planned under. */
|
|
2034
|
+
readonly refresh?: number | undefined;
|
|
2035
|
+
} |
|
|
2036
|
+
/**
|
|
2037
|
+
* Queries for these connections were sent. One with nothing to show reads
|
|
2038
|
+
* `Loading` until its page or its failure arrives, which is what separates
|
|
2039
|
+
* "being fetched" from `Initial`, "nothing is fetching this".
|
|
2040
|
+
*/
|
|
2041
|
+
{
|
|
2042
|
+
readonly _tag: 'QueryStarted';
|
|
2043
|
+
readonly connections: readonly string[];
|
|
2044
|
+
} |
|
|
2045
|
+
/** The active Surfaces' roots changed; everything they do not reach is collected. */
|
|
2046
|
+
{
|
|
2047
|
+
readonly _tag: 'RetentionChanged';
|
|
2048
|
+
readonly roots: RetentionRoots;
|
|
2049
|
+
} |
|
|
2050
|
+
/** A restored snapshot meets the store; runtime state is untouched. */
|
|
2051
|
+
{
|
|
2052
|
+
readonly _tag: 'Hydrated';
|
|
2053
|
+
readonly entities: EntityStore;
|
|
2266
2054
|
/**
|
|
2267
|
-
* The
|
|
2268
|
-
*
|
|
2269
|
-
*
|
|
2055
|
+
* The connections a snapshot declared should survive, as their edges.
|
|
2056
|
+
* Restored with **unknown** boundaries and marked stale: the rows show
|
|
2057
|
+
* at once and the connection is refetched, because a persisted cursor
|
|
2058
|
+
* may name server state that is gone.
|
|
2270
2059
|
*/
|
|
2271
|
-
|
|
2060
|
+
readonly connections?: Readonly<Record<string, ReadonlyArray<ReadonlyArray<Edge>>>> | undefined;
|
|
2061
|
+
readonly merge: MergePolicy;
|
|
2062
|
+
/** The storage key the snapshot was read from, when it was: `restoredFrom`. */
|
|
2063
|
+
readonly from?: string | undefined;
|
|
2064
|
+
} |
|
|
2065
|
+
/** A mutation began; its optimistic operations show until it settles. */
|
|
2066
|
+
{
|
|
2067
|
+
readonly _tag: 'MutationStarted';
|
|
2068
|
+
readonly requestId: string;
|
|
2069
|
+
readonly optimistic?: ReadonlyArray<OptimisticOperation> | undefined;
|
|
2070
|
+
} | {
|
|
2071
|
+
readonly _tag: 'MutationSucceeded';
|
|
2072
|
+
readonly requestId: string;
|
|
2073
|
+
readonly entities: readonly NormalizedPatch[];
|
|
2074
|
+
/** Connection changes the server confirmed; they replace the request's own. */
|
|
2075
|
+
readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
|
|
2076
|
+
/** Entities the mutation deleted: tombstoned, which hides them from every connection. */
|
|
2077
|
+
readonly deleted?: ReadonlyArray<{
|
|
2078
|
+
readonly entity: string;
|
|
2079
|
+
readonly id: string;
|
|
2080
|
+
}> | undefined;
|
|
2081
|
+
/** Injected clock reading of the answer: how fresh the written entities are. */
|
|
2082
|
+
readonly now: number;
|
|
2083
|
+
} | {
|
|
2084
|
+
readonly _tag: 'MutationFailed';
|
|
2085
|
+
readonly requestId: string;
|
|
2086
|
+
readonly error: RemoteError;
|
|
2087
|
+
} |
|
|
2088
|
+
/**
|
|
2089
|
+
* Operations shown over the store with no request behind them, until they are
|
|
2090
|
+
* lifted: a preview of a change nobody has made. Showing an id again replaces
|
|
2091
|
+
* what it showed.
|
|
2092
|
+
*/
|
|
2093
|
+
{
|
|
2094
|
+
readonly _tag: 'OverlayShown';
|
|
2095
|
+
readonly id: string;
|
|
2096
|
+
readonly optimistic: ReadonlyArray<OptimisticOperation>;
|
|
2097
|
+
} | {
|
|
2098
|
+
readonly _tag: 'OverlayLifted';
|
|
2099
|
+
readonly id: string;
|
|
2100
|
+
} |
|
|
2101
|
+
/** `Data.more`: a read's window, by `windowGrowthKey`, now shows `size` rows. */
|
|
2102
|
+
{
|
|
2103
|
+
readonly _tag: 'WindowGrown';
|
|
2104
|
+
readonly window: string;
|
|
2105
|
+
readonly size: number;
|
|
2106
|
+
} | {
|
|
2107
|
+
readonly _tag: 'LiveReceived';
|
|
2108
|
+
readonly stream: string;
|
|
2109
|
+
readonly event: LiveEvent;
|
|
2110
|
+
readonly policy?: LivePolicy;
|
|
2111
|
+
readonly now: number;
|
|
2112
|
+
} | {
|
|
2113
|
+
readonly _tag: 'GapCleared';
|
|
2114
|
+
readonly stream: string;
|
|
2115
|
+
} | {
|
|
2116
|
+
readonly _tag: 'ConnectionMerged';
|
|
2117
|
+
readonly connection: string;
|
|
2118
|
+
readonly page: Segment;
|
|
2119
|
+
/** The page answers the connection's refresh, so the merge also clears `stale`. */
|
|
2120
|
+
readonly refreshes?: boolean | undefined;
|
|
2272
2121
|
/**
|
|
2273
|
-
*
|
|
2274
|
-
*
|
|
2122
|
+
* The slice the query asked for, so the payload's entities write like a
|
|
2123
|
+
* read: one request per matching edge. Absent for a page from a server
|
|
2124
|
+
* that predates payload planning, which carries edges only.
|
|
2275
2125
|
*/
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2126
|
+
readonly select?: RelationRequirement | undefined;
|
|
2127
|
+
/** The selected fields of the page's items, as a read batch returns them. */
|
|
2128
|
+
readonly entities?: ReadonlyArray<{
|
|
2129
|
+
readonly entity: string;
|
|
2130
|
+
readonly id: string;
|
|
2131
|
+
readonly values: Record<string, unknown>;
|
|
2132
|
+
}> | undefined;
|
|
2133
|
+
/** Fields asked for that the server settled without a value. */
|
|
2134
|
+
readonly settled?: ReadonlyArray<{
|
|
2135
|
+
readonly entity: string;
|
|
2136
|
+
readonly id: string;
|
|
2137
|
+
readonly fields: ReadonlyArray<string>;
|
|
2138
|
+
}> | undefined;
|
|
2139
|
+
/** Injected clock reading of the answer, dating what the payload writes. */
|
|
2140
|
+
readonly now?: number | undefined;
|
|
2141
|
+
} | {
|
|
2142
|
+
readonly _tag: 'ConnectionInvalidated';
|
|
2143
|
+
readonly connection: string;
|
|
2144
|
+
} | {
|
|
2145
|
+
readonly _tag: 'ConnectionRefreshed';
|
|
2146
|
+
readonly connection: string;
|
|
2147
|
+
} |
|
|
2285
2148
|
/**
|
|
2286
|
-
*
|
|
2287
|
-
*
|
|
2288
|
-
*
|
|
2289
|
-
* list), so the Selection's codec decides whether that is a failure.
|
|
2149
|
+
* A query for the connection failed. Its pages stay as they were, and it
|
|
2150
|
+
* reads `Failed` — with them as `previous`, when it has any — until a page
|
|
2151
|
+
* arrives, it is invalidated, or retention drops it.
|
|
2290
2152
|
*/
|
|
2291
|
-
|
|
2153
|
+
{
|
|
2154
|
+
readonly _tag: 'QueryFailed';
|
|
2155
|
+
readonly connection: string;
|
|
2156
|
+
readonly error: RemoteError;
|
|
2157
|
+
} |
|
|
2292
2158
|
/**
|
|
2293
|
-
*
|
|
2294
|
-
*
|
|
2295
|
-
*
|
|
2159
|
+
* What `Data.preload` read for a destination, as the Messages that wrote it,
|
|
2160
|
+
* reduced in order into the Model as it is now rather than the one the
|
|
2161
|
+
* preload started from.
|
|
2296
2162
|
*/
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
declare const
|
|
2163
|
+
{
|
|
2164
|
+
readonly _tag: 'Preloaded';
|
|
2165
|
+
readonly messages: ReadonlyArray<RemoteMessage>;
|
|
2166
|
+
};
|
|
2167
|
+
declare const retentionRootsSchema: Schema.Struct<{
|
|
2168
|
+
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2169
|
+
readonly connections: Schema.$Array<Schema.Struct<{
|
|
2170
|
+
readonly identity: Schema.String;
|
|
2171
|
+
readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
2172
|
+
}>>;
|
|
2173
|
+
}>;
|
|
2302
2174
|
/**
|
|
2303
|
-
*
|
|
2304
|
-
*
|
|
2175
|
+
* The Messages' fields by tag, without `_tag`: what `defineMessageUnion` takes,
|
|
2176
|
+
* so an application spreads them into its own union (`Remote.messages`).
|
|
2305
2177
|
*/
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
}
|
|
2178
|
+
declare const remoteMessageCases: {
|
|
2179
|
+
ReadReceived: {
|
|
2180
|
+
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2181
|
+
result: Schema.Struct<{
|
|
2182
|
+
readonly entities: Schema.$Array<Schema.Struct<{
|
|
2183
|
+
readonly entity: Schema.String;
|
|
2184
|
+
readonly id: Schema.String;
|
|
2185
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
2186
|
+
}>>;
|
|
2187
|
+
readonly settled: Schema.$Array<Schema.Struct<{
|
|
2188
|
+
readonly entity: Schema.String;
|
|
2189
|
+
readonly id: Schema.String;
|
|
2190
|
+
readonly fields: Schema.$Array<Schema.String>;
|
|
2191
|
+
}>>;
|
|
2192
|
+
}>;
|
|
2193
|
+
now: Schema.Number;
|
|
2194
|
+
};
|
|
2195
|
+
ReadFailed: {
|
|
2196
|
+
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2197
|
+
error: Schema.Struct<{
|
|
2198
|
+
readonly _tag: Schema.String;
|
|
2199
|
+
readonly message: Schema.String;
|
|
2200
|
+
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
2201
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
2202
|
+
}>;
|
|
2203
|
+
stream: Schema.optional<Schema.String>;
|
|
2204
|
+
};
|
|
2205
|
+
RefreshStarted: {
|
|
2206
|
+
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2207
|
+
};
|
|
2208
|
+
ReadStarted: {
|
|
2209
|
+
requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2210
|
+
refresh: Schema.optional<Schema.Number>;
|
|
2211
|
+
};
|
|
2212
|
+
QueryStarted: {
|
|
2213
|
+
connections: Schema.$Array<Schema.String>;
|
|
2214
|
+
};
|
|
2215
|
+
RetentionChanged: {
|
|
2216
|
+
roots: Schema.Struct<{
|
|
2217
|
+
readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
|
|
2218
|
+
readonly connections: Schema.$Array<Schema.Struct<{
|
|
2219
|
+
readonly identity: Schema.String;
|
|
2220
|
+
readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
2221
|
+
}>>;
|
|
2222
|
+
}>;
|
|
2223
|
+
};
|
|
2224
|
+
Hydrated: {
|
|
2225
|
+
connections: Schema.optional<Schema.Unknown>;
|
|
2226
|
+
from: Schema.optional<Schema.String>;
|
|
2227
|
+
entities: Schema.Unknown;
|
|
2228
|
+
merge: Schema.Union<readonly [Schema.Literal<"replace">, Schema.Literal<"preserve-existing">]>;
|
|
2229
|
+
};
|
|
2230
|
+
MutationStarted: {
|
|
2231
|
+
requestId: Schema.String;
|
|
2232
|
+
optimistic: Schema.optional<Schema.$Array<Schema.Unknown>>;
|
|
2233
|
+
};
|
|
2234
|
+
MutationSucceeded: {
|
|
2235
|
+
requestId: Schema.String;
|
|
2236
|
+
entities: Schema.$Array<Schema.Struct<{
|
|
2237
|
+
readonly entity: Schema.String;
|
|
2238
|
+
readonly id: Schema.String;
|
|
2239
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
2240
|
+
}>>;
|
|
2241
|
+
connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
|
|
2242
|
+
deleted: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
2243
|
+
readonly entity: Schema.String;
|
|
2244
|
+
readonly id: Schema.String;
|
|
2245
|
+
}>>>;
|
|
2246
|
+
now: Schema.Number;
|
|
2247
|
+
};
|
|
2248
|
+
MutationFailed: {
|
|
2249
|
+
requestId: Schema.String;
|
|
2250
|
+
error: Schema.Struct<{
|
|
2251
|
+
readonly _tag: Schema.String;
|
|
2252
|
+
readonly message: Schema.String;
|
|
2253
|
+
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
2254
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
2255
|
+
}>;
|
|
2256
|
+
};
|
|
2257
|
+
OverlayShown: {
|
|
2258
|
+
id: Schema.String;
|
|
2259
|
+
optimistic: Schema.$Array<Schema.Unknown>;
|
|
2260
|
+
};
|
|
2261
|
+
OverlayLifted: {
|
|
2262
|
+
id: Schema.String;
|
|
2263
|
+
};
|
|
2264
|
+
WindowGrown: {
|
|
2265
|
+
window: Schema.String;
|
|
2266
|
+
size: Schema.Number;
|
|
2267
|
+
};
|
|
2268
|
+
LiveReceived: {
|
|
2269
|
+
stream: Schema.String;
|
|
2270
|
+
event: Schema.Unknown;
|
|
2271
|
+
policy: Schema.optional<Schema.Unknown>;
|
|
2272
|
+
now: Schema.Number;
|
|
2273
|
+
};
|
|
2274
|
+
GapCleared: {
|
|
2275
|
+
stream: Schema.String;
|
|
2276
|
+
};
|
|
2277
|
+
ConnectionMerged: {
|
|
2278
|
+
connection: Schema.String;
|
|
2279
|
+
page: Schema.Unknown;
|
|
2280
|
+
refreshes: Schema.optional<Schema.Boolean>;
|
|
2281
|
+
select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
|
|
2282
|
+
entities: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
2283
|
+
readonly entity: Schema.String;
|
|
2284
|
+
readonly id: Schema.String;
|
|
2285
|
+
readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
2286
|
+
}>>>;
|
|
2287
|
+
settled: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
2288
|
+
readonly entity: Schema.String;
|
|
2289
|
+
readonly id: Schema.String;
|
|
2290
|
+
readonly fields: Schema.$Array<Schema.String>;
|
|
2291
|
+
}>>>;
|
|
2292
|
+
now: Schema.optional<Schema.Number>;
|
|
2293
|
+
};
|
|
2294
|
+
ConnectionInvalidated: {
|
|
2295
|
+
connection: Schema.String;
|
|
2296
|
+
};
|
|
2297
|
+
ConnectionRefreshed: {
|
|
2298
|
+
connection: Schema.String;
|
|
2299
|
+
};
|
|
2300
|
+
QueryFailed: {
|
|
2301
|
+
connection: Schema.String;
|
|
2302
|
+
error: Schema.Struct<{
|
|
2303
|
+
readonly _tag: Schema.String;
|
|
2304
|
+
readonly message: Schema.String;
|
|
2305
|
+
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
2306
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
2307
|
+
}>;
|
|
2308
|
+
};
|
|
2309
|
+
Preloaded: {
|
|
2310
|
+
messages: Schema.$Array<Schema.suspend<Schema.Codec<RemoteMessage, unknown, never, never>>>;
|
|
2311
|
+
};
|
|
2312
|
+
};
|
|
2313
|
+
type RemoteMessageTag = RemoteMessage['_tag'];
|
|
2321
2314
|
/**
|
|
2322
|
-
*
|
|
2323
|
-
*
|
|
2324
|
-
*
|
|
2325
|
-
* schema graph.
|
|
2315
|
+
* A Remote Message as an application's union constructs it from
|
|
2316
|
+
* `remoteMessageCases`: the same shape `RemoteMessage` names, with the runtime
|
|
2317
|
+
* slots (`entities`, `event`, `page`) typed `unknown` by their schemas.
|
|
2326
2318
|
*/
|
|
2319
|
+
type RemoteMessageInput = { [Tag in RemoteMessageTag]: {
|
|
2320
|
+
readonly _tag: Tag;
|
|
2321
|
+
} & Schema.Struct.Type<(typeof remoteMessageCases)[Tag]>; }[RemoteMessageTag];
|
|
2327
2322
|
/**
|
|
2328
|
-
*
|
|
2329
|
-
*
|
|
2330
|
-
* some other entity, which would read as a row that does not exist.
|
|
2323
|
+
* Whether a Message is one of Remote's, by tag. Narrows an application's union
|
|
2324
|
+
* to its Remote cases, and its complement to the application's own.
|
|
2331
2325
|
*/
|
|
2332
|
-
|
|
2326
|
+
declare const isRemoteMessage: <M extends {
|
|
2327
|
+
readonly _tag: string;
|
|
2328
|
+
}>(message: M) => message is Extract<M, {
|
|
2329
|
+
readonly _tag: RemoteMessageTag;
|
|
2330
|
+
}>;
|
|
2331
|
+
declare const remoteMessageSchema: Schema.Codec<RemoteMessage, unknown>;
|
|
2332
|
+
/** The ids `OverlayShown` shows now, each once, in the order they are drawn. */
|
|
2333
|
+
declare const overlaysOf: (model: RemoteModel) => ReadonlyArray<string>;
|
|
2334
|
+
/** The key a grown window is kept under: its connection and the window first asked for. */
|
|
2335
|
+
declare const windowGrowthKey: (identity: string, window: string) => string;
|
|
2333
2336
|
/**
|
|
2334
|
-
*
|
|
2335
|
-
*
|
|
2337
|
+
* Whether only overlays show this entity: the server has told the store
|
|
2338
|
+
* nothing of it and no request's layer writes it, so nothing will fetch what an
|
|
2339
|
+
* overlay leaves out.
|
|
2336
2340
|
*/
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
readonly values: Partial<Schema.Struct.Encoded<F>>;
|
|
2341
|
-
}
|
|
2341
|
+
declare const onlyOverlaid: (model: RemoteModel, entity: string, id: string) => boolean;
|
|
2342
|
+
/** Whether a query for this connection is in flight. */
|
|
2343
|
+
declare const isQueryLoading: (model: RemoteModel, identity: string) => boolean;
|
|
2342
2344
|
/**
|
|
2343
|
-
*
|
|
2344
|
-
*
|
|
2345
|
-
*
|
|
2345
|
+
* The generation a read is planned under: the highest any of the fields it
|
|
2346
|
+
* reads or connections it runs was refreshed at. A read entry carries this as a
|
|
2347
|
+
* dependency, so it restarts when what it observes is refreshed and not when
|
|
2348
|
+
* anything else is.
|
|
2346
2349
|
*/
|
|
2347
|
-
|
|
2348
|
-
readonly refs: ReadonlyArray<EntityRef<Name, F>>;
|
|
2349
|
-
readonly hasNext: boolean;
|
|
2350
|
-
readonly hasPrevious: boolean;
|
|
2351
|
-
}
|
|
2352
|
-
/** The ref codec a `foldkit-entity` relation becomes: one ref, a nullable ref, or an array of refs. */
|
|
2353
|
-
type RelationField<Spec> = Spec extends Domain.RelationSpec<infer Target, infer Cardinality, infer Optional> ? Cardinality extends 'many' ? Schema.$Array<Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>>> : Optional extends true ? Schema.NullOr<Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>>> : Schema.Codec<EntityRef<Target['name']>, RefKey<Target['name']>> : never;
|
|
2350
|
+
declare const refreshedAt: (refresh: RefreshState, requests: ReadonlyArray<Requirement>, connections?: ReadonlyArray<string>) => number;
|
|
2354
2351
|
/**
|
|
2355
|
-
*
|
|
2356
|
-
*
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
type FieldsFrom<E> = E extends Domain.Entity<any, infer Fields, infer Relations, infer Derived> ? Fields & { readonly [K in keyof Derived]: Derived[K]['schema']; } & { readonly [K in keyof Relations]: RelationField<Relations[K]>; } : never;
|
|
2360
|
-
declare const Entity$2: {
|
|
2361
|
-
/**
|
|
2362
|
-
* The Remote descriptor of a `foldkit-entity` Entity. Relations declared with
|
|
2363
|
-
* `Entity.relate` become ref fields, so the store, the planner, and the server
|
|
2364
|
-
* treat it as they treat an `Entity.make` descriptor.
|
|
2365
|
-
*/
|
|
2366
|
-
from: <E extends Domain.AnyEntity>(entity: E & {
|
|
2367
|
-
readonly fields: {
|
|
2368
|
-
readonly id: unknown;
|
|
2369
|
-
};
|
|
2370
|
-
}) => EntityDescriptor<E["name"], FieldsFrom<E>>;
|
|
2371
|
-
make: <const Name extends string, const F extends Schema.Struct.Fields & {
|
|
2372
|
-
readonly id: Schema.Schema<unknown>;
|
|
2373
|
-
}>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
|
|
2374
|
-
/** A relation to a known entity, decoded as a reference. */
|
|
2375
|
-
ref: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<EntityRef<Name, F>, RefKey<Name>>;
|
|
2376
|
-
/** A relation by name, for recursive or forward references. */
|
|
2377
|
-
refTo: <Name extends string>(name: Name) => Schema.Codec<EntityRef<Name>, RefKey<Name>>;
|
|
2378
|
-
/**
|
|
2379
|
-
* The wire key a relation field carries (`"Entity:id"`). Adapters that read a
|
|
2380
|
-
* foreign key emit this so the ref codec can decode it on the client.
|
|
2381
|
-
*/
|
|
2382
|
-
refKey: (ref: {
|
|
2383
|
-
readonly entity: string;
|
|
2384
|
-
readonly id: string;
|
|
2385
|
-
}) => string;
|
|
2386
|
-
/** Splits a ref key back into its entity and id. */
|
|
2387
|
-
refParts: (encoded: string) => RefParts;
|
|
2388
|
-
/** A relation value of one authoritative page of refs. */
|
|
2389
|
-
refPage: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<RefPage<Name, F>, {
|
|
2390
|
-
readonly refs: ReadonlyArray<string>;
|
|
2391
|
-
readonly hasNext: boolean;
|
|
2392
|
-
readonly hasPrevious: boolean;
|
|
2393
|
-
}>;
|
|
2394
|
-
/**
|
|
2395
|
-
* A normalized patch for an entity, typed against its fields' wire shape:
|
|
2396
|
-
* write a relation as its ref key (`Entity.refKey`), as the server does.
|
|
2397
|
-
*/
|
|
2398
|
-
patch: <Name extends string, F extends Schema.Struct.Fields>(ref: EntityRef<Name, F>, patch: Partial<Schema.Struct.Encoded<F>>) => EntityPatch<Name, F>;
|
|
2399
|
-
};
|
|
2400
|
-
//#endregion
|
|
2401
|
-
//#region src/matching.d.ts
|
|
2352
|
+
* Marks every field of `requests` and every connection in `connections`
|
|
2353
|
+
* refreshed at the next generation.
|
|
2354
|
+
*/
|
|
2355
|
+
declare const withRefreshRequested: (refresh: RefreshState, requests: ReadonlyArray<Requirement>, connections?: ReadonlyArray<string>) => RefreshState;
|
|
2402
2356
|
/**
|
|
2403
|
-
*
|
|
2404
|
-
*
|
|
2405
|
-
*
|
|
2406
|
-
* `Page` carries `hasNext`/`hasPrevious`, which are facts the *server* stated
|
|
2407
|
-
* about rows beyond the ones it delivered; a local answer has no such facts and
|
|
2408
|
-
* cannot invent them. What it can say is whether the population it judged was
|
|
2409
|
-
* all of it, which is decidable: a connection terminal at both ends is wholly
|
|
2410
|
-
* held, and nothing was skipped for a missing field.
|
|
2411
|
-
*
|
|
2412
|
-
* An incomplete answer is not wrong — it is an answer about less than the
|
|
2413
|
-
* caller may have meant, and the flag is what lets a view say "3 so far" rather
|
|
2414
|
-
* than "3", or a caller decide to ask the server.
|
|
2357
|
+
* Marks connections as needing to be asked again, and restarts a read of them
|
|
2358
|
+
* already in flight: a page requested before what invalidated it could land
|
|
2359
|
+
* after it, saying what is no longer true. `Remote.refresh` marks the same way.
|
|
2415
2360
|
*/
|
|
2416
|
-
|
|
2417
|
-
readonly items: ReadonlyArray<A>;
|
|
2418
|
-
/** Whether every row the answer is about was judged. */
|
|
2419
|
-
readonly complete: boolean;
|
|
2420
|
-
}
|
|
2361
|
+
declare const invalidateConnections: (model: RemoteModel, connections: ReadonlyArray<string>) => RemoteModel;
|
|
2421
2362
|
/**
|
|
2422
|
-
*
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
2425
|
-
*
|
|
2426
|
-
* would turn "I could not tell" into "no". Naming it lets a caller decide:
|
|
2427
|
-
* fetch the field, ask the server, or say the answer is partial.
|
|
2363
|
+
* Whether one field's read already began under the generation that field was
|
|
2364
|
+
* last refreshed at. Such a read is in flight and would otherwise outlive the
|
|
2365
|
+
* refresh, so the refresh takes a new generation to restart it even though the
|
|
2366
|
+
* field is already stale.
|
|
2428
2367
|
*/
|
|
2429
|
-
|
|
2430
|
-
/** Keys of the rows that satisfy the body, in the order the body asks for. */
|
|
2431
|
-
readonly matched: ReadonlyArray<EntityKey>;
|
|
2432
|
-
/** Keys of rows held but missing a field the body reads, so not judged either way. */
|
|
2433
|
-
readonly skipped: ReadonlyArray<EntityKey>;
|
|
2434
|
-
}
|
|
2435
|
-
interface MatchingOptions {
|
|
2436
|
-
/**
|
|
2437
|
-
* Judge only these keys. Without it every row of the body's Entity in the
|
|
2438
|
-
* store is a candidate, which is what a filter over a loaded list wants; with
|
|
2439
|
-
* it, a caller narrows to a connection's own edges.
|
|
2440
|
-
*/
|
|
2441
|
-
readonly among?: ReadonlyArray<EntityKey> | undefined;
|
|
2442
|
-
}
|
|
2368
|
+
declare const refreshIsInFlight: (refresh: RefreshState, request: Requirement, field: string) => boolean;
|
|
2443
2369
|
/**
|
|
2444
|
-
*
|
|
2445
|
-
*
|
|
2446
|
-
*
|
|
2447
|
-
* through the descriptor's own `Input` codec. That is deliberate and is the
|
|
2448
|
-
* whole reason this takes a descriptor rather than a bare body: a store holds
|
|
2449
|
-
* wire values, so an input has to be in that space to be compared against them,
|
|
2450
|
-
* and handing an interpreter a decoded value is a mistake **no runtime error
|
|
2451
|
-
* catches** — the reference interpreter answers "no rows", which reads exactly
|
|
2452
|
-
* like a correct answer. Doing it here means a caller cannot get it wrong.
|
|
2453
|
-
*
|
|
2454
|
-
* Literals in the body are deliberately *not* encoded. A literal written in
|
|
2455
|
-
* domain terms is already broken against the server, which binds it to a column
|
|
2456
|
-
* the same way; accepting it here would make the client quietly more permissive
|
|
2457
|
-
* than the thing it has to agree with.
|
|
2370
|
+
* Whether a read is fetching any of `fields` for this entity. Consulted only
|
|
2371
|
+
* when the store lacks the value, which is what separates `Loading` from
|
|
2372
|
+
* `Initial`.
|
|
2458
2373
|
*/
|
|
2459
|
-
declare const
|
|
2374
|
+
declare const isLoading: (model: RemoteModel, entity: string, id: string, fields: ReadonlyArray<string>) => boolean;
|
|
2460
2375
|
/**
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
2463
|
-
*
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2466
|
-
*
|
|
2467
|
-
*
|
|
2468
|
-
*
|
|
2469
|
-
* `eq`, `isNull` or `contains` needs no collation: equality on text is exact
|
|
2470
|
-
* and `contains` folds ASCII, both stated in §6.0.1. *Where* a row sorts needs
|
|
2471
|
-
* text collation, which is the backend's and deliberately outside the
|
|
2472
|
-
* conformant subset — so this answers the half that is always answerable, and
|
|
2473
|
-
* ordering stays the server's until a query can declare its collation.
|
|
2376
|
+
* The pure reducer all four producers share. A live event that arrives ahead of
|
|
2377
|
+
* its cursor is a gap: it is not applied, and the stream is recorded so its
|
|
2378
|
+
* live entry restarts it rather than silently missing facts. When every field a Message
|
|
2379
|
+
* touches keeps its identity, `model` itself is returned, so the application's
|
|
2380
|
+
* root keeps its identity and Foldkit does not render. The common no-ops do (a
|
|
2381
|
+
* duplicate live event, a repeated `ReadStarted`); a repeated failure, or a
|
|
2382
|
+
* `preserve-existing` restore of entities already held, still makes an equal
|
|
2383
|
+
* copy.
|
|
2474
2384
|
*/
|
|
2475
|
-
|
|
2385
|
+
declare const updateRemote: (model: RemoteModel, message: RemoteMessage) => RemoteModel;
|
|
2386
|
+
/** Whether this field's last read failed and nothing has settled it since. */
|
|
2387
|
+
declare const isFieldFailed: (model: RemoteModel, entity: string, id: string, field: string) => boolean;
|
|
2476
2388
|
/**
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2479
|
-
*
|
|
2480
|
-
*
|
|
2481
|
-
* A decoded-input sibling was written first and deleted: nothing called it. The
|
|
2482
|
-
* asymmetry with `matching`, which takes a decoded input, is the shape of the
|
|
2483
|
-
* two real callers rather than an oversight.
|
|
2389
|
+
* Whether a read is fetching any field `relation` reads of an entity, its own
|
|
2390
|
+
* or, through each relation the store holds, its targets'. A value whose owner
|
|
2391
|
+
* is being fetched is loading, not `Initial`: nothing is missing a fetch.
|
|
2484
2392
|
*/
|
|
2485
|
-
declare const
|
|
2393
|
+
declare const isLoadingThrough: (model: RemoteModel, entity: string, id: string, relation: RelationRequirement) => boolean;
|
|
2394
|
+
/**
|
|
2395
|
+
* The first failure among the fields `relation` reads of an entity, following
|
|
2396
|
+
* each relation the store holds into its targets, as `assemble` does. A read
|
|
2397
|
+
* that consults it shows `Failed` for a related entity's failure too, rather
|
|
2398
|
+
* than waiting on a field nothing will fetch.
|
|
2399
|
+
*/
|
|
2400
|
+
declare const failureOf: (model: RemoteModel, entity: string, id: string, relation: RelationRequirement) => RemoteError | undefined;
|
|
2401
|
+
/**
|
|
2402
|
+
* Writes a read result into the store, recording each field's applied window so
|
|
2403
|
+
* a later request with a different window refetches. A relation page requested
|
|
2404
|
+
* with a cursor is merged onto the page already stored, so "load more"
|
|
2405
|
+
* accumulates rather than replaces. Every read path should use this rather than
|
|
2406
|
+
* reducing `writeEntity` by hand.
|
|
2407
|
+
*/
|
|
2408
|
+
declare const writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
|
|
2486
2409
|
//#endregion
|
|
2487
2410
|
//#region src/inspect.d.ts
|
|
2488
2411
|
/** A query body's `Dependencies` as plain data: each field by its Entity's name and key. */
|
|
@@ -2532,7 +2455,7 @@ interface RemoteInspection {
|
|
|
2532
2455
|
/** A pure, serializable view of the whole cache. */
|
|
2533
2456
|
declare const inspectRemote: (model: RemoteModel) => RemoteInspection;
|
|
2534
2457
|
/** A pure, serializable view of one entity, or `undefined` if unknown. */
|
|
2535
|
-
declare const inspectEntity: (model: RemoteModel, key: string) => RemoteInspection[
|
|
2458
|
+
declare const inspectEntity: (model: RemoteModel, key: string) => RemoteInspection['entities'][number] | undefined;
|
|
2536
2459
|
/**
|
|
2537
2460
|
* Why a read shows what it shows, in words, and for `Initial`, which of the
|
|
2538
2461
|
* usual mistakes it is.
|
|
@@ -2684,7 +2607,7 @@ type RemotePolicy =
|
|
|
2684
2607
|
declare const RemotePolicy: {
|
|
2685
2608
|
/** Fetch only what the store lacks. */
|
|
2686
2609
|
cacheFirst: {
|
|
2687
|
-
readonly _tag:
|
|
2610
|
+
readonly _tag: 'CacheFirst';
|
|
2688
2611
|
};
|
|
2689
2612
|
/** Keep present values visible, read as `Refreshing`, and refetch an entry older than `maxAge` ms. */
|
|
2690
2613
|
staleWhileRevalidate: (options: {
|
|
@@ -2692,7 +2615,7 @@ declare const RemotePolicy: {
|
|
|
2692
2615
|
}) => RemotePolicy;
|
|
2693
2616
|
/** Fetch every selected field regardless of coverage; cached values stay visible meanwhile. */
|
|
2694
2617
|
networkOnly: {
|
|
2695
|
-
readonly _tag:
|
|
2618
|
+
readonly _tag: 'NetworkOnly';
|
|
2696
2619
|
};
|
|
2697
2620
|
/** The planner options a policy compiles to at `now`. */
|
|
2698
2621
|
toPlan: (policy: RemotePolicy, now: number) => PlanOptions;
|
|
@@ -2704,6 +2627,89 @@ declare const RemotePolicy: {
|
|
|
2704
2627
|
refreshes: (policy: RemotePolicy) => boolean;
|
|
2705
2628
|
};
|
|
2706
2629
|
//#endregion
|
|
2630
|
+
//#region src/resume.d.ts
|
|
2631
|
+
/**
|
|
2632
|
+
* A resume part, in the shape `foldkit-ssr`'s `SSR.plan` takes in `parts`.
|
|
2633
|
+
* Declared here structurally, so neither package depends on the other.
|
|
2634
|
+
*/
|
|
2635
|
+
interface RemoteResumePart<AppModel> {
|
|
2636
|
+
readonly id: string;
|
|
2637
|
+
/** The metadata key names whose reads this part resumes. */
|
|
2638
|
+
readonly covers: ReadonlyArray<string>;
|
|
2639
|
+
readonly capture: (model: AppModel, projections: ReadonlyArray<{
|
|
2640
|
+
readonly metadata: Metadata;
|
|
2641
|
+
}>) => unknown;
|
|
2642
|
+
readonly restore: (model: AppModel, value: unknown) => Result.Result<AppModel, string>;
|
|
2643
|
+
/** Whether a Subscription entry is one of this domain's, which may start late. */
|
|
2644
|
+
readonly deferrable: (key: string, entry: unknown) => boolean;
|
|
2645
|
+
}
|
|
2646
|
+
/**
|
|
2647
|
+
* The resume part for a Remote domain, for `SSR.plan`'s `parts`: it sends
|
|
2648
|
+
* what the plan's active Surfaces read from this domain's store, and nothing
|
|
2649
|
+
* else of it. `id` tells two domains in one application apart.
|
|
2650
|
+
*/
|
|
2651
|
+
declare const resumePart: <AppModel, Store extends RemoteModel>(domain: {
|
|
2652
|
+
readonly store: ModelRef<AppModel, Store>;
|
|
2653
|
+
}, options?: {
|
|
2654
|
+
readonly id?: string | undefined;
|
|
2655
|
+
}) => RemoteResumePart<AppModel>;
|
|
2656
|
+
//#endregion
|
|
2657
|
+
//#region src/json.d.ts
|
|
2658
|
+
/** A request: which of Remote's calls, and its payload as the RPC protocol encodes it. */
|
|
2659
|
+
declare const RemoteJsonRequest: Schema.Struct<{
|
|
2660
|
+
readonly operation: Schema.Literals<readonly ["read", "query", "mutate"]>;
|
|
2661
|
+
readonly payload: Schema.Unknown;
|
|
2662
|
+
}>;
|
|
2663
|
+
type RemoteJsonRequest = typeof RemoteJsonRequest.Type;
|
|
2664
|
+
/** An answer: the call's result, or why there is none. */
|
|
2665
|
+
declare const RemoteJsonAnswer: Schema.Union<readonly [Schema.Struct<{
|
|
2666
|
+
readonly result: Schema.Unknown;
|
|
2667
|
+
}>, Schema.Struct<{
|
|
2668
|
+
readonly error: Schema.String;
|
|
2669
|
+
readonly refusal: Schema.optional<Schema.Unknown>;
|
|
2670
|
+
/** Who is asking was refused, with the application's reason when it gave one. */
|
|
2671
|
+
readonly forbidden: Schema.optional<Schema.Struct<{
|
|
2672
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
2673
|
+
}>>;
|
|
2674
|
+
}>]>;
|
|
2675
|
+
type RemoteJsonAnswer = typeof RemoteJsonAnswer.Type;
|
|
2676
|
+
/**
|
|
2677
|
+
* Sends one request's text and resolves with its answer as parsed JSON. It
|
|
2678
|
+
* rejects when nothing came back, and the call fails with that message.
|
|
2679
|
+
*/
|
|
2680
|
+
type RemoteJsonSend = (request: string) => Promise<unknown>;
|
|
2681
|
+
/** Remote's client over `send`, for `Remote.clientLayer`. */
|
|
2682
|
+
declare const json: (send: RemoteJsonSend) => RemoteRpcClient;
|
|
2683
|
+
/**
|
|
2684
|
+
* Remote's client over HTTP: each call a `POST` of the request to `url`, the
|
|
2685
|
+
* answer its JSON body whatever its status. A 403 is answered as forbidden
|
|
2686
|
+
* unless its body says so itself, as the server's own does: one from
|
|
2687
|
+
* middleware in front of Remote (a refused session) may say only `{ error }`.
|
|
2688
|
+
* `headers` is read per request, so a token that changes reaches the next
|
|
2689
|
+
* call. `fetch` defaults to the global one; pass it to route calls through
|
|
2690
|
+
* another implementation in tests.
|
|
2691
|
+
*/
|
|
2692
|
+
declare const http: (url: string, options?: {
|
|
2693
|
+
readonly headers?: (() => Readonly<Record<string, string>>) | undefined;
|
|
2694
|
+
readonly fetch?: typeof fetch | undefined;
|
|
2695
|
+
}) => RemoteRpcClient;
|
|
2696
|
+
//#endregion
|
|
2697
|
+
//#region src/sse.d.ts
|
|
2698
|
+
/** What `httpWithLive` needs besides the URL. Mirrors `http`, plus the fetch itself. */
|
|
2699
|
+
interface LiveFetchOptions {
|
|
2700
|
+
/** Read per request, so a token that changes reaches the next call. */
|
|
2701
|
+
readonly headers?: (() => Readonly<Record<string, string>>) | undefined;
|
|
2702
|
+
/** Defaults to the global one; pass it to route calls elsewhere in tests. */
|
|
2703
|
+
readonly fetch?: typeof fetch | undefined;
|
|
2704
|
+
}
|
|
2705
|
+
/** Remote's live stream over fetch: `serveFetch`'s live open as a `Stream`. */
|
|
2706
|
+
declare const liveFetch: (url: string, options?: LiveFetchOptions) => RemoteRpcClient['FoldkitRemoteLive'];
|
|
2707
|
+
/**
|
|
2708
|
+
* Remote's client over HTTP with live: reads, queries, and mutations as
|
|
2709
|
+
* `http` sends them, live as `liveFetch` streams it, for `clientLayer`.
|
|
2710
|
+
*/
|
|
2711
|
+
declare const httpWithLive: (url: string, options?: LiveFetchOptions) => RemoteRpcClient;
|
|
2712
|
+
//#endregion
|
|
2707
2713
|
//#region src/placement.d.ts
|
|
2708
2714
|
/** Where a row falls in a loaded list. */
|
|
2709
2715
|
type RowPlace = Data.TaggedEnum<{
|
|
@@ -2724,65 +2730,43 @@ type RowPlace = Data.TaggedEnum<{
|
|
|
2724
2730
|
};
|
|
2725
2731
|
}>;
|
|
2726
2732
|
declare const RowPlace: {
|
|
2727
|
-
readonly Unknown:
|
|
2728
|
-
readonly _tag: "Unknown";
|
|
2729
|
-
readonly reason: string;
|
|
2730
|
-
}, "_tag">;
|
|
2731
|
-
readonly Before: Data.TaggedEnum.ConstructorFrom<{
|
|
2733
|
+
readonly $is: <Tag extends "Before" | "End" | "Outside" | "Unknown">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
2732
2734
|
readonly _tag: "Before";
|
|
2733
2735
|
readonly segment: number;
|
|
2734
2736
|
readonly edge: string;
|
|
2735
|
-
}, "_tag">;
|
|
2736
|
-
readonly End: Data.TaggedEnum.ConstructorFrom<{
|
|
2737
|
-
readonly _tag: "End";
|
|
2738
|
-
readonly segment: number;
|
|
2739
|
-
}, "_tag">;
|
|
2740
|
-
readonly Outside: Data.TaggedEnum.ConstructorFrom<{
|
|
2741
|
-
readonly _tag: "Outside";
|
|
2742
|
-
}, "_tag">;
|
|
2743
|
-
readonly $is: <Tag extends "Unknown" | "Before" | "End" | "Outside">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
2744
|
-
readonly _tag: "Unknown";
|
|
2745
|
-
readonly reason: string;
|
|
2746
2737
|
}, {
|
|
2747
2738
|
readonly _tag: Tag;
|
|
2748
2739
|
}> | Extract<{
|
|
2749
|
-
readonly _tag: "
|
|
2740
|
+
readonly _tag: "End";
|
|
2750
2741
|
readonly segment: number;
|
|
2751
|
-
readonly edge: string;
|
|
2752
2742
|
}, {
|
|
2753
2743
|
readonly _tag: Tag;
|
|
2754
2744
|
}> | Extract<{
|
|
2755
|
-
readonly _tag: "
|
|
2756
|
-
readonly segment: number;
|
|
2745
|
+
readonly _tag: "Outside";
|
|
2757
2746
|
}, {
|
|
2758
2747
|
readonly _tag: Tag;
|
|
2759
2748
|
}> | Extract<{
|
|
2760
|
-
readonly _tag: "
|
|
2749
|
+
readonly _tag: "Unknown";
|
|
2750
|
+
readonly reason: string;
|
|
2761
2751
|
}, {
|
|
2762
2752
|
readonly _tag: Tag;
|
|
2763
2753
|
}>;
|
|
2764
2754
|
readonly $match: {
|
|
2765
|
-
<Cases extends {
|
|
2766
|
-
readonly
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
readonly
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
readonly End: (args: {
|
|
2776
|
-
readonly _tag: "End";
|
|
2777
|
-
readonly segment: number;
|
|
2778
|
-
}) => any;
|
|
2779
|
-
readonly Outside: (args: {
|
|
2780
|
-
readonly _tag: "Outside";
|
|
2781
|
-
}) => any;
|
|
2782
|
-
}>(cases: Cases): (value: {
|
|
2755
|
+
<Cases extends { readonly [Tag in "Before" | "End" | "Outside" | "Unknown"]: (args: Extract<{
|
|
2756
|
+
readonly _tag: "Before";
|
|
2757
|
+
readonly segment: number;
|
|
2758
|
+
readonly edge: string;
|
|
2759
|
+
} | {
|
|
2760
|
+
readonly _tag: "End";
|
|
2761
|
+
readonly segment: number;
|
|
2762
|
+
} | {
|
|
2763
|
+
readonly _tag: "Outside";
|
|
2764
|
+
} | {
|
|
2783
2765
|
readonly _tag: "Unknown";
|
|
2784
2766
|
readonly reason: string;
|
|
2785
|
-
}
|
|
2767
|
+
}, {
|
|
2768
|
+
readonly _tag: Tag;
|
|
2769
|
+
}>) => any; }>(cases: Cases): (value: {
|
|
2786
2770
|
readonly _tag: "Before";
|
|
2787
2771
|
readonly segment: number;
|
|
2788
2772
|
readonly edge: string;
|
|
@@ -2791,28 +2775,25 @@ declare const RowPlace: {
|
|
|
2791
2775
|
readonly segment: number;
|
|
2792
2776
|
} | {
|
|
2793
2777
|
readonly _tag: "Outside";
|
|
2794
|
-
}
|
|
2795
|
-
<Cases extends {
|
|
2796
|
-
readonly Unknown: (args: {
|
|
2797
|
-
readonly _tag: "Unknown";
|
|
2798
|
-
readonly reason: string;
|
|
2799
|
-
}) => any;
|
|
2800
|
-
readonly Before: (args: {
|
|
2801
|
-
readonly _tag: "Before";
|
|
2802
|
-
readonly segment: number;
|
|
2803
|
-
readonly edge: string;
|
|
2804
|
-
}) => any;
|
|
2805
|
-
readonly End: (args: {
|
|
2806
|
-
readonly _tag: "End";
|
|
2807
|
-
readonly segment: number;
|
|
2808
|
-
}) => any;
|
|
2809
|
-
readonly Outside: (args: {
|
|
2810
|
-
readonly _tag: "Outside";
|
|
2811
|
-
}) => any;
|
|
2812
|
-
}>(value: {
|
|
2778
|
+
} | {
|
|
2813
2779
|
readonly _tag: "Unknown";
|
|
2814
2780
|
readonly reason: string;
|
|
2781
|
+
}) => import("effect/Unify").Unify<ReturnType<Cases["Before" | "End" | "Outside" | "Unknown"]>>;
|
|
2782
|
+
<Cases extends { readonly [Tag in "Before" | "End" | "Outside" | "Unknown"]: (args: Extract<{
|
|
2783
|
+
readonly _tag: "Before";
|
|
2784
|
+
readonly segment: number;
|
|
2785
|
+
readonly edge: string;
|
|
2786
|
+
} | {
|
|
2787
|
+
readonly _tag: "End";
|
|
2788
|
+
readonly segment: number;
|
|
2789
|
+
} | {
|
|
2790
|
+
readonly _tag: "Outside";
|
|
2815
2791
|
} | {
|
|
2792
|
+
readonly _tag: "Unknown";
|
|
2793
|
+
readonly reason: string;
|
|
2794
|
+
}, {
|
|
2795
|
+
readonly _tag: Tag;
|
|
2796
|
+
}>) => any; }>(value: {
|
|
2816
2797
|
readonly _tag: "Before";
|
|
2817
2798
|
readonly segment: number;
|
|
2818
2799
|
readonly edge: string;
|
|
@@ -2821,8 +2802,27 @@ declare const RowPlace: {
|
|
|
2821
2802
|
readonly segment: number;
|
|
2822
2803
|
} | {
|
|
2823
2804
|
readonly _tag: "Outside";
|
|
2824
|
-
}
|
|
2805
|
+
} | {
|
|
2806
|
+
readonly _tag: "Unknown";
|
|
2807
|
+
readonly reason: string;
|
|
2808
|
+
}, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Before" | "End" | "Outside" | "Unknown"]>>;
|
|
2825
2809
|
};
|
|
2810
|
+
readonly Before: Data.TaggedEnum.ConstructorFrom<{
|
|
2811
|
+
readonly _tag: "Before";
|
|
2812
|
+
readonly segment: number;
|
|
2813
|
+
readonly edge: string;
|
|
2814
|
+
}, "_tag">;
|
|
2815
|
+
readonly End: Data.TaggedEnum.ConstructorFrom<{
|
|
2816
|
+
readonly _tag: "End";
|
|
2817
|
+
readonly segment: number;
|
|
2818
|
+
}, "_tag">;
|
|
2819
|
+
readonly Outside: Data.TaggedEnum.ConstructorFrom<{
|
|
2820
|
+
readonly _tag: "Outside";
|
|
2821
|
+
}, "_tag">;
|
|
2822
|
+
readonly Unknown: Data.TaggedEnum.ConstructorFrom<{
|
|
2823
|
+
readonly _tag: "Unknown";
|
|
2824
|
+
readonly reason: string;
|
|
2825
|
+
}, "_tag">;
|
|
2826
2826
|
};
|
|
2827
2827
|
/**
|
|
2828
2828
|
* Where the row stored under `key` falls in `connection`, by `body`'s order
|
|
@@ -3166,6 +3166,19 @@ interface RemoteDomain<AppModel, Store extends RemoteModel, Entities extends rea
|
|
|
3166
3166
|
* held is not asked again.
|
|
3167
3167
|
*/
|
|
3168
3168
|
satisfy(model: AppModel, active: Readonly<Record<string, ActiveEntry<AppModel>>>, options?: SatisfyOptions): Effect.Effect<AppModel, RemoteReadError | RemoteProtocolError | RemoteQueryError | RemoteUnsatisfied, RemoteClient>;
|
|
3169
|
+
/**
|
|
3170
|
+
* `satisfy` from `update`, for a destination the reader has not reached:
|
|
3171
|
+
* a hover over a link, or a navigation the app expects. `model` is the
|
|
3172
|
+
* Model as it would be there (the route set to the target's); the Command
|
|
3173
|
+
* reads what `active` would read in it and yields one `Preloaded`
|
|
3174
|
+
* carrying the Messages that wrote it, which reduce into the Model as it is
|
|
3175
|
+
* by then. It never fails: a read that fails is one the destination makes
|
|
3176
|
+
* again, and what was read before it still arrives.
|
|
3177
|
+
*
|
|
3178
|
+
* What it reads is kept like any other read until the next change of what
|
|
3179
|
+
* is retained, so preload close to the navigation it expects.
|
|
3180
|
+
*/
|
|
3181
|
+
preload(model: AppModel, active: Readonly<Record<string, ActiveEntry<AppModel>>>, options?: SatisfyOptions): Command<RemoteMessage, never, RemoteClient>;
|
|
3169
3182
|
/**
|
|
3170
3183
|
* Starts a registered mutation from `update`: applies `MutationStarted` (with
|
|
3171
3184
|
* the optimistic operations) to the Model and returns the Command that runs
|
|
@@ -3230,6 +3243,8 @@ interface RemoteFold<AppModel, ParentMessage, Domain extends RemoteDomain<AppMod
|
|
|
3230
3243
|
(model: AppModel, message: RemoteMessage | RemoteMessageInput): Update.Return<AppModel, ParentMessage>;
|
|
3231
3244
|
/** `Data.mutate`, its Command lifted. */
|
|
3232
3245
|
readonly mutate: (...args: Parameters<Domain['mutate']>) => FoldedMutationStarted<AppModel, ParentMessage>;
|
|
3246
|
+
/** `Data.preload`, its Command lifted. */
|
|
3247
|
+
readonly preload: (...args: Parameters<Domain['preload']>) => Command<ParentMessage, never, RemoteClient>;
|
|
3233
3248
|
/** `Data.subscriptions`, every entry lifted to the wrapper Message. */
|
|
3234
3249
|
readonly subscriptions: <const Active extends Readonly<Record<string, ActiveEntry<AppModel>>>>(active: Active, options?: SubscriptionsOptions) => SubscriptionEntries<AppModel, Active, ParentMessage>;
|
|
3235
3250
|
}
|
|
@@ -3325,6 +3340,14 @@ interface LiveOptions {
|
|
|
3325
3340
|
/** The longest a restart waits. Default `5 seconds`. */
|
|
3326
3341
|
readonly maxRetryDelay?: Duration.Input | undefined;
|
|
3327
3342
|
}
|
|
3343
|
+
/** Declares a Remote domain: its entities, queries, and mutations, plus the submodel. */
|
|
3344
|
+
declare const defineRemote: <const Entities extends readonly EntityLike[], const Queries extends readonly QueryDescriptor<any, any, any>[] = readonly QueryDescriptor<any, any, any>[], const Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly MutationDescriptor<any, any, any>[]>(config: {
|
|
3345
|
+
readonly entities: Entities;
|
|
3346
|
+
readonly queries?: Queries;
|
|
3347
|
+
readonly mutations?: Mutations;
|
|
3348
|
+
}) => RemoteDescriptor<Entities, Queries, Mutations>;
|
|
3349
|
+
/** Binds a Remote domain to its store's location in the application Model. */
|
|
3350
|
+
declare const bindRemote: <AppModel, Store extends RemoteModel, Entities extends readonly EntityLike[], Queries extends readonly QueryDescriptor<any, any, any>[], Mutations extends readonly MutationDescriptor<any, any, any>[]>(definition: RemoteDescriptor<Entities, Queries, Mutations>, store: ModelRef<AppModel, Store>) => BoundRemote<AppModel, Store, EntityName<Entities[number]>>;
|
|
3328
3351
|
/** A query the read entry runs, as its dependencies carry it: plain data Foldkit compares. */
|
|
3329
3352
|
declare const PlannedQuery: Schema.Struct<{
|
|
3330
3353
|
readonly identity: Schema.String;
|
|
@@ -3496,13 +3519,12 @@ declare const Remote: {
|
|
|
3496
3519
|
readonly reason: Schema.optional<Schema.String>;
|
|
3497
3520
|
}>;
|
|
3498
3521
|
};
|
|
3522
|
+
Preloaded: {
|
|
3523
|
+
messages: Schema.$Array<Schema.suspend<Schema.Codec<RemoteMessage, unknown, never, never>>>;
|
|
3524
|
+
};
|
|
3499
3525
|
};
|
|
3500
3526
|
/** Whether a Message is one of Remote's, by tag. */
|
|
3501
|
-
reduces:
|
|
3502
|
-
readonly _tag: string;
|
|
3503
|
-
}>(message: M) => message is Extract<M, {
|
|
3504
|
-
readonly _tag: RemoteMessageTag;
|
|
3505
|
-
}>;
|
|
3527
|
+
reduces: typeof isRemoteMessage;
|
|
3506
3528
|
/**
|
|
3507
3529
|
* Remote's Messages as one Schema, for a wrapper variant in the
|
|
3508
3530
|
* application's union: `GotRemoteMessage: { message: Remote.Message }`. With
|
|
@@ -3640,6 +3662,9 @@ declare const Remote: {
|
|
|
3640
3662
|
readonly reason: Schema.optional<Schema.String>;
|
|
3641
3663
|
}>;
|
|
3642
3664
|
};
|
|
3665
|
+
Preloaded: {
|
|
3666
|
+
messages: Schema.$Array<Schema.suspend<Schema.Codec<RemoteMessage, unknown, never, never>>>;
|
|
3667
|
+
};
|
|
3643
3668
|
}>;
|
|
3644
3669
|
/**
|
|
3645
3670
|
* A bound domain under one wrapper variant of the application's union, the
|
|
@@ -3704,28 +3729,20 @@ declare const Remote: {
|
|
|
3704
3729
|
* mutations, plus the submodel. For a domain reused across applications or
|
|
3705
3730
|
* bound in a test; `Remote.make` is the one-step form.
|
|
3706
3731
|
*/
|
|
3707
|
-
define:
|
|
3708
|
-
readonly entities: Entities;
|
|
3709
|
-
readonly queries?: Queries;
|
|
3710
|
-
readonly mutations?: Mutations;
|
|
3711
|
-
}) => RemoteDescriptor<Entities, Queries, Mutations>;
|
|
3732
|
+
define: typeof defineRemote;
|
|
3712
3733
|
/**
|
|
3713
3734
|
* Binds a Remote domain to its store's location in the application Model. The
|
|
3714
3735
|
* registered entity names are carried on the returned value, so `Remote.select`
|
|
3715
3736
|
* rejects a selection for an entity this domain never declared.
|
|
3716
3737
|
*/
|
|
3717
|
-
at:
|
|
3738
|
+
at: typeof bindRemote;
|
|
3718
3739
|
/**
|
|
3719
3740
|
* The resume part for this domain, for `foldkit-ssr`'s `SSR.plan({ parts })`:
|
|
3720
3741
|
* a server render sends what the plan's active Surfaces read from the store,
|
|
3721
3742
|
* each connection with its boundaries and each live cursor with it, and
|
|
3722
3743
|
* nothing else. `id` tells two domains in one application apart.
|
|
3723
3744
|
*/
|
|
3724
|
-
resume:
|
|
3725
|
-
readonly store: ModelRef<AppModel, Store>;
|
|
3726
|
-
}, options?: {
|
|
3727
|
-
readonly id?: string | undefined;
|
|
3728
|
-
}) => RemoteResumePart<AppModel>;
|
|
3745
|
+
resume: typeof resumePart;
|
|
3729
3746
|
/**
|
|
3730
3747
|
* A Projection node that reads a `RemoteData` value out of the store. The id
|
|
3731
3748
|
* is supplied by the caller, usually from a Surface's params. The assembled
|
|
@@ -3733,7 +3750,7 @@ declare const Remote: {
|
|
|
3733
3750
|
* as `Failed` instead of being asserted into `Value`. A present value with a
|
|
3734
3751
|
* stale field reads as `Refreshing`: an observer is refetching it.
|
|
3735
3752
|
*/
|
|
3736
|
-
select: <AppModel, Store extends RemoteModel, Names extends string, Value, Name extends string>(bound: BoundRemote<AppModel, Store, Names>, given: EntitySelection<Value, Name> & Registered<Name, Names,
|
|
3753
|
+
select: <AppModel, Store extends RemoteModel, Names extends string, Value, Name extends string>(bound: BoundRemote<AppModel, Store, Names>, given: EntitySelection<Value, Name> & Registered<Name, Names, 'Entity'>) => (id: string) => Projection<AppModel, RemoteData<Value>>;
|
|
3737
3754
|
/**
|
|
3738
3755
|
* When what a projection shows was last received, and whether it is stale
|
|
3739
3756
|
* or loading. Pure, so a view can show "updated 5s ago" without I/O.
|
|
@@ -3774,7 +3791,7 @@ declare const Remote: {
|
|
|
3774
3791
|
* `policy` decides what a present field means (default cache-first); `now`
|
|
3775
3792
|
* is the clock it reads, so the planner itself stays pure and time-injected.
|
|
3776
3793
|
*/
|
|
3777
|
-
prefetch: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store, string>, model: AppModel, projection: Projection<AppModel, Value>, options?: ObserveOptions | undefined) => Effect.Effect<Readonly<Record<string, EntityEntry>>,
|
|
3794
|
+
prefetch: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store, string>, model: AppModel, projection: Projection<AppModel, Value>, options?: ObserveOptions | undefined) => Effect.Effect<Readonly<Record<string, EntityEntry>>, RemoteProtocolError | RemoteReadError, RemoteClient>;
|
|
3778
3795
|
/**
|
|
3779
3796
|
* Marks what a projection, or a Surface without params, requires as due again.
|
|
3780
3797
|
* Called from `update`: every selected field the store holds reads `Refreshing`,
|
|
@@ -3812,7 +3829,7 @@ declare const Remote: {
|
|
|
3812
3829
|
* Writes a read result into the store, recording each field's applied window.
|
|
3813
3830
|
* `requests` are the planned requirements the result answers.
|
|
3814
3831
|
*/
|
|
3815
|
-
writeRead:
|
|
3832
|
+
writeRead: typeof writeRead;
|
|
3816
3833
|
/**
|
|
3817
3834
|
* Adapts an Effect RPC client for `RemoteRpc` to `RemoteClient`, so an
|
|
3818
3835
|
* application provides the transport's RPC layer instead of writing the
|
|
@@ -3826,29 +3843,26 @@ declare const Remote: {
|
|
|
3826
3843
|
* answer, for `clientLayer`: a worker, a server in the page. `RemoteServer.answer`
|
|
3827
3844
|
* is the other end.
|
|
3828
3845
|
*/
|
|
3829
|
-
json:
|
|
3846
|
+
json: typeof json;
|
|
3830
3847
|
/**
|
|
3831
3848
|
* Remote's client over HTTP, for `clientLayer`: each call a `POST` of the JSON
|
|
3832
3849
|
* request to `url`. `headers` is read per request (a session token, say).
|
|
3833
3850
|
*/
|
|
3834
|
-
http:
|
|
3835
|
-
readonly headers?: (() => Readonly<Record<string, string>>) | undefined;
|
|
3836
|
-
readonly fetch?: typeof fetch | undefined;
|
|
3837
|
-
}) => RemoteRpcClient;
|
|
3851
|
+
http: typeof http;
|
|
3838
3852
|
/**
|
|
3839
3853
|
* Remote's client over HTTP with live, for `clientLayer`: reads, queries,
|
|
3840
3854
|
* and mutations as `http` sends them, live requirements as one `POST`
|
|
3841
3855
|
* answered with a `text/event-stream` of changes.
|
|
3842
3856
|
* `foldkit-remote-server/fetch` is the other end.
|
|
3843
3857
|
*/
|
|
3844
|
-
httpWithLive:
|
|
3858
|
+
httpWithLive: typeof httpWithLive;
|
|
3845
3859
|
clientLayer: <R = never>(client: RemoteRpcClient<R, RpcClientError.RpcClientError>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, never, R>;
|
|
3846
3860
|
/**
|
|
3847
3861
|
* Wraps a `RemoteClient` layer so its reads coalesce: requirements issued
|
|
3848
3862
|
* together become one batch, and a requirement already in flight is joined.
|
|
3849
3863
|
* `Remote.clientLayer` applies this; use it on a hand-written client.
|
|
3850
3864
|
*/
|
|
3851
|
-
coalesced:
|
|
3865
|
+
coalesced: typeof coalescedLayer;
|
|
3852
3866
|
/**
|
|
3853
3867
|
* A Foldkit Subscription entry that keeps the cache to what the active
|
|
3854
3868
|
* Surfaces reach. `projections` are the ones the application observes (the
|
|
@@ -3901,9 +3915,9 @@ declare const Remote: {
|
|
|
3901
3915
|
/** The `RemoteMessage` that merges a query page into its connection. */
|
|
3902
3916
|
queryMessage: <Name extends string, Input>(ref: QueryRef<Name, Input>, result: Schema.Schema.Type<typeof QueryResult>, select?: RelationRequirement | undefined, now?: number | undefined) => RemoteMessage;
|
|
3903
3917
|
/** A pure, serializable view of the whole cache. */
|
|
3904
|
-
inspect:
|
|
3918
|
+
inspect: typeof inspectRemote;
|
|
3905
3919
|
/** A pure, serializable view of one entity, or `undefined` if unknown. */
|
|
3906
|
-
inspectEntity:
|
|
3920
|
+
inspectEntity: typeof inspectEntity;
|
|
3907
3921
|
/**
|
|
3908
3922
|
* Runs a mutation through `RemoteClient`, decoding its typed Output and
|
|
3909
3923
|
* returning the result's normalized patches so the caller can reconcile them
|
|
@@ -3923,7 +3937,7 @@ declare const Remote: {
|
|
|
3923
3937
|
readonly entity: string;
|
|
3924
3938
|
readonly id: string;
|
|
3925
3939
|
}[];
|
|
3926
|
-
},
|
|
3940
|
+
}, RemoteForbidden | RemoteMutationError, RemoteClient>;
|
|
3927
3941
|
/**
|
|
3928
3942
|
* Runs a mutation and reconciles its patches into a `RemoteModel` in one step,
|
|
3929
3943
|
* returning the new model alongside the typed Output. The model-level form of
|
|
@@ -3934,7 +3948,7 @@ declare const Remote: {
|
|
|
3934
3948
|
mutateInto: <Name extends string, Input, Output, AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store, string>, model: AppModel, mutation: MutationDescriptor<Name, Input, Output, unknown>, input: Input, requestId: string, options?: MutateOptions | undefined) => Effect.Effect<{
|
|
3935
3949
|
output: Output;
|
|
3936
3950
|
model: AppModel;
|
|
3937
|
-
},
|
|
3951
|
+
}, RemoteForbidden | RemoteMutationError, RemoteClient>;
|
|
3938
3952
|
/**
|
|
3939
3953
|
* A Foldkit Subscription entry that plans a Surface's missing fields from the
|
|
3940
3954
|
* Model and fetches them through `RemoteClient`, emitting a `RemoteMessage`
|
|
@@ -3956,5 +3970,5 @@ declare const Remote: {
|
|
|
3956
3970
|
live: <AppModel, Store extends RemoteModel, Names extends string, Model, SurfaceMessage, Params, Message = RemoteMessage>(bound: BoundRemote<AppModel, Store, Names>, surface: Surface<AppModel, Model, SurfaceMessage, Params>, params: Params, toMessage?: (message: RemoteMessage) => Message, options?: LiveOptions) => EntryWithoutKeepAlive<AppModel, Message, LiveDependencies, RemoteClient>;
|
|
3957
3971
|
};
|
|
3958
3972
|
//#endregion
|
|
3959
|
-
export {
|
|
3960
|
-
//# sourceMappingURL=index-
|
|
3973
|
+
export { QueryExplanation as $, terminal as $i, coalesceReads as $n, ConnectionOverlay as $r, Entity$2 as $t, RemoteWiring as A, patchOfWrite as Ai, RemoteRpcClient as An, SettledFields as Ar, remoteModelSchema as At, liveFetch as B, Cursor as Bi, LiveEvent as Bn, ConnectionSpec as Br, SnapshotOptions as Bt, Registered as C, SchemaOrFields as Ci, isRefPage as Cn, RemoteForbidden as Cr, noFailures as Ct, RemoteEntry as D, failMutation as Di, relationShape as Dn, RemoteQueryError as Dr, refreshedAt as Dt, RemoteDomain as E, emptyMutationState as Ei, relationAlias as En, RemoteProtocolError as Er, refreshIsInFlight as Et, SubscriptionsOptions as F, RemoteError as Fi, remoteError as Fn, RemoteConnections as Fr, writeRead as Ft, RemotePolicy as G, edge as Gi, classifyLive as Gn, QueryDescriptor as Gr, reachable as Gt, RemoteJsonRequest as H, EdgeRef as Hi, LiveState as Hn, LiveInsertion as Hr, Retained as Ht, RowPlace as I, remoteDataSchema as Ii, BoundaryCounts as In, RemoteRequirements as Ir, MergePolicy as It, PlanOptions as J, hasPrevious as Ji, liveHasPrevious as Jn, QueryWindow as Jr, Matched as Jt, Deadline as K, emptyConnection as Ki, emptyLiveState as Kn, QueryInputs as Kr, Belongs as Kt, placeIn as L, remoteErrorSchema as Li, ConnectionApplied as Ln, Requirement as Lr, REMOTE_CACHE_VERSION as Lt, SatisfyOptions as M, schemaOf as Mi, connectionChangeOf as Mn, WireBoundary as Mr, updateRemote as Mt, SelectsEntity as N, Freshness as Ni, liveEventOf as Nn, ConnectionRequirement as Nr, windowGrowthKey as Nt, RemoteFold as O, mutationStatus as Oi, targetsOf as On, RemoteReadError as Or, remoteMessageCases as Ot, SubscriptionEntries as P, RemoteData as Pi, mutateRemote as Pn, RelationRequirement as Pr, withRefreshRequested as Pt, ExplainedDependencies as Q, segment as Qi, coalesceQueries as Qn, ConnectionIdentity as Qr, AnySchema as Qt, LiveFetchOptions as R, Boundary as Ri, EntityApplied as Rn, connectionsOf as Rr, RemotePersistence as Rt, ReadMeta as S, Refusal as Si, aliasedField as Sn, RelationRequest as Sr, isRemoteMessage as St, RemoteDescriptor as T, beginMutation as Ti, refsIn as Tn, RemoteMutationError as Tr, overlaysOf as Tt, RemoteJsonSend as U, Segment as Ui, applyConnectionEvent as Un, LivePolicy as Ur, RetentionRoots as Ut, RemoteJsonAnswer as V, Edge as Vi, LiveOutcome as Vn, IDENTITY_SEPARATOR as Vr, ConnectionRoot as Vt, RemoteResumePart as W, cursor as Wi, applyEntityEvent as Wn, Query$1 as Wr, gc as Wt, plan as X, items as Xi, CoalesceOptions as Xn, stableStringify as Xr, belongsEncoded as Xt, deadlineOf as Y, isGapped as Yi, BatchRead as Yn, ResultOf as Yr, MatchingOptions as Yt, windowKey as Z, merge as Zi, QueryRun as Zn, ConnectionChange as Zr, matching as Zt, QueryOptions as _, setStale as _a, MutationDescriptor as _i, RefParts as _n, REMOTE_PROTOCOL_VERSION as _r, invalidateConnections as _t, EntitySelection as a, clearStale as aa, beginOptimistic as ai, RefPage as an, LiveRequirement as ar, PlacedOrder as at, QueryWindowOptions as b, writeEntities as ba, NormalizedPatch as bi, RelationKind as bn, ReadBatchResult as br, isLoadingThrough as bt, LiveOptions as c, entry as ca, pruneOverlays as ci, SelectionOf as cn, Mutate as cr, RemoteMessage as ct, MutateOptions as d, isFieldUnavailable as da, settleFailure as di, assemble as dn, NormalizedEntity as dr, RemoteModel as dt, unknown as ea, EntityLayer as ei, EntityDescriptor as en, requirementKey as er, ReadDiagnosis as et, MutationStarted as f, isTombstone as fa, settleSuccess as fi, pageSchema as fn, PageSize as fr, StreamHealth as ft, QueryInput as g, remove as ga, MutationAnswer as gi, RefPageValue as gn, QueryRpc as gr, initialRemoteModel as gt, QueryEntity as h, readField as ha, Mutation as hi, RELATION_ALIAS as hn, QueryResult as hr, forgetRemote as ht, EntityLike as i, EntityWrite as ia, addOverlay as ii, RefKey as in, LiveEdge as ir, Failures as it, RetainOptions as j, reconcileMutation as ji, coalescedLayer as jn, WindowSchema as jr, retentionRootsSchema as jt, RemoteUnsatisfied as k, optimisticOfWrite as ki, RemoteClient as kn, RemoteRpc as kr, remoteMessageSchema as kt, LiveStatus as l, hasField as la, removeLayer as li, SelectionValue as ln, MutationRequest as lr, RemoteMessageInput as lt, PersistenceOptions as m, missingFields as ma, visibleStore as mi, unavailableOf as mn, QueryRequest as mr, failureOf as mt, BoundRemote as n, EntityKey as na, OptimisticState as ni, EntityRef as nn, Live as nr, inspectEntity as nt, FoldedMutationStarted as o, emptyStore as oa, connectionIdentity as oi, Page as on, MAX_FIELDS_PER_REQUEST as or, PlacementMismatch as ot, ObserveOptions as p, markStale as pa, visibleItems as pi, relationOf as pn, QueryEdge as pr, emptyRefresh as pt, PlanFreshness as q, hasNext as qi, liveHasNext as qn, QueryRef as qr, Judged as qt, DomainMutateOptions as r, EntityStore as ra, addLayer as ri, FieldsFrom as rn, LiveChange as rr, inspectRemote as rt, LiveDependencies as s, entityKey as sa, emptyOptimistic as si, Selection as sn, MAX_RELATION_DEPTH as sr, RefreshState as st, ActiveEntry as t, EntityEntry as ta, OptimisticOperation as ti, EntityPatch as tn, ConnectionChangeSchema as tr, RemoteInspection as tt, ModelOfDomain as u, isFieldStale as ua, removeOverlay as ui, SelectionValueOf as un, MutationResult as ur, RemoteMessageTag as ut, QueryProjection as v, setUnavailable as va, MutationState as vi, RelationAnnotation as vn, Read as vr, isFieldFailed as vt, Remote as w, TypeOf as wi, refParts as wn, RemoteLiveError as wr, onlyOverlaid as wt, ReadDependencies as x, writeEntity as xa, Reconciled as xi, RelationShape as xn, ReadRequest as xr, isQueryLoading as xt, QueryRequirement as y, tombstone as ya, MutationStatus as yi, RelationEntityAnnotation as yn, ReadBatch as yr, isLoading as yt, httpWithLive as z, Connection as zi, LiveCursor as zn, requirementsOf as zr, Snapshot as zt };
|
|
3974
|
+
//# sourceMappingURL=index-eVkkbhPA.d.mts.map
|