foldkit-remote 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,64 @@
1
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";
2
+ import * as Domain from "foldkit-entity";
3
+ import { EntryWithoutKeepAlive } from "foldkit/subscription";
4
+ import { ActiveSurface, Contract, Invalid, Metadata, ModelRef, Projection, Surface, Wiring } from "foldkit-surface";
3
5
  import { Rpc, RpcGroup } from "effect/unstable/rpc";
4
6
  import { KeyValueStore } from "effect/unstable/persistence";
5
7
  import { Command } from "foldkit/command";
6
- import { EntryWithoutKeepAlive } from "foldkit/subscription";
8
+ //#region ../metadata/dist/index.d.mts
9
+ //#region src/index.d.ts
10
+ /** Marks a `Metadata` value. Its entries are private to this module. */
11
+ declare const MetadataTypeId: unique symbol;
12
+ type MetadataTypeId = typeof MetadataTypeId;
13
+ /**
14
+ * Declarative facts an interpreter attaches to a node it does not own, such as
15
+ * the server data a Remote selection needs. The carrier holds and combines
16
+ * them without knowing what they mean; a package reads only the key it owns.
17
+ *
18
+ * Opaque: only a key's `of` and `Metadata.combine` make one, so entries cannot
19
+ * be forged past a key's type or `merge`, and they are frozen.
20
+ */
21
+ interface Metadata$1 {
22
+ readonly [MetadataTypeId]: MetadataTypeId;
23
+ }
24
+ /**
25
+ * An interpreter's typed slot in `Metadata`. Lookup is by the key object, never
26
+ * its `name`, so two packages cannot collide by choosing the same string.
27
+ */
28
+ interface MetadataKey<A> {
29
+ /** For tooling output only. */
30
+ readonly name: string;
31
+ /** Normalizes the entries gathered from combined values, e.g. unioning duplicates. */
32
+ readonly merge: (values: ReadonlyArray<A>) => ReadonlyArray<A>;
33
+ /** One line per entry for tooling output. */
34
+ readonly summarize: (value: A) => string;
35
+ readonly of: (...values: ReadonlyArray<A>) => Metadata$1;
36
+ readonly get: (metadata: Metadata$1) => ReadonlyArray<A>;
37
+ }
38
+ /** One key's entries as serializable text, named by the key. */
39
+ interface MetadataSummary {
40
+ readonly name: string;
41
+ readonly entries: readonly string[];
42
+ }
43
+ declare const Metadata$1: {
44
+ /**
45
+ * Declares an interpreter's slot. Call once per package, at module level:
46
+ * entries are found by the key object, so two copies of a package (a
47
+ * duplicated install, a reloaded module) do not see each other's entries.
48
+ */
49
+ key: <A>(name: string, options: {
50
+ readonly merge: (values: ReadonlyArray<A>) => ReadonlyArray<A>;
51
+ readonly summarize: (value: A) => string;
52
+ }) => MetadataKey<A>;
53
+ empty: Metadata$1;
54
+ /** True only for a value this module made; a copy or a hand-built brand is not one. */
55
+ is: (value: unknown) => value is Metadata$1;
56
+ /** Gathers every part's entries and runs each key's `merge` over its group. */
57
+ combine: (parts: ReadonlyArray<Metadata$1>) => Metadata$1;
58
+ summarize: (metadata: Metadata$1) => readonly MetadataSummary[];
59
+ };
60
+ //#endregion
61
+ //#endregion
7
62
  //#region src/connection.d.ts
