foldkit-remote 0.1.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.
@@ -0,0 +1,2000 @@
1
+ import { Context, Duration, Effect, Layer, Option, Schema, Stream } from "effect";
2
+ import { ActiveSurface, ConnectionRequirement, Contract, Invalid, ModelRef, Projection, RelationRequirement, RelationRequirement as RelationRequirement$1, Requirement, Requirement as Requirement$1, Surface } from "foldkit-surface";
3
+ import { Rpc, RpcGroup } from "effect/unstable/rpc";
4
+ import { KeyValueStore } from "effect/unstable/persistence";
5
+ import { Command } from "foldkit/command";
6
+ import { EntryWithoutKeepAlive } from "foldkit/subscription";
7
+ //#region src/connection.d.ts
8
+ export interface EdgeRef {
9
+ readonly entity: string;
10
+ readonly id: string;
11
+ }
12
+ /** `key` is the edge identity used for de-duplication. */
13
+ export interface Edge {
14
+ readonly key: string;
15
+ readonly ref: EdgeRef;
16
+ }
17
+ export declare const edge: (ref: EdgeRef, key?: string) => Edge;
18
+ export type Cursor = string;
19
+ export type Boundary = {
20
+ readonly _tag: 'Terminal';
21
+ } | {
22
+ readonly _tag: 'Cursor';
23
+ readonly cursor: Cursor;
24
+ } | {
25
+ readonly _tag: 'Unknown';
26
+ };
27
+ export declare const terminal: Boundary;
28
+ export declare const unknown: Boundary;
29
+ export declare const cursor: (value: Cursor) => Boundary;
30
+ export interface Segment {
31
+ readonly edges: readonly Edge[];
32
+ readonly start: Boundary;
33
+ readonly end: Boundary;
34
+ }
35
+ export interface Connection {
36
+ readonly segments: readonly Segment[];
37
+ readonly stale: boolean;
38
+ }
39
+ export declare const emptyConnection: Connection;
40
+ export declare const segment: (edges: readonly Edge[], start: Boundary, end: Boundary) => Segment;
41
+ /** Adds a page to the connection, joining contiguous or overlapping segments. */
42
+ export declare const merge: (current: Connection, page: Segment) => Connection;
43
+ /** Visible edges, segment by segment. */
44
+ export declare const items: (connection: Connection) => ReadonlyArray<Edge>;
45
+ /** There is more before the known region. Derived from boundaries, never row count. */
46
+ export declare const hasPrevious: (connection: Connection) => boolean;
47
+ /** There is more after the known region. Derived from boundaries, never row count. */
48
+ export declare const hasNext: (connection: Connection) => boolean;
49
+ /** A connection with more than one segment has an explicit unknown gap. */
50
+ export declare const isGapped: (connection: Connection) => boolean;
51
+ //#endregion
52
+ //#region src/store.d.ts
53
+ export type EntityKey = string;
54
+ export interface EntityEntry {
55
+ readonly values: Readonly<Record<string, unknown>>;
56
+ readonly present: ReadonlySet<string>;
57
+ /** Present fields whose value may be outdated (revalidation needed). */
58
+ readonly stale: ReadonlySet<string>;
59
+ /** The entity is known to be absent; a later write clears this. */
60
+ readonly tombstone: boolean;
61
+ /** Injected clock reading of the last write; never read from ambient state. */
62
+ readonly updatedAt: number;
63
+ /**
64
+ * The canonical window each present field was fetched with (`""` for none).
65
+ * A later request with a *known, different* window is planned as missing.
66
+ */
67
+ readonly windows: Readonly<Record<string, string>>;
68
+ }
69
+ export type EntityStore = Readonly<Record<EntityKey, EntityEntry>>;
70
+ /** The separator keeps an untrusted id from colliding with a prototype key. */
71
+ export declare const entityKey: (entity: string, id: string) => EntityKey;
72
+ export declare const emptyStore: EntityStore;
73
+ export interface EntityWrite {
74
+ readonly key: EntityKey;
75
+ readonly values: Readonly<Record<string, unknown>>;
76
+ /** The canonical window each written relation field was fetched with. */
77
+ readonly windows?: Readonly<Record<string, string>> | undefined;
78
+ }
79
+ /**
80
+ * Merges known values into many entities, copying the store once. Every
81
+ * written field becomes present and non-stale; a tombstone is cleared because
82
+ * the entity is evidently not absent.
83
+ */
84
+ export declare const writeEntities: (store: EntityStore, writes: ReadonlyArray<EntityWrite>, now?: number) => EntityStore;
85
+ /** `writeEntities` for one entity. */
86
+ export declare const writeEntity: (store: EntityStore, key: EntityKey, values: Readonly<Record<string, unknown>>, now?: number, windows?: Readonly<Record<string, string>>) => EntityStore;
87
+ /**
88
+ * Marks present fields stale (`true`) or ends their staleness (`false`) across
89
+ * many entities, copying the store once. A field never present stays missing;
90
+ * an unknown entity is left alone.
91
+ */
92
+ export declare const setStale: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, stale: boolean) => EntityStore;
93
+ /** Marks present fields stale; fields that were never present stay missing. */
94
+ export declare const markStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
95
+ /** Ends a refresh that did not land: the fields are present again as they were. */
96
+ export declare const clearStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
97
+ /** Records that the entity is known to be absent, so it is not refetched. */
98
+ export declare const tombstone: (store: EntityStore, key: EntityKey) => EntityStore;
99
+ /** Forgets everything known about the entity, including a tombstone. */
100
+ export declare const remove: (store: EntityStore, key: EntityKey) => EntityStore;
101
+ export declare const entry: (store: EntityStore, key: EntityKey) => Option.Option<EntityEntry>;
102
+ export declare const isTombstone: (store: EntityStore, key: EntityKey) => boolean;
103
+ /** A field is known only if it is present and not stale. */
104
+ export declare const hasField: (store: EntityStore, key: EntityKey, field: string) => boolean;
105
+ /** A present field whose value may be outdated; absent fields are not stale. */
106
+ export declare const isFieldStale: (store: EntityStore, key: EntityKey, field: string) => boolean;
107
+ /**
108
+ * Reads a present field, stale or not. Absence and a tombstone both yield
109
+ * `Option.none()`; a present `undefined`/`null` yields `Option.some`.
110
+ */
111
+ export declare const readField: (store: EntityStore, key: EntityKey, field: string) => Option.Option<unknown>;
112
+ /**
113
+ * The fields the planner must fetch. A tombstone makes every field known
114
+ * (absent), so it returns an empty list and the entity is not refetched. A
115
+ * requested window that differs from the one a field was fetched with also
116
+ * marks it missing, but only when the stored window is known (never `""`), so a
117
+ * writer that does not record windows cannot cause a refetch loop.
118
+ */
119
+ export declare const missingFields: (store: EntityStore, key: EntityKey, fields: Iterable<string>, windows?: Readonly<Record<string, string>>) => ReadonlyArray<string>;
120
+ //#endregion
121
+ //#region src/mutation.d.ts
122
+ export interface NormalizedPatch {
123
+ readonly entity: string;
124
+ readonly id: string;
125
+ readonly values: Readonly<Record<string, unknown>>;
126
+ }
127
+ export interface MutationState {
128
+ readonly pending: ReadonlySet<string>;
129
+ readonly applied: ReadonlySet<string>;
130
+ readonly failed: ReadonlySet<string>;
131
+ /**
132
+ * How many mutations this model has started. A bound domain takes its next
133
+ * request id from here, so `update` stays pure and the id exists before the
134
+ * Command runs.
135
+ */
136
+ readonly sequence: number;
137
+ }
138
+ export declare const emptyMutationState: MutationState;
139
+ export declare const beginMutation: (state: MutationState, requestId: string) => MutationState;
140
+ export declare const failMutation: (state: MutationState, requestId: string) => MutationState;
141
+ export interface Reconciled {
142
+ readonly store: EntityStore;
143
+ readonly state: MutationState;
144
+ }
145
+ /**
146
+ * Applies a mutation result once and marks the request settled. A second call
147
+ * with the same `requestId` (a retry, or a live event describing the same change)
148
+ * does not re-apply the entities, but still clears `pending`.
149
+ */
150
+ export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>) => Reconciled;
151
+ /** A mutation an application declares: its name and input/output codecs. */
152
+ export interface MutationDescriptor<Name extends string, Input, Output> {
153
+ readonly name: Name;
154
+ readonly Input: Schema.Codec<Input>;
155
+ readonly Output: Schema.Codec<Output>;
156
+ }
157
+ /** A codec, or the fields of a `Schema.Struct` where one is expected. */
158
+ export type SchemaOrFields = Schema.Codec<any, any, any, any> | Schema.Struct.Fields;
159
+ /** The decoded type of a codec, or of the Struct the fields describe. */
160
+ export type TypeOf<S extends SchemaOrFields> = S extends Schema.Codec<infer T, any, any, any> ? T : S extends Schema.Struct.Fields ? Schema.Struct.Type<S> : never;
161
+ /** The codec itself, or a `Schema.Struct` over the fields. */
162
+ export declare const schemaOf: <S extends SchemaOrFields>(shape: S) => Schema.Codec<TypeOf<S>>;
163
+ export declare const Mutation: {
164
+ /**
165
+ * Declares a mutation. `Input` and `Output` are codecs, or the fields of the
166
+ * `Schema.Struct` they would be (`{ id: ProjectId, name: Schema.String }`).
167
+ */
168
+ make: <const Name extends string, Input extends SchemaOrFields, Output extends SchemaOrFields>(name: Name, config: {
169
+ readonly Input: Input;
170
+ readonly Output: Output;
171
+ }) => MutationDescriptor<Name, TypeOf<Input>, TypeOf<Output>>;
172
+ };
173
+ //#endregion
174
+ //#region src/optimistic.d.ts
175
+ export interface EntityLayer {
176
+ readonly id: string;
177
+ readonly patches: ReadonlyArray<NormalizedPatch>;
178
+ }
179
+ /**
180
+ * Edges placed outside a connection's server-known region (`prepend`,
181
+ * `append`) or hidden from it (`remove`), owned by the request or live event
182
+ * that produced them.
183
+ */
184
+ export interface ConnectionOverlay {
185
+ readonly id: string;
186
+ readonly connection: string;
187
+ readonly edges: ReadonlyArray<Edge>;
188
+ readonly position: 'prepend' | 'append' | 'remove';
189
+ }
190
+ /** A connection change a request makes optimistically or a mutation result confirms. */
191
+ export type ConnectionChange = {
192
+ readonly _tag: 'Insert';
193
+ readonly connection: string;
194
+ readonly position: 'prepend' | 'append';
195
+ readonly edge: Edge;
196
+ } | {
197
+ readonly _tag: 'Remove';
198
+ readonly connection: string;
199
+ readonly edge: Edge;
200
+ };
201
+ /** What a request changes before the server answers: entity patches and connection changes. */
202
+ export type OptimisticOperation = NormalizedPatch | ConnectionChange;
203
+ /** A connection, by identity string or by anything that carries one (a `QueryRef`). */
204
+ export type ConnectionIdentity = string | {
205
+ readonly identity: string;
206
+ };
207
+ export declare const connectionIdentity: (connection: ConnectionIdentity) => string;
208
+ /**
209
+ * Constructors for connection changes: what a request shows optimistically
210
+ * (`MutateOptions.optimistic`) and what a mutation source reports it made
211
+ * (`MutationOutcome.connections`).
212
+ */
213
+ export declare const ConnectionChange: {
214
+ /** Show `ref` at the front of the connection until the request settles. */
215
+ prepend: (connection: ConnectionIdentity, ref: {
216
+ readonly entity: string;
217
+ readonly id: string;
218
+ }) => ConnectionChange;
219
+ /** Show `ref` at the end of the connection until the request settles. */
220
+ append: (connection: ConnectionIdentity, ref: {
221
+ readonly entity: string;
222
+ readonly id: string;
223
+ }) => ConnectionChange;
224
+ /** Hide `ref` from the connection until the request settles. */
225
+ remove: (connection: ConnectionIdentity, ref: {
226
+ readonly entity: string;
227
+ readonly id: string;
228
+ }) => ConnectionChange;
229
+ };
230
+ /**
231
+ * Applies a request's operations: its patches become one layer and its
232
+ * connection changes become overlays, all owned by `requestId` so settling
233
+ * removes every one of them together.
234
+ */
235
+ export declare const beginOptimistic: (optimistic: OptimisticState, requestId: string, operations: ReadonlyArray<OptimisticOperation>) => OptimisticState;
236
+ /** Pending entity layers and connection overlays over the base store. */
237
+ export interface OptimisticState {
238
+ readonly layers: ReadonlyArray<EntityLayer>;
239
+ readonly overlays: ReadonlyArray<ConnectionOverlay>;
240
+ }
241
+ export declare const emptyOptimistic: OptimisticState;
242
+ export declare const addLayer: (optimistic: OptimisticState, layer: EntityLayer) => OptimisticState;
243
+ export declare const removeLayer: (optimistic: OptimisticState, id: string) => OptimisticState;
244
+ export declare const addOverlay: (optimistic: OptimisticState, overlay: ConnectionOverlay) => OptimisticState;
245
+ export declare const removeOverlay: (optimistic: OptimisticState, id: string) => OptimisticState;
246
+ /** Base store with every layer applied in order. Later layers win. */
247
+ export declare const visibleStore: (base: EntityStore, optimistic: OptimisticState) => EntityStore;
248
+ /**
249
+ * A fresh page is newer than any settled overlay it covers: an edge the page
250
+ * carries no longer needs an insert overlay, and a `remove` overlay hiding it
251
+ * is stale (the server says it is back). A pending request's overlays are
252
+ * left alone; they settle with the request.
253
+ */
254
+ export declare const pruneOverlays: (optimistic: OptimisticState, connection: string, covered: ReadonlySet<string>, pending: ReadonlySet<string>) => OptimisticState;
255
+ /**
256
+ * Applies a result idempotently and releases the request's layer and overlays:
257
+ * a later layer re-wins on rebase. Confirmed connection changes are recorded
258
+ * once per request, as overlays the request no longer owns.
259
+ */
260
+ export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>) => {
261
+ readonly store: EntityStore;
262
+ readonly state: MutationState;
263
+ readonly optimistic: OptimisticState;
264
+ };
265
+ /** A failed request's layer and overlays are dropped; the base was never mutated. */
266
+ export declare const settleFailure: (optimistic: OptimisticState, requestId: string) => OptimisticState;
267
+ /**
268
+ * Visible edges for one connection: applicable overlays are placed outside the
269
+ * server-known segments and de-duplicated by edge identity (across overlays too),
270
+ * so a pending insert never corrupts server-known ordering; a `remove` overlay
271
+ * hides its edges wherever they are, and so does a tombstone on the edge's
272
+ * target when `store` is given. A later prepend lands before an earlier one, a
273
+ * later append after, so pending inserts read in the order they were made.
274
+ * Boundaries still come from the connection's segments.
275
+ */
276
+ export declare const visibleItems: (connection: Connection, connectionId: string, overlays: ReadonlyArray<ConnectionOverlay>, store?: EntityStore) => ReadonlyArray<Edge>;
277
+ //#endregion
278
+ //#region src/query.d.ts
279
+ export type LiveInsertion = 'visible' | 'boundary' | 'invalidate' | 'ignore';
280
+ export interface LivePolicy {
281
+ readonly prepend?: LiveInsertion;
282
+ readonly append?: LiveInsertion;
283
+ }
284
+ export interface ConnectionSpec<Entity extends string = string> {
285
+ readonly entity: Entity;
286
+ readonly edgeKey?: Schema.Schema<unknown>;
287
+ readonly live?: LivePolicy;
288
+ }
289
+ export interface QueryWindow {
290
+ readonly first?: number | undefined;
291
+ readonly last?: number | undefined;
292
+ readonly after?: Cursor | undefined;
293
+ readonly before?: Cursor | undefined;
294
+ }
295
+ export interface QueryRef<Name extends string, Input> {
296
+ readonly query: Name;
297
+ readonly input: Input;
298
+ /** The input codec, so a `QueryRef` can encode itself without its descriptor. */
299
+ readonly Input: Schema.Codec<Input>;
300
+ readonly window: QueryWindow;
301
+ /** Connection identity: descriptor + canonical input, excluding the window. */
302
+ readonly identity: string;
303
+ }
304
+ export interface QueryDescriptor<Name extends string, Input, Result> {
305
+ readonly name: Name;
306
+ readonly Input: Schema.Codec<Input>;
307
+ readonly Result: Result;
308
+ readonly ref: (input: Input) => QueryRef<Name, Input>;
309
+ }
310
+ /** Stable stringify: object keys sorted, undefined-valued keys dropped, so equal inputs encode equally. */
311
+ export declare const stableStringify: (value: unknown) => string;
312
+ /**
313
+ * `Result: Project` (or anything with the entity's `name`, as `Query.connection`
314
+ * takes) means a connection over it; a `ConnectionSpec` names its `entity`
315
+ * instead and is the result as given.
316
+ */
317
+ export type ResultOf<Result> = Result extends {
318
+ readonly name: infer Entity extends string;
319
+ } ? ConnectionSpec<Entity> : Result;
320
+ export declare const Query: {
321
+ /** Declares the entity and options a query's result is a connection over. */
322
+ connection: <Entity extends string>(entity: {
323
+ readonly name: Entity;
324
+ }, options?: {
325
+ readonly edgeKey?: Schema.Schema<unknown>;
326
+ readonly live?: LivePolicy;
327
+ }) => ConnectionSpec<Entity>;
328
+ /**
329
+ * Declares a query. `Input` is a codec or the fields of the `Schema.Struct` it
330
+ * would be; `Result` is a `Query.connection(...)`, or the entity the result is
331
+ * a connection over.
332
+ */
333
+ make: <const Name extends string, Input extends SchemaOrFields, Result>(name: Name, config: {
334
+ readonly Input: Input;
335
+ readonly Result: Result;
336
+ }) => QueryDescriptor<Name, TypeOf<Input>, ResultOf<Result>>;
337
+ first: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
338
+ last: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
339
+ after: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
340
+ before: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
341
+ };
342
+ //#endregion
343
+ //#region src/live.d.ts
344
+ export type LiveCursor = number;
345
+ export type LiveEvent = {
346
+ readonly _tag: 'EntityPatched';
347
+ readonly ref: EdgeRef;
348
+ readonly values: Readonly<Record<string, unknown>>;
349
+ readonly changed: ReadonlyArray<string>;
350
+ readonly cursor: LiveCursor;
351
+ } | {
352
+ readonly _tag: 'EntityDeleted';
353
+ readonly ref: EdgeRef;
354
+ readonly cursor: LiveCursor;
355
+ } | {
356
+ readonly _tag: 'ConnectionInsert';
357
+ readonly connection: string;
358
+ readonly position: 'prepend' | 'append';
359
+ readonly edge: Edge;
360
+ readonly cursor: LiveCursor;
361
+ } | {
362
+ readonly _tag: 'ConnectionRemove';
363
+ readonly connection: string;
364
+ readonly edge: Edge;
365
+ readonly cursor: LiveCursor;
366
+ } | {
367
+ readonly _tag: 'ConnectionInvalidate';
368
+ readonly connection: string;
369
+ readonly cursor: LiveCursor;
370
+ };
371
+ export interface BoundaryCounts {
372
+ readonly before: number;
373
+ readonly after: number;
374
+ }
375
+ export interface LiveState {
376
+ /** Last applied cursor for this stream. */
377
+ readonly cursor: LiveCursor;
378
+ /** Connections marked stale by an invalidating event. */
379
+ readonly stale: ReadonlySet<string>;
380
+ /** Edges recorded outside the loaded boundary, not visible in `items`. */
381
+ readonly boundary: Readonly<Record<string, BoundaryCounts>>;
382
+ }
383
+ export declare const emptyLiveState: LiveState;
384
+ export type LiveOutcome = 'applied' | 'duplicate' | 'gap';
385
+ /**
386
+ * Ordering per stream: at most the next cursor; ahead is a gap. Cursor `0` means
387
+ * "no baseline yet" (cursors are 1-based), so the first event of a stream is
388
+ * accepted whatever its cursor — otherwise a stream not starting at 1 would be a
389
+ * spurious gap.
390
+ */
391
+ export declare const classifyLive: (state: LiveState, cursor: LiveCursor) => LiveOutcome;
392
+ export declare const invalidateConnection: (state: LiveState, connection: string) => LiveState;
393
+ /**
394
+ * A subscriber is woken only if the event changed a field it selects. A
395
+ * change to an unselected field is skipped entirely.
396
+ */
397
+ export declare const shouldWake: (changed: ReadonlyArray<string>, selected: ReadonlyArray<string>) => boolean;
398
+ export interface EntityApplied {
399
+ readonly state: LiveState;
400
+ readonly store: EntityStore;
401
+ readonly outcome: LiveOutcome;
402
+ }
403
+ export declare const applyEntityEvent: (state: LiveState, store: EntityStore, event: Extract<LiveEvent, {
404
+ _tag: "EntityPatched" | "EntityDeleted";
405
+ }>, now?: number) => EntityApplied;
406
+ export interface ConnectionApplied {
407
+ readonly state: LiveState;
408
+ readonly optimistic: OptimisticState;
409
+ readonly outcome: LiveOutcome;
410
+ }
411
+ export declare const applyConnectionEvent: (state: LiveState, optimistic: OptimisticState, event: Extract<LiveEvent, {
412
+ _tag: "ConnectionInsert" | "ConnectionRemove" | "ConnectionInvalidate";
413
+ }>, policy?: LivePolicy) => ConnectionApplied;
414
+ export declare const isStale: (state: LiveState, connection: string) => boolean;
415
+ /**
416
+ * Clears a connection's stale mark once a fresh page has been adopted. An
417
+ * invalidating event only records that a refetch is due; whoever merges the
418
+ * refetched page calls this so `isStale` stops reporting.
419
+ */
420
+ export declare const refreshConnection: (state: LiveState, connection: string) => LiveState;
421
+ /** `hasPrevious` accounting for edges recorded outside the loaded boundary. */
422
+ export declare const liveHasPrevious: (connection: Connection, state: LiveState, connectionId: string) => boolean;
423
+ /** `hasNext` accounting for edges recorded outside the loaded boundary. */
424
+ export declare const liveHasNext: (connection: Connection, state: LiveState, connectionId: string) => boolean;
425
+ //#endregion
426
+ //#region src/retain.d.ts
427
+ /** A connection to keep: its identity, and what a page of it selects of each item, if a projection reads it. */
428
+ export interface ConnectionRoot {
429
+ readonly identity: string;
430
+ readonly select?: RelationRequirement$1 | undefined;
431
+ }
432
+ export interface RetentionRoots {
433
+ readonly requirements: ReadonlyArray<Requirement$1>;
434
+ /** Connections (`QueryRef.identity`) to keep, with their edges' targets and what `select` reaches through them. */
435
+ readonly connections: ReadonlyArray<ConnectionRoot>;
436
+ }
437
+ export interface Retained {
438
+ readonly entities: EntityStore;
439
+ readonly connections: Readonly<Record<string, Connection>>;
440
+ readonly optimistic: OptimisticState;
441
+ }
442
+ /**
443
+ * The entity keys the roots reach: each root entity, the targets its retained
444
+ * fields refer to, and recursively the targets a nested relation selects.
445
+ */
446
+ export declare const reachable: (store: EntityStore, roots: RetentionRoots, connections: Readonly<Record<string, Connection>>, optimistic: OptimisticState, pending: ReadonlySet<string>) => ReadonlySet<EntityKey>;
447
+ /**
448
+ * Drops every entity the roots do not reach, every connection they do not
449
+ * name, and every settled overlay on a dropped connection, keeping whatever a
450
+ * pending request's layer or overlays touch. Pure.
451
+ */
452
+ export declare const gc: (state: Retained & {
453
+ readonly mutations: MutationState;
454
+ }, roots: RetentionRoots) => Retained;
455
+ //#endregion
456
+ //#region src/persistence.d.ts
457
+ /** Bump when the serialized shape changes; a mismatch discards the cache. */
458
+ export declare const REMOTE_CACHE_VERSION = 3;
459
+ export interface SnapshotOptions {
460
+ /**
461
+ * Who or what the snapshot is for (a user id, a tenant, a build). A snapshot
462
+ * taken under another scope is discarded rather than shown to the wrong
463
+ * reader. Default: unscoped, which only matches unscoped.
464
+ */
465
+ readonly scope?: string | undefined;
466
+ /** Snapshots larger than this many bytes are not written and not read. */
467
+ readonly maxBytes?: number | undefined;
468
+ }
469
+ /** How a snapshot meets a store that already has entries. */
470
+ export type MergePolicy = 'replace' | 'preserve-existing';
471
+ export declare const RemotePersistence: {
472
+ /** The snapshot text, or `undefined` when it would exceed `maxBytes`. */
473
+ dehydrate: (store: EntityStore, options?: SnapshotOptions) => string | undefined;
474
+ /** The store a snapshot text holds, or `undefined` when it is refused. */
475
+ hydrate: (raw: string | undefined | null, options?: SnapshotOptions) => EntityStore | undefined;
476
+ /** A snapshot brought into a store by policy. */
477
+ mergeStores: (current: EntityStore, snapshot: EntityStore, policy: MergePolicy) => EntityStore;
478
+ /**
479
+ * Writes the snapshot under `key`, or removes the key when the store would
480
+ * exceed `maxBytes`, so a stale smaller snapshot cannot outlive a larger
481
+ * store it no longer describes.
482
+ */
483
+ save: (store: EntityStore, options: {
484
+ readonly key: string;
485
+ } & SnapshotOptions) => Effect.Effect<void, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
486
+ /**
487
+ * Reads the cache. A missing key yields `emptyStore`; anything `hydrate`
488
+ * refuses yields `emptyStore` and removes the key, so the next `restore` is
489
+ * clean and the planner refetches.
490
+ */
491
+ restore: (options: {
492
+ readonly key: string;
493
+ } & SnapshotOptions) => Effect.Effect<Readonly<Record<string, EntityEntry>>, KeyValueStore.KeyValueStoreError, KeyValueStore.KeyValueStore>;
494
+ };
495
+ //#endregion
496
+ //#region src/wire.d.ts
497
+ /**
498
+ * The read/live protocol version. A batch names the version it speaks and the
499
+ * server refuses a mismatch with `RemoteProtocolError`, so a shape change never
500
+ * drifts silently: bump it whenever `ReadRequest` or `LiveRequirement` change.
501
+ */
502
+ export declare const REMOTE_PROTOCOL_VERSION = 3;
503
+ declare const RemoteReadError_base: Schema.Class<RemoteReadError, Schema.TaggedStruct<"RemoteReadError", {
504
+ readonly message: Schema.String;
505
+ }>, import("effect/Cause").YieldableError>;
506
+ export declare class RemoteReadError extends RemoteReadError_base {}
507
+ declare const RemoteMutationError_base: Schema.Class<RemoteMutationError, Schema.TaggedStruct<"RemoteMutationError", {
508
+ readonly message: Schema.String;
509
+ }>, import("effect/Cause").YieldableError>;
510
+ export declare class RemoteMutationError extends RemoteMutationError_base {}
511
+ declare const RemoteLiveError_base: Schema.Class<RemoteLiveError, Schema.TaggedStruct<"RemoteLiveError", {
512
+ readonly message: Schema.String;
513
+ }>, import("effect/Cause").YieldableError>;
514
+ export declare class RemoteLiveError extends RemoteLiveError_base {}
515
+ declare const RemoteProtocolError_base: Schema.Class<RemoteProtocolError, Schema.TaggedStruct<"RemoteProtocolError", {
516
+ readonly message: Schema.String;
517
+ readonly expected: Schema.Number;
518
+ readonly received: Schema.Number;
519
+ }>, import("effect/Cause").YieldableError>;
520
+ /** The peer speaks another protocol version; nothing was read. */
521
+ export declare class RemoteProtocolError extends RemoteProtocolError_base {}
522
+ /** A page size: a non-negative integer, refused at decode otherwise rather than defaulted. */
523
+ export declare const PageSize: Schema.Number;
524
+ export declare const WindowSchema: Schema.Struct<{
525
+ readonly first: Schema.optional<Schema.Number>;
526
+ readonly last: Schema.optional<Schema.Number>;
527
+ readonly after: Schema.optional<Schema.String>;
528
+ readonly before: Schema.optional<Schema.String>;
529
+ }>;
530
+ /** A request may not name more fields of one entity than this; a selection never does. */
531
+ export declare const MAX_FIELDS_PER_REQUEST = 256;
532
+ /** A selection may not nest relations deeper than this; the wire refuses more. */
533
+ export declare const MAX_RELATION_DEPTH = 8;
534
+ export declare const RelationRequest: Schema.Codec<RelationRequirement$1, RelationRequirement$1, never, never>;
535
+ export declare const ReadRequest: Schema.Codec<Requirement$1, Requirement$1>;
536
+ export declare const ReadBatch: Schema.Struct<{
537
+ readonly version: Schema.Number;
538
+ readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
539
+ }>;
540
+ export declare const NormalizedEntity: Schema.Struct<{
541
+ readonly entity: Schema.String;
542
+ readonly id: Schema.String;
543
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
544
+ }>;
545
+ export declare const ReadBatchResult: Schema.Struct<{
546
+ readonly entities: Schema.$Array<Schema.Struct<{
547
+ readonly entity: Schema.String;
548
+ readonly id: Schema.String;
549
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
550
+ }>>;
551
+ }>;
552
+ export declare const MutationRequest: Schema.Struct<{
553
+ /** Stable across transport retries so a mutation is not applied twice. */
554
+ readonly requestId: Schema.String;
555
+ readonly mutation: Schema.String;
556
+ readonly input: Schema.Unknown;
557
+ }>;
558
+ export declare const LiveEdge: Schema.Struct<{
559
+ readonly entity: Schema.String;
560
+ readonly id: Schema.String;
561
+ readonly key: Schema.String;
562
+ }>;
563
+ /** A connection change a mutation confirms: the same facts a live event carries, without a cursor. */
564
+ export declare const ConnectionChangeSchema: Schema.Union<readonly [Schema.Struct<{
565
+ readonly _tag: Schema.Literal<"Insert">;
566
+ readonly connection: Schema.String;
567
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
568
+ readonly edge: Schema.Struct<{
569
+ readonly entity: Schema.String;
570
+ readonly id: Schema.String;
571
+ readonly key: Schema.String;
572
+ }>;
573
+ }>, Schema.Struct<{
574
+ readonly _tag: Schema.Literal<"Remove">;
575
+ readonly connection: Schema.String;
576
+ readonly edge: Schema.Struct<{
577
+ readonly entity: Schema.String;
578
+ readonly id: Schema.String;
579
+ readonly key: Schema.String;
580
+ }>;
581
+ }>]>;
582
+ export declare const MutationResult: Schema.Struct<{
583
+ readonly output: Schema.Unknown;
584
+ readonly entities: Schema.$Array<Schema.Struct<{
585
+ readonly entity: Schema.String;
586
+ readonly id: Schema.String;
587
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
588
+ }>>;
589
+ /** Connection changes the mutation made, applied alongside its entity patches. */
590
+ readonly connections: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
591
+ readonly _tag: Schema.Literal<"Insert">;
592
+ readonly connection: Schema.String;
593
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
594
+ readonly edge: Schema.Struct<{
595
+ readonly entity: Schema.String;
596
+ readonly id: Schema.String;
597
+ readonly key: Schema.String;
598
+ }>;
599
+ }>, Schema.Struct<{
600
+ readonly _tag: Schema.Literal<"Remove">;
601
+ readonly connection: Schema.String;
602
+ readonly edge: Schema.Struct<{
603
+ readonly entity: Schema.String;
604
+ readonly id: Schema.String;
605
+ readonly key: Schema.String;
606
+ }>;
607
+ }>]>>>;
608
+ }>;
609
+ export declare const LiveRequirement: Schema.Struct<{
610
+ readonly version: Schema.Number;
611
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
612
+ /** Resume cursor; events at or before it are duplicates. */
613
+ readonly after: Schema.Number;
614
+ }>;
615
+ /**
616
+ * A live change. Entity changes update the store; connection changes alter
617
+ * membership and ordering; both carry a per-stream cursor.
618
+ */
619
+ export declare const LiveChange: Schema.Union<readonly [Schema.Struct<{
620
+ readonly _tag: Schema.Literal<"EntityPatched">;
621
+ readonly cursor: Schema.Number;
622
+ readonly entity: Schema.String;
623
+ readonly id: Schema.String;
624
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
625
+ readonly changed: Schema.$Array<Schema.String>;
626
+ }>, Schema.Struct<{
627
+ readonly _tag: Schema.Literal<"EntityDeleted">;
628
+ readonly cursor: Schema.Number;
629
+ readonly entity: Schema.String;
630
+ readonly id: Schema.String;
631
+ }>, Schema.Struct<{
632
+ readonly _tag: Schema.Literal<"ConnectionInsert">;
633
+ readonly cursor: Schema.Number;
634
+ readonly connection: Schema.String;
635
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
636
+ readonly edge: Schema.Struct<{
637
+ readonly entity: Schema.String;
638
+ readonly id: Schema.String;
639
+ readonly key: Schema.String;
640
+ }>;
641
+ }>, Schema.Struct<{
642
+ readonly _tag: Schema.Literal<"ConnectionRemove">;
643
+ readonly cursor: Schema.Number;
644
+ readonly connection: Schema.String;
645
+ readonly edge: Schema.Struct<{
646
+ readonly entity: Schema.String;
647
+ readonly id: Schema.String;
648
+ readonly key: Schema.String;
649
+ }>;
650
+ }>, Schema.Struct<{
651
+ readonly _tag: Schema.Literal<"ConnectionInvalidate">;
652
+ readonly cursor: Schema.Number;
653
+ readonly connection: Schema.String;
654
+ }>]>;
655
+ export declare const Read: Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
656
+ readonly version: Schema.Number;
657
+ readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
658
+ }>, Schema.Struct<{
659
+ readonly entities: Schema.$Array<Schema.Struct<{
660
+ readonly entity: Schema.String;
661
+ readonly id: Schema.String;
662
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
663
+ }>>;
664
+ }>, Schema.Union<readonly [typeof RemoteReadError, typeof RemoteProtocolError]>, never, never>;
665
+ export declare const Mutate: Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
666
+ /** Stable across transport retries so a mutation is not applied twice. */
667
+ readonly requestId: Schema.String;
668
+ readonly mutation: Schema.String;
669
+ readonly input: Schema.Unknown;
670
+ }>, Schema.Struct<{
671
+ readonly output: Schema.Unknown;
672
+ readonly entities: Schema.$Array<Schema.Struct<{
673
+ readonly entity: Schema.String;
674
+ readonly id: Schema.String;
675
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
676
+ }>>;
677
+ /** Connection changes the mutation made, applied alongside its entity patches. */
678
+ readonly connections: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
679
+ readonly _tag: Schema.Literal<"Insert">;
680
+ readonly connection: Schema.String;
681
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
682
+ readonly edge: Schema.Struct<{
683
+ readonly entity: Schema.String;
684
+ readonly id: Schema.String;
685
+ readonly key: Schema.String;
686
+ }>;
687
+ }>, Schema.Struct<{
688
+ readonly _tag: Schema.Literal<"Remove">;
689
+ readonly connection: Schema.String;
690
+ readonly edge: Schema.Struct<{
691
+ readonly entity: Schema.String;
692
+ readonly id: Schema.String;
693
+ readonly key: Schema.String;
694
+ }>;
695
+ }>]>>>;
696
+ }>, typeof RemoteMutationError, never, never>;
697
+ export declare const Live: Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
698
+ readonly version: Schema.Number;
699
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
700
+ /** Resume cursor; events at or before it are duplicates. */
701
+ readonly after: Schema.Number;
702
+ }>, import("effect/unstable/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
703
+ readonly _tag: Schema.Literal<"EntityPatched">;
704
+ readonly cursor: Schema.Number;
705
+ readonly entity: Schema.String;
706
+ readonly id: Schema.String;
707
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
708
+ readonly changed: Schema.$Array<Schema.String>;
709
+ }>, Schema.Struct<{
710
+ readonly _tag: Schema.Literal<"EntityDeleted">;
711
+ readonly cursor: Schema.Number;
712
+ readonly entity: Schema.String;
713
+ readonly id: Schema.String;
714
+ }>, Schema.Struct<{
715
+ readonly _tag: Schema.Literal<"ConnectionInsert">;
716
+ readonly cursor: Schema.Number;
717
+ readonly connection: Schema.String;
718
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
719
+ readonly edge: Schema.Struct<{
720
+ readonly entity: Schema.String;
721
+ readonly id: Schema.String;
722
+ readonly key: Schema.String;
723
+ }>;
724
+ }>, Schema.Struct<{
725
+ readonly _tag: Schema.Literal<"ConnectionRemove">;
726
+ readonly cursor: Schema.Number;
727
+ readonly connection: Schema.String;
728
+ readonly edge: Schema.Struct<{
729
+ readonly entity: Schema.String;
730
+ readonly id: Schema.String;
731
+ readonly key: Schema.String;
732
+ }>;
733
+ }>, Schema.Struct<{
734
+ readonly _tag: Schema.Literal<"ConnectionInvalidate">;
735
+ readonly cursor: Schema.Number;
736
+ readonly connection: Schema.String;
737
+ }>]>, Schema.Union<readonly [typeof RemoteLiveError, typeof RemoteProtocolError]>>, Schema.Never, never, never>;
738
+ declare const RemoteQueryError_base: Schema.Class<RemoteQueryError, Schema.TaggedStruct<"RemoteQueryError", {
739
+ readonly message: Schema.String;
740
+ }>, import("effect/Cause").YieldableError>;
741
+ export declare class RemoteQueryError extends RemoteQueryError_base {}
742
+ export declare const WireBoundary: Schema.Union<readonly [Schema.Struct<{
743
+ readonly _tag: Schema.Literal<"Terminal">;
744
+ }>, Schema.Struct<{
745
+ readonly _tag: Schema.Literal<"Cursor">;
746
+ readonly cursor: Schema.String;
747
+ }>, Schema.Struct<{
748
+ readonly _tag: Schema.Literal<"Unknown">;
749
+ }>]>;
750
+ export declare const QueryRequest: Schema.Struct<{
751
+ readonly query: Schema.String;
752
+ readonly input: Schema.Unknown;
753
+ readonly window: Schema.Struct<{
754
+ readonly first: Schema.optional<Schema.Number>;
755
+ readonly last: Schema.optional<Schema.Number>;
756
+ readonly after: Schema.optional<Schema.String>;
757
+ readonly before: Schema.optional<Schema.String>;
758
+ }>;
759
+ }>;
760
+ export declare const QueryEdge: Schema.Struct<{
761
+ readonly entity: Schema.String;
762
+ readonly id: Schema.String;
763
+ readonly key: Schema.String;
764
+ }>;
765
+ export declare const QueryResult: Schema.Struct<{
766
+ readonly edges: Schema.$Array<Schema.Struct<{
767
+ readonly entity: Schema.String;
768
+ readonly id: Schema.String;
769
+ readonly key: Schema.String;
770
+ }>>;
771
+ readonly start: Schema.Union<readonly [Schema.Struct<{
772
+ readonly _tag: Schema.Literal<"Terminal">;
773
+ }>, Schema.Struct<{
774
+ readonly _tag: Schema.Literal<"Cursor">;
775
+ readonly cursor: Schema.String;
776
+ }>, Schema.Struct<{
777
+ readonly _tag: Schema.Literal<"Unknown">;
778
+ }>]>;
779
+ readonly end: Schema.Union<readonly [Schema.Struct<{
780
+ readonly _tag: Schema.Literal<"Terminal">;
781
+ }>, Schema.Struct<{
782
+ readonly _tag: Schema.Literal<"Cursor">;
783
+ readonly cursor: Schema.String;
784
+ }>, Schema.Struct<{
785
+ readonly _tag: Schema.Literal<"Unknown">;
786
+ }>]>;
787
+ }>;
788
+ export declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
789
+ readonly query: Schema.String;
790
+ readonly input: Schema.Unknown;
791
+ readonly window: Schema.Struct<{
792
+ readonly first: Schema.optional<Schema.Number>;
793
+ readonly last: Schema.optional<Schema.Number>;
794
+ readonly after: Schema.optional<Schema.String>;
795
+ readonly before: Schema.optional<Schema.String>;
796
+ }>;
797
+ }>, Schema.Struct<{
798
+ readonly edges: Schema.$Array<Schema.Struct<{
799
+ readonly entity: Schema.String;
800
+ readonly id: Schema.String;
801
+ readonly key: Schema.String;
802
+ }>>;
803
+ readonly start: Schema.Union<readonly [Schema.Struct<{
804
+ readonly _tag: Schema.Literal<"Terminal">;
805
+ }>, Schema.Struct<{
806
+ readonly _tag: Schema.Literal<"Cursor">;
807
+ readonly cursor: Schema.String;
808
+ }>, Schema.Struct<{
809
+ readonly _tag: Schema.Literal<"Unknown">;
810
+ }>]>;
811
+ readonly end: Schema.Union<readonly [Schema.Struct<{
812
+ readonly _tag: Schema.Literal<"Terminal">;
813
+ }>, Schema.Struct<{
814
+ readonly _tag: Schema.Literal<"Cursor">;
815
+ readonly cursor: Schema.String;
816
+ }>, Schema.Struct<{
817
+ readonly _tag: Schema.Literal<"Unknown">;
818
+ }>]>;
819
+ }>, typeof RemoteQueryError, never, never>;
820
+ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
821
+ readonly version: Schema.Number;
822
+ readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
823
+ }>, Schema.Struct<{
824
+ readonly entities: Schema.$Array<Schema.Struct<{
825
+ readonly entity: Schema.String;
826
+ readonly id: Schema.String;
827
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
828
+ }>>;
829
+ }>, Schema.Union<readonly [typeof RemoteReadError, typeof RemoteProtocolError]>, never, never> | Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
830
+ /** Stable across transport retries so a mutation is not applied twice. */
831
+ readonly requestId: Schema.String;
832
+ readonly mutation: Schema.String;
833
+ readonly input: Schema.Unknown;
834
+ }>, Schema.Struct<{
835
+ readonly output: Schema.Unknown;
836
+ readonly entities: Schema.$Array<Schema.Struct<{
837
+ readonly entity: Schema.String;
838
+ readonly id: Schema.String;
839
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
840
+ }>>;
841
+ /** Connection changes the mutation made, applied alongside its entity patches. */
842
+ readonly connections: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
843
+ readonly _tag: Schema.Literal<"Insert">;
844
+ readonly connection: Schema.String;
845
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
846
+ readonly edge: Schema.Struct<{
847
+ readonly entity: Schema.String;
848
+ readonly id: Schema.String;
849
+ readonly key: Schema.String;
850
+ }>;
851
+ }>, Schema.Struct<{
852
+ readonly _tag: Schema.Literal<"Remove">;
853
+ readonly connection: Schema.String;
854
+ readonly edge: Schema.Struct<{
855
+ readonly entity: Schema.String;
856
+ readonly id: Schema.String;
857
+ readonly key: Schema.String;
858
+ }>;
859
+ }>]>>>;
860
+ }>, typeof RemoteMutationError, never, never> | Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
861
+ readonly version: Schema.Number;
862
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
863
+ /** Resume cursor; events at or before it are duplicates. */
864
+ readonly after: Schema.Number;
865
+ }>, import("effect/unstable/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
866
+ readonly _tag: Schema.Literal<"EntityPatched">;
867
+ readonly cursor: Schema.Number;
868
+ readonly entity: Schema.String;
869
+ readonly id: Schema.String;
870
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
871
+ readonly changed: Schema.$Array<Schema.String>;
872
+ }>, Schema.Struct<{
873
+ readonly _tag: Schema.Literal<"EntityDeleted">;
874
+ readonly cursor: Schema.Number;
875
+ readonly entity: Schema.String;
876
+ readonly id: Schema.String;
877
+ }>, Schema.Struct<{
878
+ readonly _tag: Schema.Literal<"ConnectionInsert">;
879
+ readonly cursor: Schema.Number;
880
+ readonly connection: Schema.String;
881
+ readonly position: Schema.Union<readonly [Schema.Literal<"prepend">, Schema.Literal<"append">]>;
882
+ readonly edge: Schema.Struct<{
883
+ readonly entity: Schema.String;
884
+ readonly id: Schema.String;
885
+ readonly key: Schema.String;
886
+ }>;
887
+ }>, Schema.Struct<{
888
+ readonly _tag: Schema.Literal<"ConnectionRemove">;
889
+ readonly cursor: Schema.Number;
890
+ readonly connection: Schema.String;
891
+ readonly edge: Schema.Struct<{
892
+ readonly entity: Schema.String;
893
+ readonly id: Schema.String;
894
+ readonly key: Schema.String;
895
+ }>;
896
+ }>, Schema.Struct<{
897
+ readonly _tag: Schema.Literal<"ConnectionInvalidate">;
898
+ readonly cursor: Schema.Number;
899
+ readonly connection: Schema.String;
900
+ }>]>, Schema.Union<readonly [typeof RemoteLiveError, typeof RemoteProtocolError]>>, Schema.Never, never, never> | Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
901
+ readonly query: Schema.String;
902
+ readonly input: Schema.Unknown;
903
+ readonly window: Schema.Struct<{
904
+ readonly first: Schema.optional<Schema.Number>;
905
+ readonly last: Schema.optional<Schema.Number>;
906
+ readonly after: Schema.optional<Schema.String>;
907
+ readonly before: Schema.optional<Schema.String>;
908
+ }>;
909
+ }>, Schema.Struct<{
910
+ readonly edges: Schema.$Array<Schema.Struct<{
911
+ readonly entity: Schema.String;
912
+ readonly id: Schema.String;
913
+ readonly key: Schema.String;
914
+ }>>;
915
+ readonly start: Schema.Union<readonly [Schema.Struct<{
916
+ readonly _tag: Schema.Literal<"Terminal">;
917
+ }>, Schema.Struct<{
918
+ readonly _tag: Schema.Literal<"Cursor">;
919
+ readonly cursor: Schema.String;
920
+ }>, Schema.Struct<{
921
+ readonly _tag: Schema.Literal<"Unknown">;
922
+ }>]>;
923
+ readonly end: Schema.Union<readonly [Schema.Struct<{
924
+ readonly _tag: Schema.Literal<"Terminal">;
925
+ }>, Schema.Struct<{
926
+ readonly _tag: Schema.Literal<"Cursor">;
927
+ readonly cursor: Schema.String;
928
+ }>, Schema.Struct<{
929
+ readonly _tag: Schema.Literal<"Unknown">;
930
+ }>]>;
931
+ }>, typeof RemoteQueryError, never, never>>;
932
+ //#endregion
933
+ //#region src/remoteData.d.ts
934
+ export interface RemoteError {
935
+ readonly _tag: string;
936
+ readonly message: string;
937
+ }
938
+ export type RemoteData<A> = {
939
+ readonly _tag: 'Initial';
940
+ } | {
941
+ readonly _tag: 'Loading';
942
+ } | {
943
+ readonly _tag: 'Ready';
944
+ readonly value: A;
945
+ } | {
946
+ readonly _tag: 'Refreshing';
947
+ readonly value: A;
948
+ } | {
949
+ readonly _tag: 'Failed';
950
+ readonly error: RemoteError;
951
+ readonly previous?: A;
952
+ } | {
953
+ readonly _tag: 'NotFound';
954
+ };
955
+ export declare const remoteErrorSchema: Schema.Struct<{
956
+ readonly _tag: Schema.String;
957
+ readonly message: Schema.String;
958
+ }>;
959
+ export declare const remoteDataSchema: <A>(value: Schema.Schema<A>) => Schema.Schema<RemoteData<A>>;
960
+ export declare const RemoteData: {
961
+ /**
962
+ * The `RemoteData` schema for a value schema. Exposed so a `RemoteData` can
963
+ * be embedded in a hand-written Model schema, not only through `Remote.select`.
964
+ */
965
+ schema: <A>(value: Schema.Schema<A>) => Schema.Schema<RemoteData<A>>;
966
+ /** Exhaustive: omitting a state is a compile error. */
967
+ match: <A, R>(data: RemoteData<A>, cases: {
968
+ readonly Initial: () => R;
969
+ readonly Loading: () => R;
970
+ readonly Ready: (value: A) => R;
971
+ readonly Refreshing: (value: A) => R;
972
+ readonly Failed: (error: RemoteError, previous: Option.Option<A>) => R;
973
+ readonly NotFound: () => R;
974
+ }) => R;
975
+ map: <A, B>(data: RemoteData<A>, f: (value: A) => B) => RemoteData<B>;
976
+ };
977
+ //#endregion
978
+ //#region src/model.d.ts
979
+ /**
980
+ * The normalized cache as a Foldkit Submodel. `Remote.make` returns a schema and
981
+ * an `update` for this shape; `Remote.update` reconciles every producer.
982
+ */
983
+ export interface RemoteModel {
984
+ /** Entity values, presence, staleness, tombstones, and applied windows. */
985
+ readonly entities: EntityStore;
986
+ /** Normalized ordered connections, keyed by connection identity. */
987
+ readonly connections: Readonly<Record<string, Connection>>;
988
+ /** Optimistic entity layers and connection overlays over the base store. */
989
+ readonly optimistic: OptimisticState;
990
+ /** Live cursor and boundary state, keyed by the subscription's stream key. */
991
+ readonly live: Readonly<Record<string, LiveState>>;
992
+ /** Mutation pending/applied/failed ledger. */
993
+ readonly mutations: MutationState;
994
+ /** Streams whose live cursor fell behind; the caller should resync or refetch. */
995
+ readonly gaps: ReadonlySet<string>;
996
+ }
997
+ export declare const initialRemoteModel: RemoteModel;
998
+ export declare const remoteModelSchema: () => Schema.Schema<RemoteModel>;
999
+ /** The submodel's Messages; each reduces to `RemoteModel` through `Remote.update`. */
1000
+ export type RemoteMessage = {
1001
+ readonly _tag: 'ReadReceived';
1002
+ readonly requests: readonly Requirement$1[];
1003
+ readonly result: Schema.Schema.Type<typeof ReadBatchResult>;
1004
+ readonly now: number;
1005
+ } | {
1006
+ readonly _tag: 'ReadFailed';
1007
+ readonly requests: readonly Requirement$1[];
1008
+ readonly error: RemoteError;
1009
+ } |
1010
+ /** A refetch of present fields began; they read as `Refreshing` until it lands. */
1011
+ {
1012
+ readonly _tag: 'RefreshStarted';
1013
+ readonly requests: readonly Requirement$1[];
1014
+ } |
1015
+ /** The active Surfaces' roots changed; everything they do not reach is collected. */
1016
+ {
1017
+ readonly _tag: 'RetentionChanged';
1018
+ readonly roots: RetentionRoots;
1019
+ } |
1020
+ /** A restored snapshot meets the store; runtime state is untouched. */
1021
+ {
1022
+ readonly _tag: 'Hydrated';
1023
+ readonly entities: EntityStore;
1024
+ readonly merge: MergePolicy;
1025
+ } |
1026
+ /** A mutation began; its optimistic operations show until it settles. */
1027
+ {
1028
+ readonly _tag: 'MutationStarted';
1029
+ readonly requestId: string;
1030
+ readonly optimistic?: ReadonlyArray<OptimisticOperation> | undefined;
1031
+ } | {
1032
+ readonly _tag: 'MutationSucceeded';
1033
+ readonly requestId: string;
1034
+ readonly entities: readonly NormalizedPatch[];
1035
+ /** Connection changes the server confirmed; they replace the request's own. */
1036
+ readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
1037
+ } | {
1038
+ readonly _tag: 'MutationFailed';
1039
+ readonly requestId: string;
1040
+ readonly error: RemoteError;
1041
+ } | {
1042
+ readonly _tag: 'LiveReceived';
1043
+ readonly stream: string;
1044
+ readonly event: LiveEvent;
1045
+ readonly policy?: LivePolicy;
1046
+ readonly now: number;
1047
+ } | {
1048
+ readonly _tag: 'GapCleared';
1049
+ readonly stream: string;
1050
+ } | {
1051
+ readonly _tag: 'ConnectionMerged';
1052
+ readonly connection: string;
1053
+ readonly page: Segment;
1054
+ /** The page answers the connection's refresh, so the merge also clears `stale`. */
1055
+ readonly refreshes?: boolean | undefined;
1056
+ } | {
1057
+ readonly _tag: 'ConnectionInvalidated';
1058
+ readonly connection: string;
1059
+ } | {
1060
+ readonly _tag: 'ConnectionRefreshed';
1061
+ readonly connection: string;
1062
+ } |
1063
+ /** A query for the connection failed; it reads as it did before the request. */
1064
+ {
1065
+ readonly _tag: 'QueryFailed';
1066
+ readonly connection: string;
1067
+ readonly error: RemoteError;
1068
+ };
1069
+ export declare const retentionRootsSchema: Schema.Struct<{
1070
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1071
+ readonly connections: Schema.$Array<Schema.Struct<{
1072
+ readonly identity: Schema.String;
1073
+ readonly select: Schema.optional<Schema.Codec<import("foldkit-surface").RelationRequirement, import("foldkit-surface").RelationRequirement, never, never>>;
1074
+ }>>;
1075
+ }>;
1076
+ /**
1077
+ * The Messages' fields by tag, without `_tag`: what `defineMessageUnion` takes,
1078
+ * so an application spreads them into its own union (`Remote.messages`).
1079
+ */
1080
+ export declare const remoteMessageCases: {
1081
+ ReadReceived: {
1082
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1083
+ result: Schema.Struct<{
1084
+ readonly entities: Schema.$Array<Schema.Struct<{
1085
+ readonly entity: Schema.String;
1086
+ readonly id: Schema.String;
1087
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1088
+ }>>;
1089
+ }>;
1090
+ now: Schema.Number;
1091
+ };
1092
+ ReadFailed: {
1093
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1094
+ error: Schema.Struct<{
1095
+ readonly _tag: Schema.String;
1096
+ readonly message: Schema.String;
1097
+ }>;
1098
+ };
1099
+ RefreshStarted: {
1100
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1101
+ };
1102
+ RetentionChanged: {
1103
+ roots: Schema.Struct<{
1104
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1105
+ readonly connections: Schema.$Array<Schema.Struct<{
1106
+ readonly identity: Schema.String;
1107
+ readonly select: Schema.optional<Schema.Codec<import("foldkit-surface").RelationRequirement, import("foldkit-surface").RelationRequirement, never, never>>;
1108
+ }>>;
1109
+ }>;
1110
+ };
1111
+ Hydrated: {
1112
+ entities: Schema.Unknown;
1113
+ merge: Schema.Union<readonly [Schema.Literal<"replace">, Schema.Literal<"preserve-existing">]>;
1114
+ };
1115
+ MutationStarted: {
1116
+ requestId: Schema.String;
1117
+ optimistic: Schema.optional<Schema.$Array<Schema.Unknown>>;
1118
+ };
1119
+ MutationSucceeded: {
1120
+ requestId: Schema.String;
1121
+ entities: Schema.$Array<Schema.Struct<{
1122
+ readonly entity: Schema.String;
1123
+ readonly id: Schema.String;
1124
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1125
+ }>>;
1126
+ connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
1127
+ };
1128
+ MutationFailed: {
1129
+ requestId: Schema.String;
1130
+ error: Schema.Struct<{
1131
+ readonly _tag: Schema.String;
1132
+ readonly message: Schema.String;
1133
+ }>;
1134
+ };
1135
+ LiveReceived: {
1136
+ stream: Schema.String;
1137
+ event: Schema.Unknown;
1138
+ policy: Schema.optional<Schema.Unknown>;
1139
+ now: Schema.Number;
1140
+ };
1141
+ GapCleared: {
1142
+ stream: Schema.String;
1143
+ };
1144
+ ConnectionMerged: {
1145
+ connection: Schema.String;
1146
+ page: Schema.Unknown;
1147
+ refreshes: Schema.optional<Schema.Boolean>;
1148
+ };
1149
+ ConnectionInvalidated: {
1150
+ connection: Schema.String;
1151
+ };
1152
+ ConnectionRefreshed: {
1153
+ connection: Schema.String;
1154
+ };
1155
+ QueryFailed: {
1156
+ connection: Schema.String;
1157
+ error: Schema.Struct<{
1158
+ readonly _tag: Schema.String;
1159
+ readonly message: Schema.String;
1160
+ }>;
1161
+ };
1162
+ };
1163
+ export type RemoteMessageTag = RemoteMessage['_tag'];
1164
+ /**
1165
+ * A Remote Message as an application's union constructs it from
1166
+ * `remoteMessageCases`: the same shape `RemoteMessage` names, with the runtime
1167
+ * slots (`entities`, `event`, `page`) typed `unknown` by their schemas.
1168
+ */
1169
+ export type RemoteMessageInput = { [Tag in RemoteMessageTag]: {
1170
+ readonly _tag: Tag;
1171
+ } & Schema.Struct.Type<(typeof remoteMessageCases)[Tag]>; }[RemoteMessageTag];
1172
+ /**
1173
+ * Whether a Message is one of Remote's, by tag. Narrows an application's union
1174
+ * to its Remote cases, and its complement to the application's own.
1175
+ */
1176
+ export declare const isRemoteMessage: <M extends {
1177
+ readonly _tag: string;
1178
+ }>(message: M) => message is Extract<M, {
1179
+ readonly _tag: RemoteMessageTag;
1180
+ }>;
1181
+ export declare const remoteMessageSchema: Schema.Schema<RemoteMessage>;
1182
+ /**
1183
+ * The pure reducer all four producers share. A live event that arrives ahead of
1184
+ * its cursor is a gap: it is not applied, and the stream is recorded so the host
1185
+ * can resubscribe rather than silently miss facts.
1186
+ */
1187
+ export declare const updateRemote: (model: RemoteModel, message: RemoteMessage) => RemoteModel;
1188
+ /**
1189
+ * Writes a read result into the store, recording each field's applied window so
1190
+ * a later request with a different window refetches. A relation page requested
1191
+ * with a cursor is merged onto the page already stored, so "load more"
1192
+ * accumulates rather than replaces. Every read path should use this rather than
1193
+ * reducing `writeEntity` by hand.
1194
+ */
1195
+ export declare const writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement$1>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1196
+ //#endregion
1197
+ //#region src/coalesce.d.ts
1198
+ type Batch = Schema.Schema.Type<typeof ReadBatch>;
1199
+ type BatchResult = Schema.Schema.Type<typeof ReadBatchResult>;
1200
+ type ReadError = RemoteReadError | RemoteProtocolError;
1201
+ export type BatchRead = (batch: Batch) => Effect.Effect<BatchResult, ReadError>;
1202
+ type QueryRequestValue = Schema.Schema.Type<typeof QueryRequest>;
1203
+ type QueryResultValue = Schema.Schema.Type<typeof QueryResult>;
1204
+ export type QueryRun = (request: QueryRequestValue) => Effect.Effect<QueryResultValue, RemoteQueryError>;
1205
+ export interface CoalesceOptions {
1206
+ /**
1207
+ * How long a batch waits to collect more requirements before it runs.
1208
+ * Requirements issued concurrently coalesce even at the default of no wait.
1209
+ */
1210
+ readonly window?: Duration.Input | undefined;
1211
+ }
1212
+ /** A stable key for a requirement, so an equal requirement in flight is joined. */
1213
+ export declare const requirementKey: (requirement: Requirement$1) => string;
1214
+ /**
1215
+ * Wraps a raw query so that an identical query in flight (same query, input,
1216
+ * and window) is joined rather than run again; distinct queries run
1217
+ * concurrently. A page answers exactly one window, so nothing is batched.
1218
+ */
1219
+ export declare const coalesceQueries: (query: QueryRun, options?: CoalesceOptions) => Effect.Effect<QueryRun>;
1220
+ /**
1221
+ * Wraps a raw batch read so that requirements are batched and deduplicated.
1222
+ * Every waiter receives the whole batch result; `Remote.writeRead` is
1223
+ * idempotent, so writing it more than once is harmless.
1224
+ */
1225
+ export declare const coalesceReads: (read: BatchRead, options?: CoalesceOptions) => Effect.Effect<BatchRead>;
1226
+ //#endregion
1227
+ //#region src/client.d.ts
1228
+ declare const RemoteClient_base: Context.ServiceClass<RemoteClient, "foldkit-remote/RemoteClient", {
1229
+ readonly read: (batch: Schema.Schema.Type<typeof ReadBatch>) => Effect.Effect<Schema.Schema.Type<typeof ReadBatchResult>, RemoteReadError | RemoteProtocolError>;
1230
+ readonly query: (request: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError>;
1231
+ readonly mutate: (request: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError>;
1232
+ readonly live: (request: {
1233
+ readonly requirements: ReadonlyArray<Requirement$1>;
1234
+ readonly after: LiveCursor;
1235
+ }) => Stream.Stream<LiveEvent, RemoteLiveError | RemoteProtocolError>;
1236
+ }>;
1237
+ /**
1238
+ * The transport boundary. `foldkit-remote` never talks to a transport directly;
1239
+ * it depends on this Effect service, which a later phase wires to Effect RPC.
1240
+ */
1241
+ export declare class RemoteClient extends RemoteClient_base {}
1242
+ /**
1243
+ * The methods an Effect RPC client for `RemoteRpc` exposes. `R` is the
1244
+ * environment a handler needs; it defaults to `never`, which is what a real
1245
+ * transport client satisfies. `RemoteServer.handlers` returns this type with its
1246
+ * own `R`, so the two sides cannot drift apart.
1247
+ */
1248
+ export interface RemoteRpcClient<R = never> {
1249
+ readonly FoldkitRemoteRead: (payload: Schema.Schema.Type<typeof ReadBatch>) => Effect.Effect<Schema.Schema.Type<typeof ReadBatchResult>, RemoteReadError | RemoteProtocolError, R>;
1250
+ readonly FoldkitRemoteQuery: (payload: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError, R>;
1251
+ readonly FoldkitRemoteMutate: (payload: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError, R>;
1252
+ readonly FoldkitRemoteLive: (payload: Schema.Schema.Type<typeof LiveRequirement>) => Stream.Stream<Schema.Schema.Type<typeof LiveChange>, RemoteLiveError | RemoteProtocolError, R>;
1253
+ }
1254
+ /** Reconstructs the client's `ConnectionChange` from the wire's flattened edge. */
1255
+ export declare const connectionChangeOf: (change: Schema.Schema.Type<typeof ConnectionChangeSchema>) => ConnectionChange;
1256
+ /** Reconstructs the client's `LiveEvent` from the wire's flattened `LiveChange`. */
1257
+ export declare const liveEventOf: (change: Schema.Schema.Type<typeof LiveChange>) => LiveEvent;
1258
+ export declare const remoteError: (error: {
1259
+ readonly _tag: string;
1260
+ readonly message: string;
1261
+ }) => RemoteError;
1262
+ export declare const coalescedLayer: <E, R>(layer: Layer.Layer<RemoteClient, E, R>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, E, R>;
1263
+ /**
1264
+ * `Remote.mutate` as a standalone effect, so `Remote.mutateInto` can reuse it
1265
+ * without the object literal referencing itself.
1266
+ */
1267
+ export declare const mutateRemote: <Name extends string, Input, Output>(mutation: MutationDescriptor<Name, Input, Output>, input: Input, requestId: string) => Effect.Effect<{
1268
+ output: Output;
1269
+ entities: readonly {
1270
+ readonly entity: string;
1271
+ readonly id: string;
1272
+ readonly values: {
1273
+ readonly [x: string]: unknown;
1274
+ };
1275
+ }[];
1276
+ connections: ConnectionChange[];
1277
+ }, RemoteMutationError, RemoteClient>;
1278
+ //#endregion
1279
+ //#region src/relation.d.ts
1280
+ export interface RefParts {
1281
+ readonly entity: string;
1282
+ readonly id: string;
1283
+ }
1284
+ /** A page of refs as the wire and the store hold it. */
1285
+ export interface RefPageValue {
1286
+ readonly refs: ReadonlyArray<string>;
1287
+ readonly hasNext: boolean;
1288
+ readonly hasPrevious: boolean;
1289
+ }
1290
+ /** Marks the codec `Entity.ref`/`Entity.refPage` produce, so a Selection can tell the field's shape. */
1291
+ export declare const RelationAnnotation = "foldkitRemoteRelation";
1292
+ /** The target entity's name on the same codec, so a nested selection of another entity is refused. */
1293
+ export declare const RelationEntityAnnotation = "foldkitRemoteRelationEntity";
1294
+ export type RelationKind = 'one' | 'many' | 'page';
1295
+ export interface RelationShape {
1296
+ readonly kind: RelationKind;
1297
+ readonly nullable: boolean;
1298
+ readonly entity: string;
1299
+ }
1300
+ /** Splits a ref key (`"Entity:id"`, the store key too) back into its parts. */
1301
+ export declare const refParts: (encoded: string) => RefParts;
1302
+ /**
1303
+ * The refs a relation value carries, in order. Anything that is not a ref key,
1304
+ * an array of them, or a page of them contributes nothing.
1305
+ */
1306
+ export declare const refsIn: (value: unknown) => ReadonlyArray<RefParts>;
1307
+ /** The refs in a relation value that name the relation's target entity, and no other. */
1308
+ export declare const targetsOf: (value: unknown, relation: RelationRequirement$1) => ReadonlyArray<RefParts>;
1309
+ export declare const isRefPage: (value: unknown) => value is RefPageValue;
1310
+ /**
1311
+ * The relation shape an entity field schema declares: a ref (`one`), a nullable
1312
+ * ref, an array of refs (`many`), or a page of refs (`page`). `undefined` for a
1313
+ * scalar field, which cannot take a nested selection.
1314
+ */
1315
+ export declare const relationShape: (schema: Schema.Top) => RelationShape | undefined;
1316
+ //#endregion
1317
+ //#region src/selection.d.ts
1318
+ /** One page of a paginated relation with each target assembled through a nested selection. */
1319
+ export interface Page<Item> {
1320
+ readonly items: ReadonlyArray<Item>;
1321
+ readonly hasNext: boolean;
1322
+ readonly hasPrevious: boolean;
1323
+ }
1324
+ /**
1325
+ * The fields a projection reads of one entity, plus the slice it reads of each
1326
+ * relation's target. `Shape` tells a parent selection whether this one is a
1327
+ * paginated relation (`connection`) or a plain entity slice (`entity`).
1328
+ */
1329
+ export interface Selection<Value, Name extends string = string, Shape extends 'entity' | 'connection' = 'entity' | 'connection'> {
1330
+ readonly entity: Name;
1331
+ readonly fields: readonly string[];
1332
+ /** A pure codec: entity fields carry no decoding or encoding services. */
1333
+ readonly schema: Schema.Codec<Value, unknown, never, never>;
1334
+ /** Pagination windows for nested relation fields, keyed by field name. */
1335
+ readonly connections?: Readonly<Record<string, QueryWindow>> | undefined;
1336
+ /** The slice required of each nested relation's target, keyed by field name. */
1337
+ readonly relations?: Readonly<Record<string, RelationRequirement$1>> | undefined;
1338
+ /** Present when this selection is itself a paginated relation. */
1339
+ readonly window?: QueryWindow | undefined;
1340
+ /** Phantom: see `Shape`. */
1341
+ readonly shape?: Shape | undefined;
1342
+ }
1343
+ /** Flattens a mapped type so hovers show the picked fields, not the machinery. */
1344
+ type Simplify<T> = T extends (infer O) ? { readonly [K in keyof O]: O[K]; } : never;
1345
+ /** The value a Selection reads: `Selection.Value<typeof ProjectCard>`. */
1346
+ export type SelectionValueOf<S> = S extends Selection<infer V, any, any> ? V : never;
1347
+ /** The nested selections a relation field admits: of its target entity, in the shapes its value takes. */
1348
+ 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;
1349
+ /** What a selection of an entity with fields `F` may pick: `true` per scalar, a nested selection per relation. */
1350
+ export type SelectionOf<F extends Schema.Struct.Fields> = { readonly [K in keyof F]?: true | NestedFor<Schema.Schema.Type<F[K]>>; };
1351
+ /** `T | null` when the field admits `null` or `undefined` (both assemble to `null`). */
1352
+ type Nullable<Field, T> = [Extract<Field, null | undefined>] extends [never] ? T : T | null;
1353
+ /** A nested selection's value takes the shape of the field it selects through. */
1354
+ 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;
1355
+ /** The value a selection `Sel` of fields `F` reads. */
1356
+ export 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]>; }>;
1357
+ export declare const pageSchema: (item: AnySchema) => AnySchema;
1358
+ /** The requirement a nested selection contributes for its relation's target. */
1359
+ export declare const relationOf: (selection: Selection<unknown>) => RelationRequirement$1;
1360
+ export declare const Selection: {
1361
+ /**
1362
+ * The fields to read of `entity`. A nested `Selection` on a relation field
1363
+ * reads through the ref (or refs, or page of refs) the field holds into the
1364
+ * target's fields; a scalar field cannot take one.
1365
+ */
1366
+ 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">;
1367
+ /**
1368
+ * A paginated relation: one page of refs to `entity` with a window, or, with
1369
+ * a nested selection, one page of targets assembled through it.
1370
+ */
1371
+ connection: {
1372
+ <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>, window: QueryWindow): Selection<RefPage<Name, F>, Name, "connection">;
1373
+ <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">;
1374
+ };
1375
+ };
1376
+ interface Assembled {
1377
+ readonly values: unknown;
1378
+ readonly refreshing: boolean;
1379
+ }
1380
+ /**
1381
+ * Reads an entity's selected fields out of the store, following each nested
1382
+ * relation into its targets. `undefined` means some field, at any depth, is
1383
+ * not present yet. A tombstoned target reads as `null` (or is dropped from a
1384
+ * list), so the Selection's codec decides whether that is a failure.
1385
+ */
1386
+ export declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement$1) => Assembled | undefined;
1387
+ //#endregion
1388
+ //#region src/entity.d.ts
1389
+ export type AnySchema = Schema.Schema<unknown>;
1390
+ declare const entityRefFields: unique symbol;
1391
+ /**
1392
+ * A normalized reference to an entity. `F` is a phantom carrying the entity's
1393
+ * fields so `Entity.patch` can type its patch; it is absent at runtime.
1394
+ */
1395
+ export interface EntityRef<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
1396
+ readonly entity: Name;
1397
+ readonly id: string;
1398
+ readonly [entityRefFields]?: F;
1399
+ }
1400
+ export interface EntityDescriptor<Name extends string, F extends Schema.Struct.Fields> {
1401
+ readonly name: Name;
1402
+ readonly schema: Schema.Struct<F>;
1403
+ readonly fields: F;
1404
+ ref(id: Schema.Schema.Type<F['id']>): EntityRef<Name, F>;
1405
+ /** The fields a Surface reads of this entity; `Selection.make(entity, …)` with the entity as receiver. */
1406
+ select<const Sel extends SelectionOf<F>>(selection: Sel): Selection<SelectionValue<F, Sel>, Name, 'entity'>;
1407
+ /** A patch of this entity's wire-shaped values; `Entity.patch(entity.ref(id), values)`. */
1408
+ patch(id: Schema.Schema.Type<F['id']>, values: Partial<Schema.Struct.Encoded<F>>): EntityPatch<Name, F>;
1409
+ }
1410
+ /**
1411
+ * A patch in wire shape: the values the store holds, so a relation is its ref
1412
+ * key (`Entity.refKey`), not an `EntityRef`.
1413
+ */
1414
+ export interface EntityPatch<Name extends string, F extends Schema.Struct.Fields> {
1415
+ readonly entity: Name;
1416
+ readonly id: string;
1417
+ readonly values: Partial<Schema.Struct.Encoded<F>>;
1418
+ }
1419
+ /**
1420
+ * One authoritative page of a paginated relation: refs (never inline entities)
1421
+ * plus whether more exist. The adapter does not hold segmentation state; the
1422
+ * client merges pages.
1423
+ */
1424
+ export interface RefPage<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
1425
+ readonly refs: ReadonlyArray<EntityRef<Name, F>>;
1426
+ readonly hasNext: boolean;
1427
+ readonly hasPrevious: boolean;
1428
+ }
1429
+ declare const Entity$1: {
1430
+ make: <const Name extends string, const F extends Schema.Struct.Fields & {
1431
+ readonly id: Schema.Schema<unknown>;
1432
+ }>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
1433
+ /** A relation to a known entity, decoded as a reference. */
1434
+ ref: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<EntityRef<Name, F>, string>;
1435
+ /** A relation by name, for recursive or forward references. */
1436
+ refTo: <Name extends string>(name: Name) => Schema.Codec<EntityRef<Name>, string>;
1437
+ /**
1438
+ * The wire key a relation field carries (`"Entity:id"`). Adapters that read a
1439
+ * foreign key emit this so the ref codec can decode it on the client.
1440
+ */
1441
+ refKey: (ref: {
1442
+ readonly entity: string;
1443
+ readonly id: string;
1444
+ }) => string;
1445
+ /** Splits a ref key back into its entity and id. */
1446
+ refParts: (encoded: string) => RefParts;
1447
+ /** A relation value of one authoritative page of refs. */
1448
+ refPage: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<RefPage<Name, F>, {
1449
+ readonly refs: ReadonlyArray<string>;
1450
+ readonly hasNext: boolean;
1451
+ readonly hasPrevious: boolean;
1452
+ }>;
1453
+ /**
1454
+ * A normalized patch for an entity, typed against its fields' wire shape:
1455
+ * write a relation as its ref key (`Entity.refKey`), as the server does.
1456
+ */
1457
+ patch: <Name extends string, F extends Schema.Struct.Fields>(ref: EntityRef<Name, F>, patch: Partial<Schema.Struct.Encoded<F>>) => EntityPatch<Name, F>;
1458
+ };
1459
+ //#endregion
1460
+ //#region src/inspect.d.ts
1461
+ /** A serializable summary of a RemoteModel for DevTools and diagnostics. */
1462
+ export interface RemoteInspection {
1463
+ readonly entities: ReadonlyArray<{
1464
+ readonly key: string;
1465
+ readonly present: ReadonlyArray<string>;
1466
+ readonly stale: ReadonlyArray<string>;
1467
+ readonly tombstone: boolean;
1468
+ readonly updatedAt: number;
1469
+ readonly windows: Readonly<Record<string, string>>;
1470
+ }>;
1471
+ readonly connections: ReadonlyArray<string>;
1472
+ readonly live: ReadonlyArray<string>;
1473
+ readonly gaps: ReadonlyArray<string>;
1474
+ readonly mutations: {
1475
+ readonly pending: ReadonlyArray<string>;
1476
+ readonly failed: ReadonlyArray<string>;
1477
+ readonly applied: number;
1478
+ };
1479
+ }
1480
+ /** A pure, serializable view of the whole cache. */
1481
+ export declare const inspectRemote: (model: RemoteModel) => RemoteInspection;
1482
+ /** A pure, serializable view of one entity, or `undefined` if unknown. */
1483
+ export declare const inspectEntity: (model: RemoteModel, key: string) => RemoteInspection["entities"][number] | undefined;
1484
+ //#endregion
1485
+ //#region src/plan.d.ts
1486
+ type Window = NonNullable<Requirement$1['windows']>[string];
1487
+ /** A stable key for a window, so two equal windows compare equal. */
1488
+ export declare const windowKey: (window: Window) => string;
1489
+ export interface PlanFreshness {
1490
+ readonly now: number;
1491
+ /** A present entry older than this many milliseconds is refreshed whole. */
1492
+ readonly freshness: number;
1493
+ }
1494
+ export interface PlanOptions {
1495
+ readonly freshness?: PlanFreshness | undefined;
1496
+ /** Plan every requested field, present or not, tombstoned or not. */
1497
+ readonly force?: boolean | undefined;
1498
+ }
1499
+ export declare const plan: (store: EntityStore, requirements: readonly Requirement$1[], options?: PlanOptions) => ReadonlyArray<Requirement$1>;
1500
+ //#endregion
1501
+ //#region src/policy.d.ts
1502
+ export type RemotePolicy =
1503
+ /** Fetch only fields the store lacks (missing, stale, or re-windowed). */
1504
+ {
1505
+ readonly _tag: 'CacheFirst';
1506
+ } |
1507
+ /**
1508
+ * Keep present values visible, read them as `Refreshing`, and refetch an
1509
+ * entry older than `maxAge` milliseconds.
1510
+ */
1511
+ {
1512
+ readonly _tag: 'StaleWhileRevalidate';
1513
+ readonly maxAge: number;
1514
+ } |
1515
+ /** Fetch every selected field regardless of coverage; cached values stay visible meanwhile. */
1516
+ {
1517
+ readonly _tag: 'NetworkOnly';
1518
+ };
1519
+ export declare const RemotePolicy: {
1520
+ /** Fetch only what the store lacks. */
1521
+ cacheFirst: {
1522
+ readonly _tag: "CacheFirst";
1523
+ };
1524
+ /** Keep present values visible, read as `Refreshing`, and refetch an entry older than `maxAge` ms. */
1525
+ staleWhileRevalidate: (options: {
1526
+ readonly maxAge: number;
1527
+ }) => RemotePolicy;
1528
+ /** Fetch every selected field regardless of coverage; cached values stay visible meanwhile. */
1529
+ networkOnly: {
1530
+ readonly _tag: "NetworkOnly";
1531
+ };
1532
+ /** The planner options a policy compiles to at `now`. */
1533
+ toPlan: (policy: RemotePolicy, now: number) => PlanOptions;
1534
+ /**
1535
+ * Whether a read under this policy may refetch fields the store already
1536
+ * holds, so an observer marks them stale (read as `Refreshing`) while the
1537
+ * request is pending.
1538
+ */
1539
+ refreshes: (policy: RemotePolicy) => boolean;
1540
+ };
1541
+ //#endregion
1542
+ //#region src/index.d.ts
1543
+ type EntityName<D> = D extends EntityDescriptor<infer Name, any> ? Name : never;
1544
+ type QueryName<D> = D extends QueryDescriptor<infer Name, any, any> ? Name : never;
1545
+ type MutationName<D> = D extends MutationDescriptor<infer Name, any, any> ? Name : never;
1546
+ /**
1547
+ * Nothing when `Name` is one of the domain's registered `Names`; otherwise a
1548
+ * branded failure naming the descriptor, so `Data.get(Team.select(…))` for an
1549
+ * unregistered `Team` errors at the selection in one line.
1550
+ */
1551
+ export type Registered<Name extends string, Names extends string, Kind extends string> = [Name] extends [Names] ? unknown : Invalid<`${Kind} "${Name}" is not registered with this Remote domain`>;
1552
+ /** Nothing when a selection is of the query's entity; otherwise a branded failure naming both. */
1553
+ export type SelectsEntity<Entity extends string, Of extends string> = [Entity] extends [Of] ? unknown : Invalid<`the selection is of "${Entity}", but the query lists "${Of}"`>;
1554
+ export interface RemoteDescriptor<Entities extends readonly EntityDescriptor<any, any>[] = readonly EntityDescriptor<any, any>[], Queries extends readonly QueryDescriptor<any, any, any>[] = readonly QueryDescriptor<any, any, any>[], Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly MutationDescriptor<any, any, any>[]> {
1555
+ readonly entities: Entities;
1556
+ readonly queries: Queries;
1557
+ readonly mutations: Mutations;
1558
+ readonly Model: Schema.Schema<RemoteModel>;
1559
+ readonly initial: RemoteModel;
1560
+ readonly Message: Schema.Schema<RemoteMessage>;
1561
+ readonly update: (model: RemoteModel, message: RemoteMessage) => RemoteModel;
1562
+ readonly rpc: typeof RemoteRpc;
1563
+ /** Name-keyed lookups built from the declared entities, queries, and mutations. */
1564
+ readonly registry: {
1565
+ readonly entities: ReadonlyMap<string, EntityDescriptor<any, any>>;
1566
+ readonly queries: ReadonlyMap<string, QueryDescriptor<any, any, any>>;
1567
+ readonly mutations: ReadonlyMap<string, MutationDescriptor<any, any, any>>;
1568
+ };
1569
+ }
1570
+ declare const boundRemoteNames: unique symbol;
1571
+ export interface BoundRemote<AppModel, Store extends RemoteModel, Names extends string = string> {
1572
+ readonly definition: RemoteDescriptor;
1573
+ readonly store: ModelRef<AppModel, Store>;
1574
+ /** For `Module`: owns the store's Model path. */
1575
+ readonly contract: Contract;
1576
+ /** Phantom: the entity names this Remote definition registers. */
1577
+ readonly [boundRemoteNames]?: Names;
1578
+ }
1579
+ type MutationInput<M> = M extends MutationDescriptor<any, infer Input, any> ? Input : never;
1580
+ export interface DomainMutateOptions {
1581
+ /** Overrides the generated id, for a retry, a durable bridge, or a test. */
1582
+ readonly requestId?: string | undefined;
1583
+ /**
1584
+ * What the request changes before the server answers, released when it
1585
+ * settles. A function receives the generated ids, so a created entity can
1586
+ * carry `tempId` until the result names the real one.
1587
+ */
1588
+ readonly optimistic?: ReadonlyArray<OptimisticOperation> | ((ids: {
1589
+ readonly requestId: string;
1590
+ readonly tempId: string;
1591
+ }) => ReadonlyArray<OptimisticOperation>) | undefined;
1592
+ }
1593
+ /** A Foldkit Subscription entry of the Remote domain, emitting its Messages through `RemoteClient`. */
1594
+ export type RemoteEntry<AppModel, Dependencies> = EntryWithoutKeepAlive<AppModel, RemoteMessage, Dependencies, RemoteClient>;
1595
+ export interface SubscriptionsOptions extends ObserveOptions, LiveOptions, RetainOptions {}
1596
+ /** What `RemoteDomain.mutate` hands `update`: the Model with the request started, and the Command that settles it. */
1597
+ export interface MutationStarted<AppModel> {
1598
+ readonly model: AppModel;
1599
+ readonly requestId: string;
1600
+ readonly tempId: string;
1601
+ /** Yields `MutationSucceeded` or `MutationFailed`; never fails. */
1602
+ readonly command: Command<RemoteMessage, never, RemoteClient>;
1603
+ }
1604
+ /**
1605
+ * A Remote domain bound to its place in the application Model: the descriptor
1606
+ * (`Remote.define`), the binding (`Remote.at`), and the application-facing
1607
+ * operations over them. Every method compiles to the `Remote.*` function of the
1608
+ * same name, which stays exported for tooling, SSR, and tests.
1609
+ */
1610
+ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities extends readonly EntityDescriptor<any, any>[], Queries extends readonly QueryDescriptor<any, any, any>[], Mutations extends readonly MutationDescriptor<any, any, any>[]> extends BoundRemote<AppModel, Store, EntityName<Entities[number]>>, RemoteDescriptor<Entities, Queries, Mutations> {
1611
+ /** `Remote.select`: a Projection reading one entity through a selection of a registered entity. */
1612
+ get<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1613
+ /**
1614
+ * `get`, and the projection also subscribes to the entity's changes: its
1615
+ * requirements are marked `live`, so `subscriptions` derives a live entry for
1616
+ * the Surfaces that read it.
1617
+ */
1618
+ live<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1619
+ /**
1620
+ * A query connection read as a `Page` of items selected of the query's
1621
+ * entity: `Initial` until the page and every item's selected fields are
1622
+ * present, `Refreshing` while any of them is being refetched. The window is
1623
+ * the page first asked for; the pages `next`, `previous` and `fetch` merge
1624
+ * onto the connection read through the same projection.
1625
+ */
1626
+ query<Q extends QueryDescriptor<any, any, any>, Value, Entity extends string>(query: Q & Registered<Q['name'], QueryName<Queries[number]>, 'Query'>, input: QueryInput<Q>, options: QueryOptions<Value, Entity, QueryEntity<Q>>): QueryProjection<AppModel, Value, Q['name'], QueryInput<Q>>;
1627
+ /** The `QueryRef` for the page after the loaded end (same page size), or `undefined` when there is none or its cursor is unknown. */
1628
+ next<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
1629
+ /** The `QueryRef` for the page before the loaded start, or `undefined`. */
1630
+ previous<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
1631
+ /** A Command that runs the query and yields the `ConnectionMerged` (or `QueryFailed`) that reduces it: "load more". */
1632
+ fetch(ref: QueryRef<string, unknown>): Command<RemoteMessage, never, RemoteClient>;
1633
+ /**
1634
+ * The Foldkit Subscription entries for the active Surfaces, keyed for
1635
+ * `Subscription.make`: a read entry per Surface (`Remote.observe`), a live
1636
+ * entry per Surface that reads through `live` (`Remote.live`), and one
1637
+ * retain entry with every active Surface as a root (`Remote.retain`). A
1638
+ * Surface's params are a function of the Model (`Surface.at`), so what is
1639
+ * fetched, subscribed, and retained follows the Model.
1640
+ */
1641
+ subscriptions(active: Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>, options?: SubscriptionsOptions): Readonly<Record<string, RemoteEntry<AppModel, any>>>;
1642
+ /** `Remote.plan`: the requirements the store does not satisfy. */
1643
+ plan<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions): ReadonlyArray<Requirement$1>;
1644
+ /** `Remote.storeOf`: the visible store, base under the pending optimistic layers. */
1645
+ storeOf(model: AppModel): EntityStore;
1646
+ /**
1647
+ * The plan run through `RemoteClient` and reduced into the Model: the
1648
+ * projection's pending queries first, then the fields it lacks (the pages'
1649
+ * items included). For SSR, route or hover prefetch, and tests.
1650
+ */
1651
+ prefetch<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: ObserveOptions): Effect.Effect<AppModel, RemoteReadError | RemoteProtocolError | RemoteQueryError, RemoteClient>;
1652
+ /**
1653
+ * Starts a registered mutation from `update`: applies `MutationStarted` (with
1654
+ * the optimistic operations) to the Model and returns the Command that runs
1655
+ * it and yields the settling Message. The request id comes from the model's
1656
+ * mutation sequence unless `options.requestId` is given.
1657
+ */
1658
+ mutate<M extends MutationDescriptor<any, any, any>>(model: AppModel, mutation: M & Registered<M['name'], MutationName<Mutations[number]>, 'Mutation'>, input: MutationInput<M>, options?: DomainMutateOptions): MutationStarted<AppModel>;
1659
+ /** `Remote.update` on the bound slice: reduces one of Remote's Messages, as `RemoteMessage` or as the application's union constructs it. */
1660
+ reduce(model: AppModel, message: RemoteMessage | RemoteMessageInput): AppModel;
1661
+ /** `Remote.inspect` of the bound slice. */
1662
+ inspect(model: AppModel): RemoteInspection;
1663
+ }
1664
+ /** A projection's connection requirement with the `QueryRef` that runs it. */
1665
+ export interface QueryRequirement extends ConnectionRequirement {
1666
+ readonly ref: QueryRef<string, unknown>;
1667
+ }
1668
+ /** A page forward (`first`, `after`) or back (`last`, `before`); mixing the two is a type error. */
1669
+ export type QueryWindowOptions = {
1670
+ readonly first?: number | undefined;
1671
+ readonly after?: string | undefined;
1672
+ readonly last?: undefined;
1673
+ readonly before?: undefined;
1674
+ } | {
1675
+ readonly last: number;
1676
+ readonly before?: string | undefined;
1677
+ readonly first?: undefined;
1678
+ readonly after?: undefined;
1679
+ };
1680
+ export type QueryOptions<Value, Entity extends string, Of extends string = Entity> = {
1681
+ /** What to read of each item: a selection of the query's entity (`Of`). */
1682
+ readonly select: Selection<Value, Entity, 'entity'> & SelectsEntity<Entity, Of>;
1683
+ } & QueryWindowOptions;
1684
+ /** A query connection read as a `Page` of selected items; `ref` is the connection with its first window. */
1685
+ export interface QueryProjection<AppModel, Value, Name extends string, Input> extends Projection<AppModel, RemoteData<Page<Value>>> {
1686
+ readonly ref: QueryRef<Name, Input>;
1687
+ }
1688
+ /** The input of a query descriptor. */
1689
+ export type QueryInput<Q> = Q extends QueryDescriptor<any, infer Input, any> ? Input : never;
1690
+ /** The entity a query's connection is over. */
1691
+ export type QueryEntity<Q> = Q extends QueryDescriptor<any, any, ConnectionSpec<infer Entity>> ? Entity : string;
1692
+ export interface MutateOptions {
1693
+ /** What the request changes before the server answers; released when it settles. */
1694
+ readonly optimistic?: ReadonlyArray<OptimisticOperation> | undefined;
1695
+ }
1696
+ export interface RetainOptions {
1697
+ /** The query connections the application shows, by `QueryRef` or identity. */
1698
+ readonly connections?: ReadonlyArray<ConnectionIdentity> | undefined;
1699
+ /** How long the roots must be stable before collecting; default none. */
1700
+ readonly grace?: Duration.Input | undefined;
1701
+ }
1702
+ /** How `Remote.observe` and `Remote.prefetch` treat fields the store already holds. */
1703
+ export interface ObserveOptions {
1704
+ /** Default `RemotePolicy.cacheFirst`. */
1705
+ readonly policy?: RemotePolicy | undefined;
1706
+ /** The clock a refreshing policy reads; default `Date.now`. */
1707
+ readonly now?: (() => number) | undefined;
1708
+ }
1709
+ export interface LiveOptions {
1710
+ /** The clock `LiveReceived` stamps events with; default `Date.now`. */
1711
+ readonly now?: (() => number) | undefined;
1712
+ }
1713
+ /** A query the read entry runs, as its dependencies carry it: plain data Foldkit compares. */
1714
+ declare const PlannedQuery: Schema.Struct<{
1715
+ readonly identity: Schema.String;
1716
+ readonly window: Schema.Struct<{
1717
+ readonly first: Schema.optional<Schema.Number>;
1718
+ readonly last: Schema.optional<Schema.Number>;
1719
+ readonly after: Schema.optional<Schema.String>;
1720
+ readonly before: Schema.optional<Schema.String>;
1721
+ }>;
1722
+ readonly select: Schema.Codec<RelationRequirement, RelationRequirement, never, never>;
1723
+ }>;
1724
+ /** The dependencies of the read entry: the entity fields to read and the queries to run. */
1725
+ export interface ReadDependencies {
1726
+ readonly requirements: ReadonlyArray<Requirement$1>;
1727
+ readonly queries: ReadonlyArray<Schema.Schema.Type<typeof PlannedQuery>>;
1728
+ }
1729
+ export declare const Remote: {
1730
+ /** The submodel's schema, the same for every domain; embed it in the application Model. */
1731
+ Model: Schema.Schema<RemoteModel>;
1732
+ /** The submodel's initial value. */
1733
+ initial: RemoteModel;
1734
+ /**
1735
+ * Remote's Message cases for `defineMessageUnion`: spread them into the
1736
+ * application's union, and reduce the ones `Remote.reduces` recognizes with
1737
+ * `RemoteDomain.reduce`.
1738
+ */
1739
+ messages: {
1740
+ ReadReceived: {
1741
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1742
+ result: Schema.Struct<{
1743
+ readonly entities: Schema.$Array<Schema.Struct<{
1744
+ readonly entity: Schema.String;
1745
+ readonly id: Schema.String;
1746
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1747
+ }>>;
1748
+ }>;
1749
+ now: Schema.Number;
1750
+ };
1751
+ ReadFailed: {
1752
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1753
+ error: Schema.Struct<{
1754
+ readonly _tag: Schema.String;
1755
+ readonly message: Schema.String;
1756
+ }>;
1757
+ };
1758
+ RefreshStarted: {
1759
+ requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1760
+ };
1761
+ RetentionChanged: {
1762
+ roots: Schema.Struct<{
1763
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1764
+ readonly connections: Schema.$Array<Schema.Struct<{
1765
+ readonly identity: Schema.String;
1766
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1767
+ }>>;
1768
+ }>;
1769
+ };
1770
+ Hydrated: {
1771
+ entities: Schema.Unknown;
1772
+ merge: Schema.Union<readonly [Schema.Literal<"replace">, Schema.Literal<"preserve-existing">]>;
1773
+ };
1774
+ MutationStarted: {
1775
+ requestId: Schema.String;
1776
+ optimistic: Schema.optional<Schema.$Array<Schema.Unknown>>;
1777
+ };
1778
+ MutationSucceeded: {
1779
+ requestId: Schema.String;
1780
+ entities: Schema.$Array<Schema.Struct<{
1781
+ readonly entity: Schema.String;
1782
+ readonly id: Schema.String;
1783
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1784
+ }>>;
1785
+ connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
1786
+ };
1787
+ MutationFailed: {
1788
+ requestId: Schema.String;
1789
+ error: Schema.Struct<{
1790
+ readonly _tag: Schema.String;
1791
+ readonly message: Schema.String;
1792
+ }>;
1793
+ };
1794
+ LiveReceived: {
1795
+ stream: Schema.String;
1796
+ event: Schema.Unknown;
1797
+ policy: Schema.optional<Schema.Unknown>;
1798
+ now: Schema.Number;
1799
+ };
1800
+ GapCleared: {
1801
+ stream: Schema.String;
1802
+ };
1803
+ ConnectionMerged: {
1804
+ connection: Schema.String;
1805
+ page: Schema.Unknown;
1806
+ refreshes: Schema.optional<Schema.Boolean>;
1807
+ };
1808
+ ConnectionInvalidated: {
1809
+ connection: Schema.String;
1810
+ };
1811
+ ConnectionRefreshed: {
1812
+ connection: Schema.String;
1813
+ };
1814
+ QueryFailed: {
1815
+ connection: Schema.String;
1816
+ error: Schema.Struct<{
1817
+ readonly _tag: Schema.String;
1818
+ readonly message: Schema.String;
1819
+ }>;
1820
+ };
1821
+ };
1822
+ /** Whether a Message is one of Remote's, by tag. */
1823
+ reduces: <M extends {
1824
+ readonly _tag: string;
1825
+ }>(message: M) => message is Extract<M, {
1826
+ readonly _tag: RemoteMessageTag;
1827
+ }>;
1828
+ /**
1829
+ * Declares a Remote domain and binds it to its place in the application Model
1830
+ * in one step; the result carries the application-facing operations. The
1831
+ * descriptor alone is `Remote.define`, the binding alone `Remote.at`.
1832
+ */
1833
+ make: <AppModel, Store extends RemoteModel, const Entities extends readonly EntityDescriptor<any, any>[], const Queries extends readonly QueryDescriptor<any, any, any>[] = readonly [], const Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly []>(config: {
1834
+ readonly model: ModelRef<AppModel, Store>;
1835
+ readonly entities: Entities;
1836
+ readonly queries?: Queries;
1837
+ readonly mutations?: Mutations;
1838
+ }) => RemoteDomain<AppModel, Store, Entities, Queries, Mutations>;
1839
+ /**
1840
+ * Declares a Remote domain without binding it: its entities, queries, and
1841
+ * mutations, plus the submodel. For a domain reused across applications or
1842
+ * bound in a test; `Remote.make` is the one-step form.
1843
+ */
1844
+ define: <const Entities extends readonly EntityDescriptor<any, any>[], 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: {
1845
+ readonly entities: Entities;
1846
+ readonly queries?: Queries;
1847
+ readonly mutations?: Mutations;
1848
+ }) => RemoteDescriptor<Entities, Queries, Mutations>;
1849
+ /**
1850
+ * Binds a Remote domain to its store's location in the application Model. The
1851
+ * registered entity names are carried on the returned value, so `Remote.select`
1852
+ * rejects a selection for an entity this domain never declared.
1853
+ */
1854
+ at: <AppModel, Store extends RemoteModel, Entities extends readonly EntityDescriptor<any, any>[], 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]>>;
1855
+ /**
1856
+ * A Projection node that reads a `RemoteData` value out of the store. The id
1857
+ * is supplied by the caller, usually from a Surface's params. The assembled
1858
+ * value is decoded against the Selection, so malformed server data surfaces
1859
+ * as `Failed` instead of being asserted into `Value`. A present value with a
1860
+ * stale field reads as `Refreshing`: an observer is refetching it.
1861
+ */
1862
+ select: <AppModel, Store extends RemoteModel, Names extends string, Value, Name extends string>(bound: BoundRemote<AppModel, Store, Names>, selection: Selection<Value, Name, "entity"> & Registered<Name, Names, "Entity">) => (id: string) => Projection<AppModel, RemoteData<Value>>;
1863
+ /**
1864
+ * The pure plan for a projection against a Model: the requirements its
1865
+ * remote store does not satisfy, under `options` (freshness, force). A
1866
+ * Surface's projection is `surface.projection(params)`.
1867
+ */
1868
+ plan: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store>, model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions) => ReadonlyArray<Requirement$1>;
1869
+ /**
1870
+ * The queries a projection needs run before its connections read: those the
1871
+ * Model does not hold, or holds stale (every one under `force`).
1872
+ */
1873
+ planQueries: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store>, model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions) => ReadonlyArray<QueryRef<string, unknown>>;
1874
+ /**
1875
+ * The store reads see: the base store under the pending optimistic layers.
1876
+ * One store is shared by every read and plan of a Model whose remote state
1877
+ * has not changed.
1878
+ */
1879
+ storeOf: <AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store>, model: AppModel) => EntityStore;
1880
+ /**
1881
+ * Executes the plan against the `RemoteClient` and returns a new store. Used
1882
+ * for SSR route prefetch, hover prefetch, and tests. Never called during render.
1883
+ * `policy` decides what a present field means (default cache-first); `now`
1884
+ * is the clock it reads, so the planner itself stays pure and time-injected.
1885
+ */
1886
+ 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>>, RemoteReadError | RemoteProtocolError, RemoteClient>;
1887
+ /**
1888
+ * Writes a read result into the store, recording each field's applied window.
1889
+ * `requests` are the planned requirements the result answers.
1890
+ */
1891
+ writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement$1>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1892
+ /**
1893
+ * Adapts an Effect RPC client for `RemoteRpc` to `RemoteClient`, so an
1894
+ * application provides the transport's RPC layer instead of writing the
1895
+ * `LiveChange`-to-`LiveEvent` mapping by hand.
1896
+ */
1897
+ clientLayer: <R = never>(client: RemoteRpcClient<R>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, never, R>;
1898
+ /**
1899
+ * Wraps a `RemoteClient` layer so its reads coalesce: requirements issued
1900
+ * together become one batch, and a requirement already in flight is joined.
1901
+ * `Remote.clientLayer` applies this; use it on a hand-written client.
1902
+ */
1903
+ coalesced: <E, R>(layer: Layer.Layer<RemoteClient, E, R>, options?: CoalesceOptions) => Layer.Layer<RemoteClient, E, R>;
1904
+ /**
1905
+ * A Foldkit Subscription entry that keeps the cache to what the active
1906
+ * Surfaces reach. `projections` are the ones the application observes (the
1907
+ * same it passes to `Remote.observe`), `connections` the query connections
1908
+ * it shows; anything else is collected once the roots have been stable for
1909
+ * `grace`, so a route transition that comes straight back does not thrash.
1910
+ */
1911
+ retain: <AppModel, Message = RemoteMessage>(projections: ReadonlyArray<Projection<AppModel, unknown>>, toMessage?: (message: RemoteMessage) => Message, options?: RetainOptions) => EntryWithoutKeepAlive<AppModel, Message, RetentionRoots, never>;
1912
+ /**
1913
+ * Runs a `Query` through `RemoteClient`, encoding its input from the ref.
1914
+ * Pair the result with `Remote.queryMessage` to merge the page into the Model.
1915
+ */
1916
+ query: <Name extends string, Input>(ref: QueryRef<Name, Input>) => Effect.Effect<{
1917
+ readonly edges: readonly {
1918
+ readonly entity: string;
1919
+ readonly id: string;
1920
+ readonly key: string;
1921
+ }[];
1922
+ readonly start: {
1923
+ readonly _tag: "Terminal";
1924
+ } | {
1925
+ readonly _tag: "Cursor";
1926
+ readonly cursor: string;
1927
+ } | {
1928
+ readonly _tag: "Unknown";
1929
+ };
1930
+ readonly end: {
1931
+ readonly _tag: "Terminal";
1932
+ } | {
1933
+ readonly _tag: "Cursor";
1934
+ readonly cursor: string;
1935
+ } | {
1936
+ readonly _tag: "Unknown";
1937
+ };
1938
+ }, RemoteQueryError, RemoteClient>;
1939
+ /** The `RemoteMessage` that merges a query page into its connection. */
1940
+ queryMessage: <Name extends string, Input>(ref: QueryRef<Name, Input>, result: Schema.Schema.Type<typeof QueryResult>) => RemoteMessage;
1941
+ /**
1942
+ * The edges a connection shows: its server-known region with pending and
1943
+ * confirmed overlays placed around it, minus removed edges and edges whose
1944
+ * target is a tombstone.
1945
+ */
1946
+ visibleItems: (model: RemoteModel, connection: ConnectionIdentity) => ReadonlyArray<Edge>;
1947
+ /** A pure, serializable view of the whole cache. */
1948
+ inspect: (model: RemoteModel) => RemoteInspection;
1949
+ /** A pure, serializable view of one entity, or `undefined` if unknown. */
1950
+ inspectEntity: (model: RemoteModel, key: string) => RemoteInspection["entities"][number] | undefined;
1951
+ /**
1952
+ * Runs a mutation through `RemoteClient`, decoding its typed Output and
1953
+ * returning the result's normalized patches so the caller can reconcile them
1954
+ * through `Remote.update`'s `MutationSucceeded` (or `Remote.mutateInto`).
1955
+ */
1956
+ mutate: <Name extends string, Input, Output>(mutation: MutationDescriptor<Name, Input, Output>, input: Input, requestId: string) => Effect.Effect<{
1957
+ output: Output;
1958
+ entities: readonly {
1959
+ readonly entity: string;
1960
+ readonly id: string;
1961
+ readonly values: {
1962
+ readonly [x: string]: unknown;
1963
+ };
1964
+ }[];
1965
+ connections: ConnectionChange[];
1966
+ }, RemoteMutationError, RemoteClient>;
1967
+ /**
1968
+ * Runs a mutation and reconciles its patches into a `RemoteModel` in one step,
1969
+ * returning the new model alongside the typed Output. The model-level form of
1970
+ * `MutationStarted` → `RemoteClient.mutate` → `MutationSucceeded`; in an
1971
+ * application the three are `update` (with `optimistic`), a Command, and the
1972
+ * Message the Command returns, so the optimistic operations show meanwhile.
1973
+ */
1974
+ mutateInto: <Name extends string, Input, Output, AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store, string>, model: AppModel, mutation: MutationDescriptor<Name, Input, Output>, input: Input, requestId: string, options?: MutateOptions | undefined) => Effect.Effect<{
1975
+ output: Output;
1976
+ model: AppModel;
1977
+ }, RemoteMutationError, RemoteClient>;
1978
+ /**
1979
+ * A Foldkit Subscription entry that plans a Surface's missing fields from the
1980
+ * Model and fetches them through `RemoteClient`, emitting a `RemoteMessage`
1981
+ * per outcome. Wrap it in an application Message (`toMessage`) and reduce it
1982
+ * with the domain's `update`. Under a refreshing `policy` the entry first
1983
+ * emits `RefreshStarted`, so the fields being refetched read as `Refreshing`
1984
+ * while the request is pending.
1985
+ */
1986
+ observe: <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?: ObserveOptions) => EntryWithoutKeepAlive<AppModel, Message, ReadDependencies, RemoteClient>;
1987
+ /**
1988
+ * A Foldkit Subscription entry that consumes the live stream for a Surface's
1989
+ * requirements, emitting a `LiveReceived` per event and a `ReadFailed` when
1990
+ * the stream breaks (including `ResumeUnavailable`). The resume cursor is read
1991
+ * from `RemoteModel.live`, so the application tracks no cursor of its own.
1992
+ */
1993
+ 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, {
1994
+ readonly requirements: ReadonlyArray<Requirement$1>;
1995
+ readonly cursor: LiveCursor;
1996
+ }, RemoteClient>;
1997
+ };
1998
+ //#endregion
1999
+ export { Entity$1 as Entity, type RelationRequirement, type Requirement };
2000
+ //# sourceMappingURL=index.d.mts.map