8
63
  export interface EdgeRef {
9
64
  readonly entity: string;
@@ -49,6 +104,51 @@ export declare const hasNext: (connection: Connection) => boolean;
49
104
  /** A connection with more than one segment has an explicit unknown gap. */
50
105
  export declare const isGapped: (connection: Connection) => boolean;
51
106
  //#endregion
107
+ //#region src/remoteData.d.ts
108
+ export interface RemoteError {
109
+ readonly _tag: string;
110
+ readonly message: string;
111
+ }
112
+ export type RemoteData<A> = {
113
+ readonly _tag: 'Initial';
114
+ } | {
115
+ readonly _tag: 'Loading';
116
+ } | {
117
+ readonly _tag: 'Ready';
118
+ readonly value: A;
119
+ } | {
120
+ readonly _tag: 'Refreshing';
121
+ readonly value: A;
122
+ } | {
123
+ readonly _tag: 'Failed';
124
+ readonly error: RemoteError;
125
+ readonly previous?: A;
126
+ } | {
127
+ readonly _tag: 'NotFound';
128
+ };
129
+ export declare const remoteErrorSchema: Schema.Struct<{
130
+ readonly _tag: Schema.String;
131
+ readonly message: Schema.String;
132
+ }>;
133
+ export declare const remoteDataSchema: <A>(value: Schema.Schema<A>) => Schema.Codec<RemoteData<A>, unknown>;
134
+ export declare const RemoteData: {
135
+ /**
136
+ * The `RemoteData` schema for a value schema. Exposed so a `RemoteData` can
137
+ * be embedded in a hand-written Model schema, not only through `Remote.select`.
138
+ */
139
+ schema: <A>(value: Schema.Schema<A>) => Schema.Schema<RemoteData<A>>;
140
+ /** Exhaustive: omitting a state is a compile error. */
141
+ match: <A, R>(data: RemoteData<A>, cases: {
142
+ readonly Initial: () => R;
143
+ readonly Loading: () => R;
144
+ readonly Ready: (value: A) => R;
145
+ readonly Refreshing: (value: A) => R;
146
+ readonly Failed: (error: RemoteError, previous: Option.Option<A>) => R;
147
+ readonly NotFound: () => R;
148
+ }) => R;
149
+ map: <A, B>(data: RemoteData<A>, f: (value: A) => B) => RemoteData<B>;
150
+ };
151
+ //#endregion
52
152
  //#region src/store.d.ts
53
153
  export type EntityKey = string;
54
154
  export interface EntityEntry {
@@ -128,6 +228,8 @@ export interface MutationState {
128
228
  readonly pending: ReadonlySet<string>;
129
229
  readonly applied: ReadonlySet<string>;
130
230
  readonly failed: ReadonlySet<string>;
231
+ /** Why each request in `failed` failed, kept exactly as long as `failed` keeps its id. */
232
+ readonly errors: ReadonlyMap<string, RemoteError>;
131
233
  /**
132
234
  * How many mutations this model has started. A bound domain takes its next
133
235
  * request id from here, so `update` stays pure and the id exists before the
@@ -137,7 +239,21 @@ export interface MutationState {
137
239
  }
138
240
  export declare const emptyMutationState: MutationState;
139
241
  export declare const beginMutation: (state: MutationState, requestId: string) => MutationState;
140
- export declare const failMutation: (state: MutationState, requestId: string) => MutationState;
242
+ export declare const failMutation: (state: MutationState, requestId: string, error: RemoteError) => MutationState;
243
+ /** What Remote knows of one mutation request, by the id `mutate` returned. */
244
+ export type MutationStatus =
245
+ /** Never started here, or settled so long ago its id has left the window. */
246
+ {
247
+ readonly _tag: 'Unknown';
248
+ } | {
249
+ readonly _tag: 'Pending';
250
+ } | {
251
+ readonly _tag: 'Applied';
252
+ } | {
253
+ readonly _tag: 'Failed';
254
+ readonly error: RemoteError;
255
+ };
256
+ export declare const mutationStatus: (state: MutationState, requestId: string) => MutationStatus;
141
257
  export interface Reconciled {
142
258
  readonly store: EntityStore;
143
259
  readonly state: MutationState;
@@ -147,7 +263,10 @@ export interface Reconciled {
147
263
  * with the same `requestId` (a retry, or a live event describing the same change)
148
264
  * does not re-apply the entities, but still clears `pending`.
149
265
  */
150
- export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>) => Reconciled;
266
+ export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, deleted?: ReadonlyArray<{
267
+ readonly entity: string;
268
+ readonly id: string;
269
+ }>) => Reconciled;
151
270
  /** A mutation an application declares: its name and input/output codecs. */
152
271
  export interface MutationDescriptor<Name extends string, Input, Output> {
153
272
  readonly name: Name;
@@ -171,6 +290,130 @@ export declare const Mutation: {
171
290
  }) => MutationDescriptor<Name, TypeOf<Input>, TypeOf<Output>>;
172
291
  };
173
292
  //#endregion
293
+ //#region src/query.d.ts
294
+ export type LiveInsertion = 'visible' | 'boundary' | 'invalidate' | 'ignore';
295
+ export interface LivePolicy {
296
+ readonly prepend?: LiveInsertion;
297
+ readonly append?: LiveInsertion;
298
+ }
299
+ export interface ConnectionSpec<Entity extends string = string> {
300
+ readonly entity: Entity;
301
+ readonly edgeKey?: Schema.Schema<unknown>;
302
+ readonly live?: LivePolicy;
303
+ }
304
+ export interface QueryWindow {
305
+ readonly first?: number | undefined;
306
+ readonly last?: number | undefined;
307
+ readonly after?: Cursor | undefined;
308
+ readonly before?: Cursor | undefined;
309
+ }
310
+ export interface QueryRef<Name extends string, Input> {
311
+ readonly query: Name;
312
+ readonly input: Input;
313
+ /** The input codec, so a `QueryRef` can encode itself without its descriptor. */
314
+ readonly Input: Schema.Codec<Input>;
315
+ readonly window: QueryWindow;
316
+ /** Connection identity: descriptor + canonical input, excluding the window. */
317
+ readonly identity: string;
318
+ }
319
+ export interface QueryDescriptor<Name extends string, Input, Result> {
320
+ readonly name: Name;
321
+ readonly Input: Schema.Codec<Input>;
322
+ readonly Result: Result;
323
+ readonly ref: (input: Input) => QueryRef<Name, Input>;
324
+ }
325
+ /** Stable stringify: object keys sorted, undefined-valued keys dropped, so equal inputs encode equally. */
326
+ export declare const stableStringify: (value: unknown) => string;
327
+ /**
328
+ * `Result: Project` (or anything with the entity's `name`, as `Query.connection`
329
+ * takes) means a connection over it; a `ConnectionSpec` names its `entity`
330
+ * instead and is the result as given.
331
+ */
332
+ export type ResultOf<Result> = Result extends {
333
+ readonly name: infer Entity extends string;
334
+ } ? ConnectionSpec<Entity> : Result;
335
+ export declare const Query: {
336
+ /** Declares the entity and options a query's result is a connection over. */
337
+ connection: <Entity extends string>(entity: {
338
+ readonly name: Entity;
339
+ }, options?: {
340
+ readonly edgeKey?: Schema.Schema<unknown>;
341
+ readonly live?: LivePolicy;
342
+ }) => ConnectionSpec<Entity>;
343
+ /**
344
+ * Declares a query. `Input` is a codec or the fields of the `Schema.Struct` it
345
+ * would be; `Result` is a `Query.connection(...)`, or the entity the result is
346
+ * a connection over.
347
+ */
348
+ make: <const Name extends string, Input extends SchemaOrFields, Result>(name: Name, config: {
349
+ readonly Input: Input;
350
+ readonly Result: Result;
351
+ }) => QueryDescriptor<Name, TypeOf<Input>, ResultOf<Result>>;
352
+ first: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
353
+ last: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
354
+ after: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
355
+ before: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
356
+ };
357
+ //#endregion
358
+ //#region src/requirement.d.ts
359
+ /**
360
+ * The slice required of an entity. `windows` carries a pagination window per
361
+ * relation field, and `relations` the slice required of each relation's
362
+ * target, so one requirement describes a whole selection graph.
363
+ */
364
+ export interface RelationRequirement {
365
+ readonly entity: string;
366
+ readonly fields: readonly string[];
367
+ readonly windows?: Readonly<Record<string, QueryWindow>> | undefined;
368
+ readonly relations?: Readonly<Record<string, RelationRequirement>> | undefined;
369
+ }
370
+ export interface Requirement extends RelationRequirement {
371
+ readonly id: string;
372
+ /** The projection also subscribes to changes of this entity (`Data.live`). */
373
+ readonly live?: boolean | undefined;
374
+ }
375
+ /**
376
+ * A query connection a projection reads: the page it first asks for and the
377
+ * slice it selects of each item. `identity` is the connection's (query plus
378
+ * canonical input, excluding the window).
379
+ */
380
+ export interface ConnectionRequirement {
381
+ readonly identity: string;
382
+ readonly window: QueryWindow;
383
+ readonly select: RelationRequirement;
384
+ }
385
+ /**
386
+ * Merges connection requirements for the same connection and window into one,
387
+ * unioning what they select of each item; the first keeps its other properties.
388
+ */
389
+ declare function mergeConnections(connections: readonly ConnectionRequirement[]): readonly ConnectionRequirement[];
390
+ /** Unions two relation slices for the same target: fields, windows, and nested relations. */
391
+ declare function mergeRelation(current: RelationRequirement, next: RelationRequirement): RelationRequirement;
392
+ /** Unions requirements for the same entity + id, dropping duplicate fields. */
393
+ declare function mergeRequirements(requirements: readonly Requirement[]): readonly Requirement[];
394
+ /**
395
+ * Requirement helpers, for the packages that plan and serve requirements.
396
+ * `merge` unions same-entity+id requirements; `mergeRelation` unions two
397
+ * slices of one target (fields, windows, nested relations).
398
+ */
399
+ export declare const Requirement: {
400
+ merge: typeof mergeRequirements;
401
+ mergeRelation: typeof mergeRelation;
402
+ mergeConnections: typeof mergeConnections;
403
+ };
404
+ /** Remote's entity requirements on a Projection, unioned per entity and id as nodes compose. */
405
+ export declare const RemoteRequirements: MetadataKey<Requirement>;
406
+ /** Remote's query connections on a Projection, unioned per connection and window. */
407
+ export declare const RemoteConnections: MetadataKey<ConnectionRequirement>;
408
+ /** The entity requirements a Projection carries. */
409
+ export declare const requirementsOf: (projection: {
410
+ readonly metadata: Metadata;
411
+ }) => ReadonlyArray<Requirement>;
412
+ /** The query connections a Projection carries. */
413
+ export declare const connectionsOf: (projection: {
414
+ readonly metadata: Metadata;
415
+ }) => ReadonlyArray<ConnectionRequirement>;
416
+ //#endregion
174
417
  //#region src/optimistic.d.ts
175
418
  export interface EntityLayer {
176
419
  readonly id: string;
@@ -257,7 +500,10 @@ export declare const pruneOverlays: (optimistic: OptimisticState, connection: st
257
500
  * a later layer re-wins on rebase. Confirmed connection changes are recorded
258
501
  * once per request, as overlays the request no longer owns.
259
502
  */
260
- export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>) => {
503
+ export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>, deleted?: ReadonlyArray<{
504
+ readonly entity: string;
505
+ readonly id: string;
506
+ }>) => {
261
507
  readonly store: EntityStore;
262
508
  readonly state: MutationState;
263
509
  readonly optimistic: OptimisticState;
@@ -275,71 +521,6 @@ export declare const settleFailure: (optimistic: OptimisticState, requestId: str
275
521
  */
276
522
  export declare const visibleItems: (connection: Connection, connectionId: string, overlays: ReadonlyArray<ConnectionOverlay>, store?: EntityStore) => ReadonlyArray<Edge>;
277
523
  //#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
524
  //#region src/live.d.ts
344
525
  export type LiveCursor = number;
345
526
  export type LiveEvent = {
@@ -427,10 +608,10 @@ export declare const liveHasNext: (connection: Connection, state: LiveState, con
427
608
  /** A connection to keep: its identity, and what a page of it selects of each item, if a projection reads it. */
428
609
  export interface ConnectionRoot {
429
610
  readonly identity: string;
430
- readonly select?: RelationRequirement$1 | undefined;
611
+ readonly select?: RelationRequirement | undefined;
431
612
  }
432
613
  export interface RetentionRoots {
433
- readonly requirements: ReadonlyArray<Requirement$1>;
614
+ readonly requirements: ReadonlyArray<Requirement>;
434
615
  /** Connections (`QueryRef.identity`) to keep, with their edges' targets and what `select` reaches through them. */
435
616
  readonly connections: ReadonlyArray<ConnectionRoot>;
436
617
  }
@@ -468,9 +649,17 @@ export interface SnapshotOptions {
468
649
  }
469
650
  /** How a snapshot meets a store that already has entries. */
470
651
  export type MergePolicy = 'replace' | 'preserve-existing';
652
+ /**
653
+ * The snapshot text, or `undefined` when it would exceed `maxBytes`. Only the
654
+ * entity store goes in; pass `model.entities`, never the whole `RemoteModel`.
655
+ */
656
+ declare function dehydrate(store: EntityStore, options?: SnapshotOptions & {
657
+ readonly maxBytes?: undefined;
658
+ }): string;
659
+ declare function dehydrate(store: EntityStore, options?: SnapshotOptions): string | undefined;
471
660
  export declare const RemotePersistence: {
472
661
  /** The snapshot text, or `undefined` when it would exceed `maxBytes`. */
473
- dehydrate: (store: EntityStore, options?: SnapshotOptions) => string | undefined;
662
+ dehydrate: typeof dehydrate;
474
663
  /** The store a snapshot text holds, or `undefined` when it is refused. */
475
664
  hydrate: (raw: string | undefined | null, options?: SnapshotOptions) => EntityStore | undefined;
476
665
  /** A snapshot brought into a store by policy. */
@@ -531,11 +720,11 @@ export declare const WindowSchema: Schema.Struct<{
531
720
  export declare const MAX_FIELDS_PER_REQUEST = 256;
532
721
  /** A selection may not nest relations deeper than this; the wire refuses more. */
533
722
  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>;
723
+ export declare const RelationRequest: Schema.Codec<RelationRequirement, RelationRequirement, never, never>;
724
+ export declare const ReadRequest: Schema.Codec<Requirement, Requirement>;
536
725
  export declare const ReadBatch: Schema.Struct<{
537
726
  readonly version: Schema.Number;
538
- readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
727
+ readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
539
728
  }>;
540
729
  export declare const NormalizedEntity: Schema.Struct<{
541
730
  readonly entity: Schema.String;
@@ -605,10 +794,15 @@ export declare const MutationResult: Schema.Struct<{
605
794
  readonly key: Schema.String;
606
795
  }>;
607
796
  }>]>>>;
797
+ /** Entities the mutation deleted; the client knows them absent from then on. */
798
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
799
+ readonly entity: Schema.String;
800
+ readonly id: Schema.String;
801
+ }>>>;
608
802
  }>;
609
803
  export declare const LiveRequirement: Schema.Struct<{
610
804
  readonly version: Schema.Number;
611
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
805
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
612
806
  /** Resume cursor; events at or before it are duplicates. */
613
807
  readonly after: Schema.Number;
614
808
  }>;
@@ -654,7 +848,7 @@ export declare const LiveChange: Schema.Union<readonly [Schema.Struct<{
654
848
  }>]>;
655
849
  export declare const Read: Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
656
850
  readonly version: Schema.Number;
657
- readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
851
+ readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
658
852
  }>, Schema.Struct<{
659
853
  readonly entities: Schema.$Array<Schema.Struct<{
660
854
  readonly entity: Schema.String;
@@ -693,10 +887,15 @@ export declare const Mutate: Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
693
887
  readonly key: Schema.String;
694
888
  }>;
695
889
  }>]>>>;
890
+ /** Entities the mutation deleted; the client knows them absent from then on. */
891
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
892
+ readonly entity: Schema.String;
893
+ readonly id: Schema.String;
894
+ }>>>;
696
895
  }>, typeof RemoteMutationError, never, never>;
697
896
  export declare const Live: Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
698
897
  readonly version: Schema.Number;
699
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
898
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
700
899
  /** Resume cursor; events at or before it are duplicates. */
701
900
  readonly after: Schema.Number;
702
901
  }>, import("effect/unstable/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
@@ -819,7 +1018,7 @@ export declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
819
1018
  }>, typeof RemoteQueryError, never, never>;
820
1019
  export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
821
1020
  readonly version: Schema.Number;
822
- readonly requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1021
+ readonly requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
823
1022
  }>, Schema.Struct<{
824
1023
  readonly entities: Schema.$Array<Schema.Struct<{
825
1024
  readonly entity: Schema.String;
@@ -857,9 +1056,14 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
857
1056
  readonly key: Schema.String;
858
1057
  }>;
859
1058
  }>]>>>;
1059
+ /** Entities the mutation deleted; the client knows them absent from then on. */
1060
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
1061
+ readonly entity: Schema.String;
1062
+ readonly id: Schema.String;
1063
+ }>>>;
860
1064
  }>, typeof RemoteMutationError, never, never> | Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
861
1065
  readonly version: Schema.Number;
862
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1066
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
863
1067
  /** Resume cursor; events at or before it are duplicates. */
864
1068
  readonly after: Schema.Number;
865
1069
  }>, import("effect/unstable/rpc/RpcSchema").Stream<Schema.Union<readonly [Schema.Struct<{
@@ -930,51 +1134,6 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
930
1134
  }>]>;
931
1135
  }>, typeof RemoteQueryError, never, never>>;
932
1136
  //#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
1137
  //#region src/model.d.ts
979
1138
  /**
980
1139
  * The normalized cache as a Foldkit Submodel. `Remote.define` returns a schema
@@ -1000,29 +1159,40 @@ export interface RemoteModel {
1000
1159
  * fetching this".
1001
1160
  */
1002
1161
  readonly loading: ReadonlySet<string>;
1162
+ /**
1163
+ * `Remote.refresh` generations. The read entries restart when `requested`
1164
+ * moves, so a read sent before a refresh cannot land after it; `started` is
1165
+ * the latest generation a read began under.
1166
+ */
1167
+ readonly refresh: {
1168
+ readonly requested: number;
1169
+ readonly started: number;
1170
+ };
1003
1171
  }
1004
1172
  export declare const initialRemoteModel: RemoteModel;
1005
- export declare const remoteModelSchema: () => Schema.Schema<RemoteModel>;
1173
+ export declare const remoteModelSchema: () => Schema.Codec<RemoteModel, unknown>;
1006
1174
  /** The submodel's Messages; each reduces to `RemoteModel` through `updateRemote`. */
1007
1175
  export type RemoteMessage = {
1008
1176
  readonly _tag: 'ReadReceived';
1009
- readonly requests: readonly Requirement$1[];
1177
+ readonly requests: readonly Requirement[];
1010
1178
  readonly result: Schema.Schema.Type<typeof ReadBatchResult>;
1011
1179
  readonly now: number;
1012
1180
  } | {
1013
1181
  readonly _tag: 'ReadFailed';
1014
- readonly requests: readonly Requirement$1[];
1182
+ readonly requests: readonly Requirement[];
1015
1183
  readonly error: RemoteError;
1016
1184
  } |
1017
1185
  /** A refetch of present fields began; they read as `Refreshing` until it lands. */
1018
1186
  {
1019
1187
  readonly _tag: 'RefreshStarted';
1020
- readonly requests: readonly Requirement$1[];
1188
+ readonly requests: readonly Requirement[];
1021
1189
  } |
1022
1190
  /** A read began; the fields it asks for that the store lacks read as `Loading`. */
1023
1191
  {
1024
1192
  readonly _tag: 'ReadStarted';
1025
- readonly requests: readonly Requirement$1[];
1193
+ readonly requests: readonly Requirement[];
1194
+ /** The refresh generation the read was planned under. */
1195
+ readonly refresh?: number | undefined;
1026
1196
  } |
1027
1197
  /** The active Surfaces' roots changed; everything they do not reach is collected. */
1028
1198
  {
@@ -1046,6 +1216,11 @@ export type RemoteMessage = {
1046
1216
  readonly entities: readonly NormalizedPatch[];
1047
1217
  /** Connection changes the server confirmed; they replace the request's own. */
1048
1218
  readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
1219
+ /** Entities the mutation deleted: tombstoned, which hides them from every connection. */
1220
+ readonly deleted?: ReadonlyArray<{
1221
+ readonly entity: string;
1222
+ readonly id: string;
1223
+ }> | undefined;
1049
1224
  } | {
1050
1225
  readonly _tag: 'MutationFailed';
1051
1226
  readonly requestId: string;
@@ -1079,10 +1254,10 @@ export type RemoteMessage = {
1079
1254
  readonly error: RemoteError;
1080
1255
  };
1081
1256
  export declare const retentionRootsSchema: Schema.Struct<{
1082
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1257
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1083
1258
  readonly connections: Schema.$Array<Schema.Struct<{
1084
1259
  readonly identity: Schema.String;
1085
- readonly select: Schema.optional<Schema.Codec<import("foldkit-surface").RelationRequirement, import("foldkit-surface").RelationRequirement, never, never>>;
1260
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1086
1261
  }>>;
1087
1262
  }>;
1088
1263
  /**
@@ -1091,7 +1266,7 @@ export declare const retentionRootsSchema: Schema.Struct<{
1091
1266
  */
1092
1267
  export declare const remoteMessageCases: {
1093
1268
  ReadReceived: {
1094
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1269
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1095
1270
  result: Schema.Struct<{
1096
1271
  readonly entities: Schema.$Array<Schema.Struct<{
1097
1272
  readonly entity: Schema.String;
@@ -1102,24 +1277,25 @@ export declare const remoteMessageCases: {
1102
1277
  now: Schema.Number;
1103
1278
  };
1104
1279
  ReadFailed: {
1105
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1280
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1106
1281
  error: Schema.Struct<{
1107
1282
  readonly _tag: Schema.String;
1108
1283
  readonly message: Schema.String;
1109
1284
  }>;
1110
1285
  };
1111
1286
  RefreshStarted: {
1112
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1287
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1113
1288
  };
1114
1289
  ReadStarted: {
1115
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1290
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1291
+ refresh: Schema.optional<Schema.Number>;
1116
1292
  };
1117
1293
  RetentionChanged: {
1118
1294
  roots: Schema.Struct<{
1119
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
1295
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1120
1296
  readonly connections: Schema.$Array<Schema.Struct<{
1121
1297
  readonly identity: Schema.String;
1122
- readonly select: Schema.optional<Schema.Codec<import("foldkit-surface").RelationRequirement, import("foldkit-surface").RelationRequirement, never, never>>;
1298
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1123
1299
  }>>;
1124
1300
  }>;
1125
1301
  };
@@ -1139,6 +1315,10 @@ export declare const remoteMessageCases: {
1139
1315
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1140
1316
  }>>;
1141
1317
  connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
1318
+ deleted: Schema.optional<Schema.$Array<Schema.Struct<{
1319
+ readonly entity: Schema.String;
1320
+ readonly id: Schema.String;
1321
+ }>>>;
1142
1322
  };
1143
1323
  MutationFailed: {
1144
1324
  requestId: Schema.String;
@@ -1213,7 +1393,7 @@ export declare const updateRemote: (model: RemoteModel, message: RemoteMessage)
1213
1393
  * accumulates rather than replaces. Every read path should use this rather than
1214
1394
  * reducing `writeEntity` by hand.
1215
1395
  */
1216
- export declare const writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement$1>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1396
+ export declare const writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1217
1397
  //#endregion
1218
1398
  //#region src/coalesce.d.ts
1219
1399
  type Batch = Schema.Schema.Type<typeof ReadBatch>;
@@ -1231,7 +1411,7 @@ export interface CoalesceOptions {
1231
1411
  readonly window?: Duration.Input | undefined;
1232
1412
  }
1233
1413
  /** A stable key for a requirement, so an equal requirement in flight is joined. */
1234
- export declare const requirementKey: (requirement: Requirement$1) => string;
1414
+ export declare const requirementKey: (requirement: Requirement) => string;
1235
1415
  /**
1236
1416
  * Wraps a raw query so that an identical query in flight (same query, input,
1237
1417
  * and window) is joined rather than run again; distinct queries run
@@ -1251,7 +1431,7 @@ declare const RemoteClient_base: Context.ServiceClass<RemoteClient, "foldkit-rem
1251
1431
  readonly query: (request: Schema.Schema.Type<typeof QueryRequest>) => Effect.Effect<Schema.Schema.Type<typeof QueryResult>, RemoteQueryError>;
1252
1432
  readonly mutate: (request: Schema.Schema.Type<typeof MutationRequest>) => Effect.Effect<Schema.Schema.Type<typeof MutationResult>, RemoteMutationError>;
1253
1433
  readonly live: (request: {
1254
- readonly requirements: ReadonlyArray<Requirement$1>;
1434
+ readonly requirements: ReadonlyArray<Requirement>;
1255
1435
  readonly after: LiveCursor;
1256
1436
  }) => Stream.Stream<LiveEvent, RemoteLiveError | RemoteProtocolError>;
1257
1437
  }>;
@@ -1295,6 +1475,10 @@ export declare const mutateRemote: <Name extends string, Input, Output>(mutation
1295
1475
  };
1296
1476
  }[];
1297
1477
  connections: ConnectionChange[];
1478
+ deleted: readonly {
1479
+ readonly entity: string;
1480
+ readonly id: string;
1481
+ }[];
1298
1482
  }, RemoteMutationError, RemoteClient>;
1299
1483
  //#endregion
1300
1484
  //#region src/relation.d.ts
@@ -1326,7 +1510,7 @@ export declare const refParts: (encoded: string) => RefParts;
1326
1510
  */
1327
1511
  export declare const refsIn: (value: unknown) => ReadonlyArray<RefParts>;
1328
1512
  /** The refs in a relation value that name the relation's target entity, and no other. */
1329
- export declare const targetsOf: (value: unknown, relation: RelationRequirement$1) => ReadonlyArray<RefParts>;
1513
+ export declare const targetsOf: (value: unknown, relation: RelationRequirement) => ReadonlyArray<RefParts>;
1330
1514
  export declare const isRefPage: (value: unknown) => value is RefPageValue;
1331
1515
  /**
1332
1516
  * The relation shape an entity field schema declares: a ref (`one`), a nullable
@@ -1355,7 +1539,7 @@ export interface Selection<Value, Name extends string = string, Shape extends 'e
1355
1539
  /** Pagination windows for nested relation fields, keyed by field name. */
1356
1540
  readonly connections?: Readonly<Record<string, QueryWindow>> | undefined;
1357
1541
  /** The slice required of each nested relation's target, keyed by field name. */
1358
- readonly relations?: Readonly<Record<string, RelationRequirement$1>> | undefined;
1542
+ readonly relations?: Readonly<Record<string, RelationRequirement>> | undefined;
1359
1543
  /** Present when this selection is itself a paginated relation. */
1360
1544
  readonly window?: QueryWindow | undefined;
1361
1545
  /** Phantom: see `Shape`. */
@@ -1377,8 +1561,13 @@ type NestedValue<Field, Sel> = Sel extends Selection<infer V, string, 'connectio
1377
1561
  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]>; }>;
1378
1562
  export declare const pageSchema: (item: AnySchema) => AnySchema;
1379
1563
  /** The requirement a nested selection contributes for its relation's target. */
1380
- export declare const relationOf: (selection: Selection<unknown>) => RelationRequirement$1;
1564
+ export declare const relationOf: (selection: Selection<unknown>) => RelationRequirement;
1381
1565
  export declare const Selection: {
1566
+ /**
1567
+ * The Remote Selection of a `foldkit-entity` Selection: the same members, read
1568
+ * from Remote's store. `true` on a relation reads its refs, as it does here.
1569
+ */
1570
+ from: <Name extends string, S extends Schema.Constraint>(selection: Domain.Selection<Name, unknown, S>) => Selection<S["Type"], Name, "entity">;
1382
1571
  /**
1383
1572
  * The fields to read of `entity`. A nested `Selection` on a relation field
1384
1573
  * reads through the ref (or refs, or page of refs) the field holds into the
@@ -1404,7 +1593,7 @@ interface Assembled {
1404
1593
  * not present yet. A tombstoned target reads as `null` (or is dropped from a
1405
1594
  * list), so the Selection's codec decides whether that is a failure.
1406
1595
  */
1407
- export declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement$1) => Assembled | undefined;
1596
+ export declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement) => Assembled | undefined;
1408
1597
  //#endregion
1409
1598
  //#region src/entity.d.ts
1410
1599
  export type AnySchema = Schema.Schema<unknown>;
@@ -1447,7 +1636,25 @@ export interface RefPage<Name extends string, F extends Schema.Struct.Fields = S
1447
1636
  readonly hasNext: boolean;
1448
1637
  readonly hasPrevious: boolean;
1449
1638
  }
1639
+ /** The ref codec a `foldkit-entity` relation becomes: one ref, a nullable ref, or an array of refs. */
1640
+ type RelationField<Spec> = Spec extends Domain.RelationSpec<infer Target, infer Cardinality, infer Optional> ? Cardinality extends 'many' ? Schema.$Array<Schema.Codec<EntityRef<Target['name']>, string>> : Optional extends true ? Schema.NullOr<Schema.Codec<EntityRef<Target['name']>, string>> : Schema.Codec<EntityRef<Target['name']>, string> : never;
1641
+ /**
1642
+ * The fields Remote stores for a `foldkit-entity` Entity: its own fields, its
1643
+ * derived members (the server supplies them like any field), and each relation
1644
+ * as refs.
1645
+ */
1646
+ export type FieldsFrom<E> = E extends Domain.Entity<any, infer Fields, infer Relations, infer Derived> ? Fields & { readonly [K in keyof Derived]: Derived[K]['schema']; } & { readonly [K in keyof Relations]: RelationField<Relations[K]>; } : never;
1450
1647
  declare const Entity$1: {
1648
+ /**
1649
+ * The Remote descriptor of a `foldkit-entity` Entity. Relations declared with
1650
+ * `Entity.relate` become ref fields, so the store, the planner, and the server
1651
+ * treat it as they treat an `Entity.make` descriptor.
1652
+ */
1653
+ from: <E extends Domain.AnyEntity>(entity: E & {
1654
+ readonly fields: {
1655
+ readonly id: unknown;
1656
+ };
1657
+ }) => EntityDescriptor<E["name"], FieldsFrom<E>>;
1451
1658
  make: <const Name extends string, const F extends Schema.Struct.Fields & {
1452
1659
  readonly id: Schema.Schema<unknown>;
1453
1660
  }>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
@@ -1504,7 +1711,7 @@ export declare const inspectRemote: (model: RemoteModel) => RemoteInspection;
1504
1711
  export declare const inspectEntity: (model: RemoteModel, key: string) => RemoteInspection["entities"][number] | undefined;
1505
1712
  //#endregion
1506
1713
  //#region src/plan.d.ts
1507
- type Window = NonNullable<Requirement$1['windows']>[string];
1714
+ type Window = NonNullable<Requirement['windows']>[string];
1508
1715
  /** A stable key for a window, so two equal windows compare equal. */
1509
1716
  export declare const windowKey: (window: Window) => string;
1510
1717
  export interface PlanFreshness {
@@ -1517,7 +1724,7 @@ export interface PlanOptions {
1517
1724
  /** Plan every requested field, present or not, tombstoned or not. */
1518
1725
  readonly force?: boolean | undefined;
1519
1726
  }
1520
- export declare const plan: (store: EntityStore, requirements: readonly Requirement$1[], options?: PlanOptions) => ReadonlyArray<Requirement$1>;
1727
+ export declare const plan: (store: EntityStore, requirements: readonly Requirement[], options?: PlanOptions) => ReadonlyArray<Requirement>;
1521
1728
  //#endregion
1522
1729
  //#region src/policy.d.ts
1523
1730
  export type RemotePolicy =
@@ -1561,7 +1768,18 @@ export declare const RemotePolicy: {
1561
1768
  };
1562
1769
  //#endregion
1563
1770
  //#region src/index.d.ts
1564
- type EntityName<D> = D extends EntityDescriptor<infer Name, any> ? Name : never;
1771
+ /** What a domain registers: a Remote descriptor, or a `foldkit-entity` Entity (read through `Entity.from`). */
1772
+ export type EntityLike = EntityDescriptor<any, any> | Domain.AnyEntity;
1773
+ /**
1774
+ * What a read selects: a Remote Selection, or a `foldkit-entity` Selection
1775
+ * (read through `Selection.from`).
1776
+ */
1777
+ export type EntitySelection<Value, Name extends string> = Selection<Value, Name, 'entity'> | Domain.Selection<Name, unknown, Schema.Constraint & {
1778
+ readonly Type: Value;
1779
+ }>;
1780
+ type EntityName<D> = D extends {
1781
+ readonly name: infer Name extends string;
1782
+ } ? Name : never;
1565
1783
  type QueryName<D> = D extends QueryDescriptor<infer Name, any, any> ? Name : never;
1566
1784
  type MutationName<D> = D extends MutationDescriptor<infer Name, any, any> ? Name : never;
1567
1785
  /**
@@ -1572,11 +1790,11 @@ type MutationName<D> = D extends MutationDescriptor<infer Name, any, any> ? Name
1572
1790
  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`>;
1573
1791
  /** Nothing when a selection is of the query's entity; otherwise a branded failure naming both. */
1574
1792
  export type SelectsEntity<Entity extends string, Of extends string> = [Entity] extends [Of] ? unknown : Invalid<`the selection is of "${Entity}", but the query lists "${Of}"`>;
1575
- 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>[]> {
1793
+ export interface RemoteDescriptor<Entities extends readonly EntityLike[] = readonly EntityLike[], Queries extends readonly QueryDescriptor<any, any, any>[] = readonly QueryDescriptor<any, any, any>[], Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly MutationDescriptor<any, any, any>[]> {
1576
1794
  readonly entities: Entities;
1577
1795
  readonly queries: Queries;
1578
1796
  readonly mutations: Mutations;
1579
- readonly Model: Schema.Schema<RemoteModel>;
1797
+ readonly Model: Schema.Codec<RemoteModel, unknown>;
1580
1798
  readonly initial: RemoteModel;
1581
1799
  readonly Message: Schema.Schema<RemoteMessage>;
1582
1800
  readonly update: (model: RemoteModel, message: RemoteMessage) => RemoteModel;
@@ -1613,7 +1831,17 @@ export interface DomainMutateOptions {
1613
1831
  }
1614
1832
  /** A Foldkit Subscription entry of the Remote domain, emitting its Messages through `RemoteClient`. */
1615
1833
  export type RemoteEntry<AppModel, Dependencies> = EntryWithoutKeepAlive<AppModel, RemoteMessage, Dependencies, RemoteClient>;
1834
+ /**
1835
+ * The entries `RemoteDomain.subscriptions` returns for an active record: a read
1836
+ * and a live entry per key (the live one idles when nothing is read live), and
1837
+ * `retain`.
1838
+ */
1839
+ export type SubscriptionEntries<AppModel, Active> = { readonly [K in keyof Active & (string | number) as `${K}.read` | `${K}.live`]: RemoteEntry<AppModel, any>; } & {
1840
+ readonly retain: RemoteEntry<AppModel, any>;
1841
+ };
1616
1842
  export interface SubscriptionsOptions extends ObserveOptions, LiveOptions, RetainOptions {}
1843
+ /** A Remote domain's wiring for an assembly: it routes Remote's Messages into `reduce`, brings its Subscriptions and contract, and requires `RemoteClient` from the runtime's resources Layer. */
1844
+ export type RemoteWiring<AppModel> = Wiring<AppModel, RemoteMessage | RemoteMessageInput, RemoteClient>;
1617
1845
  /** What `RemoteDomain.mutate` hands `update`: the Model with the request started, and the Command that settles it. */
1618
1846
  export interface MutationStarted<AppModel> {
1619
1847
  readonly model: AppModel;
@@ -1628,15 +1856,15 @@ export interface MutationStarted<AppModel> {
1628
1856
  * operations over them. Every method compiles to the `Remote.*` function of the
1629
1857
  * same name, which stays exported for tooling, SSR, and tests.
1630
1858
  */
1631
- 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> {
1859
+ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities extends readonly EntityLike[], 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> {
1632
1860
  /** `Remote.select`: a Projection reading one entity through a selection of a registered entity. */
1633
- get<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1861
+ get<Value, Name extends string>(selection: EntitySelection<Value, Name> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1634
1862
  /**
1635
1863
  * `get`, and the projection also subscribes to the entity's changes: its
1636
1864
  * requirements are marked `live`, so `subscriptions` derives a live entry for
1637
1865
  * the Surfaces that read it.
1638
1866
  */
1639
- live<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1867
+ live<Value, Name extends string>(selection: EntitySelection<Value, Name> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
1640
1868
  /**
1641
1869
  * A query connection read as a `Page` of items selected of the query's
1642
1870
  * entity: `Initial` until the page and every item's selected fields are
@@ -1651,6 +1879,8 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1651
1879
  previous<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
1652
1880
  /** A Command that runs the query and yields the `ConnectionMerged` (or `QueryFailed`) that reduces it: "load more". */
1653
1881
  fetch(ref: QueryRef<string, unknown>): Command<RemoteMessage, never, RemoteClient>;
1882
+ /** `Remote.refresh`: marks what a projection or a Surface requires as due, for its read entry to refetch. */
1883
+ refresh(model: AppModel, target: Projection<AppModel, unknown> | Surface<AppModel, any, any, void>): AppModel;
1654
1884
  /**
1655
1885
  * The Foldkit Subscription entries for the active Surfaces, keyed for
1656
1886
  * `Subscription.make`: a read entry per Surface (`Remote.observe`), a live
@@ -1659,9 +1889,9 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1659
1889
  * Surface's params are a function of the Model (`Surface.at`), so what is
1660
1890
  * fetched, subscribed, and retained follows the Model.
1661
1891
  */
1662
- subscriptions(active: Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>, options?: SubscriptionsOptions): Readonly<Record<string, RemoteEntry<AppModel, any>>>;
1892
+ subscriptions<const Active extends Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>>(active: Active, options?: SubscriptionsOptions): SubscriptionEntries<AppModel, Active>;
1663
1893
  /** `Remote.plan`: the requirements the store does not satisfy. */
1664
- plan<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions): ReadonlyArray<Requirement$1>;
1894
+ plan<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions): ReadonlyArray<Requirement>;
1665
1895
  /** `Remote.storeOf`: the visible store, base under the pending optimistic layers. */
1666
1896
  storeOf(model: AppModel): EntityStore;
1667
1897
  /**
@@ -1677,8 +1907,21 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1677
1907
  * mutation sequence unless `options.requestId` is given.
1678
1908
  */
1679
1909
  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>;
1910
+ /**
1911
+ * What Remote knows of a mutation `mutate` started, by its request id:
1912
+ * pending, applied, or failed with the error the server or transport gave.
1913
+ */
1914
+ mutation(model: AppModel, requestId: string): MutationStatus;
1680
1915
  /** `updateRemote` on the bound slice: reduces one of Remote's Messages, as `RemoteMessage` or as the application's union constructs it. */
1681
1916
  reduce(model: AppModel, message: RemoteMessage | RemoteMessageInput): AppModel;
1917
+ /**
1918
+ * How this domain joins an assembly: it routes Remote's Messages into
1919
+ * `reduce`, brings its Subscriptions and contract, and requires
1920
+ * `RemoteClient` from the runtime's resources Layer. One assembly holds at
1921
+ * most one Remote wiring: every domain claims the same tags, and routing
1922
+ * takes the first claimant.
1923
+ */
1924
+ wiring: <const Active extends Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>>(active: Active, options?: SubscriptionsOptions) => RemoteWiring<AppModel>;
1682
1925
  /** `Remote.inspect` of the bound slice. */
1683
1926
  inspect(model: AppModel): RemoteInspection;
1684
1927
  }
@@ -1700,7 +1943,7 @@ export type QueryWindowOptions = {
1700
1943
  };
1701
1944
  export type QueryOptions<Value, Entity extends string, Of extends string = Entity> = {
1702
1945
  /** What to read of each item: a selection of the query's entity (`Of`). */
1703
- readonly select: Selection<Value, Entity, 'entity'> & SelectsEntity<Entity, Of>;
1946
+ readonly select: EntitySelection<Value, Entity> & SelectsEntity<Entity, Of>;
1704
1947
  } & QueryWindowOptions;
1705
1948
  /** A query connection read as a `Page` of selected items; `ref` is the connection with its first window. */
1706
1949
  export interface QueryProjection<AppModel, Value, Name extends string, Input> extends Projection<AppModel, RemoteData<Page<Value>>> {
@@ -1744,12 +1987,14 @@ declare const PlannedQuery: Schema.Struct<{
1744
1987
  }>;
1745
1988
  /** The dependencies of the read entry: the entity fields to read and the queries to run. */
1746
1989
  export interface ReadDependencies {
1747
- readonly requirements: ReadonlyArray<Requirement$1>;
1990
+ readonly requirements: ReadonlyArray<Requirement>;
1748
1991
  readonly queries: ReadonlyArray<Schema.Schema.Type<typeof PlannedQuery>>;
1992
+ /** The Model's requested refresh generation: a refresh restarts the entry. */
1993
+ readonly refresh: number;
1749
1994
  }
1750
1995
  export declare const Remote: {
1751
1996
  /** The submodel's schema, the same for every domain; embed it in the application Model. */
1752
- Model: Schema.Schema<RemoteModel>;
1997
+ Model: Schema.Codec<RemoteModel, unknown, never, never>;
1753
1998
  /** The submodel's initial value. */
1754
1999
  initial: RemoteModel;
1755
2000
  /**
@@ -1759,7 +2004,7 @@ export declare const Remote: {
1759
2004
  */
1760
2005
  messages: {
1761
2006
  ReadReceived: {
1762
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
2007
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1763
2008
  result: Schema.Struct<{
1764
2009
  readonly entities: Schema.$Array<Schema.Struct<{
1765
2010
  readonly entity: Schema.String;
@@ -1770,21 +2015,22 @@ export declare const Remote: {
1770
2015
  now: Schema.Number;
1771
2016
  };
1772
2017
  ReadFailed: {
1773
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
2018
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1774
2019
  error: Schema.Struct<{
1775
2020
  readonly _tag: Schema.String;
1776
2021
  readonly message: Schema.String;
1777
2022
  }>;
1778
2023
  };
1779
2024
  RefreshStarted: {
1780
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
2025
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1781
2026
  };
1782
2027
  ReadStarted: {
1783
- requests: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
2028
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
2029
+ refresh: Schema.optional<Schema.Number>;
1784
2030
  };
1785
2031
  RetentionChanged: {
1786
2032
  roots: Schema.Struct<{
1787
- readonly requirements: Schema.$Array<Schema.Codec<Requirement$1, Requirement$1, never, never>>;
2033
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
1788
2034
  readonly connections: Schema.$Array<Schema.Struct<{
1789
2035
  readonly identity: Schema.String;
1790
2036
  readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
@@ -1807,6 +2053,10 @@ export declare const Remote: {
1807
2053
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1808
2054
  }>>;
1809
2055
  connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
2056
+ deleted: Schema.optional<Schema.$Array<Schema.Struct<{
2057
+ readonly entity: Schema.String;
2058
+ readonly id: Schema.String;
2059
+ }>>>;
1810
2060
  };
1811
2061
  MutationFailed: {
1812
2062
  requestId: Schema.String;
@@ -1854,7 +2104,7 @@ export declare const Remote: {
1854
2104
  * in one step; the result carries the application-facing operations. The
1855
2105
  * descriptor alone is `Remote.define`, the binding alone `Remote.at`.
1856
2106
  */
1857
- 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: {
2107
+ make: <AppModel, Store extends RemoteModel, const Entities extends readonly EntityLike[], const Queries extends readonly QueryDescriptor<any, any, any>[] = readonly [], const Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly []>(config: {
1858
2108
  readonly model: ModelRef<AppModel, Store>;
1859
2109
  readonly entities: Entities;
1860
2110
  readonly queries?: Queries;
@@ -1865,7 +2115,7 @@ export declare const Remote: {
1865
2115
  * mutations, plus the submodel. For a domain reused across applications or
1866
2116
  * bound in a test; `Remote.make` is the one-step form.
1867
2117
  */
1868
- 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: {
2118
+ define: <const Entities extends readonly EntityLike[], const Queries extends readonly QueryDescriptor<any, any, any>[] = readonly QueryDescriptor<any, any, any>[], const Mutations extends readonly MutationDescriptor<any, any, any>[] = readonly MutationDescriptor<any, any, any>[]>(config: {
1869
2119
  readonly entities: Entities;
1870
2120
  readonly queries?: Queries;
1871
2121
  readonly mutations?: Mutations;
@@ -1875,7 +2125,7 @@ export declare const Remote: {
1875
2125
  * registered entity names are carried on the returned value, so `Remote.select`
1876
2126
  * rejects a selection for an entity this domain never declared.
1877
2127
  */
1878
- 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]>>;
2128
+ at: <AppModel, Store extends RemoteModel, Entities extends readonly EntityLike[], Queries extends readonly QueryDescriptor<any, any, any>[], Mutations extends readonly MutationDescriptor<any, any, any>[]>(definition: RemoteDescriptor<Entities, Queries, Mutations>, store: ModelRef<AppModel, Store>) => BoundRemote<AppModel, Store, EntityName<Entities[number]>>;
1879
2129
  /**
1880
2130
  * A Projection node that reads a `RemoteData` value out of the store. The id
1881
2131
  * is supplied by the caller, usually from a Surface's params. The assembled
@@ -1883,13 +2133,13 @@ export declare const Remote: {
1883
2133
  * as `Failed` instead of being asserted into `Value`. A present value with a
1884
2134
  * stale field reads as `Refreshing`: an observer is refetching it.
1885
2135
  */
1886
- 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>>;
2136
+ select: <AppModel, Store extends RemoteModel, Names extends string, Value, Name extends string>(bound: BoundRemote<AppModel, Store, Names>, given: EntitySelection<Value, Name> & Registered<Name, Names, "Entity">) => (id: string) => Projection<AppModel, RemoteData<Value>>;
1887
2137
  /**
1888
2138
  * The pure plan for a projection against a Model: the requirements its
1889
2139
  * remote store does not satisfy, under `options` (freshness, force). A
1890
2140
  * Surface's projection is `surface.projection(params)`.
1891
2141
  */
1892
- plan: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store>, model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions) => ReadonlyArray<Requirement$1>;
2142
+ plan: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store>, model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions) => ReadonlyArray<Requirement>;
1893
2143
  /**
1894
2144
  * The queries a projection needs run before its connections read: those the
1895
2145
  * Model does not hold, or holds stale (every one under `force`).
@@ -1908,11 +2158,30 @@ export declare const Remote: {
1908
2158
  * is the clock it reads, so the planner itself stays pure and time-injected.
1909
2159
  */
1910
2160
  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>;
2161
+ /**
2162
+ * Marks what a projection, or a Surface without params, requires as due again.
2163
+ * Called from `update`: every selected field the store holds reads `Refreshing`,
2164
+ * and every loaded query connection is invalidated. Nothing is fetched here.
2165
+ * The read entries `Data.subscriptions` derives refetch it, because a stale
2166
+ * field or connection is planned again under every policy, so a refresh never
2167
+ * sends a request beside the entry already observing the same data.
2168
+ *
2169
+ * A refreshed connection's page replaces its pages, so items the server removed
2170
+ * or reordered follow it; pages loaded past the first are dropped and paged
2171
+ * again with `next`/`previous`. The read entries restart, so a read or query
2172
+ * sent before the refresh is not applied after it.
2173
+ *
2174
+ * The projection must be observed, which it is while it is on screen. Live
2175
+ * subscriptions are left as they are. For data nothing observes (SSR, tests),
2176
+ * use `Remote.prefetch` with `RemotePolicy.networkOnly`. Refreshing what is
2177
+ * already being refreshed returns the same Model.
2178
+ */
2179
+ refresh: <AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store>, model: AppModel, target: Projection<AppModel, unknown> | Surface<AppModel, any, any, void>) => AppModel;
1911
2180
  /**
1912
2181
  * Writes a read result into the store, recording each field's applied window.
1913
2182
  * `requests` are the planned requirements the result answers.
1914
2183
  */
1915
- writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement$1>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
2184
+ writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1916
2185
  /**
1917
2186
  * Adapts an Effect RPC client for `RemoteRpc` to `RemoteClient`, so an
1918
2187
  * application provides the transport's RPC layer instead of writing the
@@ -1987,6 +2256,10 @@ export declare const Remote: {
1987
2256
  };
1988
2257
  }[];
1989
2258
  connections: ConnectionChange[];
2259
+ deleted: readonly {
2260
+ readonly entity: string;
2261
+ readonly id: string;
2262
+ }[];
1990
2263
  }, RemoteMutationError, RemoteClient>;
1991
2264
  /**
1992
2265
  * Runs a mutation and reconciles its patches into a `RemoteModel` in one step,
@@ -2015,10 +2288,10 @@ export declare const Remote: {
2015
2288
  * from `RemoteModel.live`, so the application tracks no cursor of its own.
2016
2289
  */
2017
2290
  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, {
2018
- readonly requirements: ReadonlyArray<Requirement$1>;
2291
+ readonly requirements: ReadonlyArray<Requirement>;
2019
2292
  readonly cursor: LiveCursor;
2020
2293
  }, RemoteClient>;
2021
2294
  };
2022
2295
  //#endregion
2023
- export { Entity$1 as Entity, type RelationRequirement, type Requirement };
2296
+ export { Entity$1 as Entity };
2024
2297
  //# sourceMappingURL=index.d.mts.map