foldkit-remote 0.7.0 → 0.9.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,13 +1,13 @@
1
- import { Context, Duration, Effect, Layer, Option, Schema, Stream } from "effect";
1
+ import { Context, Duration, Effect, Layer, Option, Result, Schema, Stream } from "effect";
2
2
  import * as Domain from "foldkit-entity";
3
3
  import { AnyEntity, AnyQuery, Dependencies, InputExpr, Query as Query$1 } from "foldkit-entity";
4
+ import { Command } from "foldkit/command";
4
5
  import { EntryWithoutKeepAlive } from "foldkit/subscription";
5
6
  import { ActiveSurface, Contract, Invalid, Metadata, ModelRef, Projection, Surface, Wiring } from "foldkit-surface";
6
7
  import { Rpc, RpcGroup } from "effect/unstable/rpc";
7
8
  import { KeyValueStore } from "effect/unstable/persistence";
8
- import { Command } from "foldkit/command";
9
- //#region ../metadata/dist/index.d.mts
10
- //#region src/index.d.ts
9
+ import * as Update from "foldkit/update";
10
+ //#region ../metadata/src/index.d.ts
11
11
  /** Marks a `Metadata` value. Its entries are private to this module. */
12
12
  declare const MetadataTypeId: unique symbol;
13
13
  type MetadataTypeId = typeof MetadataTypeId;
@@ -59,7 +59,6 @@ declare const Metadata$1: {
59
59
  summarize: (metadata: Metadata$1) => readonly MetadataSummary[];
60
60
  };
61
61
  //#endregion
62
- //#endregion
63
62
  //#region src/connection.d.ts
64
63
  export interface EdgeRef {
65
64
  readonly entity: string;
@@ -202,6 +201,12 @@ export interface EntityEntry {
202
201
  readonly present: ReadonlySet<string>;
203
202
  /** Present fields whose value may be outdated (revalidation needed). */
204
203
  readonly stale: ReadonlySet<string>;
204
+ /**
205
+ * Fields the server settled without a value: asked for, and answered without
206
+ * them, whatever the reason. Not planned again until a refresh asks; a later
207
+ * write of the field clears it.
208
+ */
209
+ readonly unavailable: ReadonlySet<string>;
205
210
  /** The entity is known to be absent; a later write clears this. */
206
211
  readonly tombstone: boolean;
207
212
  /** Injected clock reading of the last write; never read from ambient state. */
@@ -221,6 +226,8 @@ export interface EntityWrite {
221
226
  readonly values: Readonly<Record<string, unknown>>;
222
227
  /** The canonical window each written relation field was fetched with. */
223
228
  readonly windows?: Readonly<Record<string, string>> | undefined;
229
+ /** When this write dates the entity, instead of the batch's `now`. */
230
+ readonly updatedAt?: number | undefined;
224
231
  }
225
232
  /**
226
233
  * Merges known values into many entities, copying the store once. Every
@@ -240,6 +247,14 @@ export declare const setStale: (store: EntityStore, marks: ReadonlyArray<readonl
240
247
  export declare const markStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
241
248
  /** Ends a refresh that did not land: the fields are present again as they were. */
242
249
  export declare const clearStale: (store: EntityStore, key: EntityKey, fields: Iterable<string>) => EntityStore;
250
+ /**
251
+ * Records fields the server settled without a value. A present field is left
252
+ * as it is: the answer that settled it was not about the value it holds.
253
+ * `false` forgets the marks, which is how a refresh asks again.
254
+ */
255
+ export declare const setUnavailable: (store: EntityStore, marks: ReadonlyArray<readonly [key: EntityKey, fields: Iterable<string>]>, unavailable: boolean) => EntityStore;
256
+ /** Whether the server settled this field without a value, and nothing has written it since. */
257
+ export declare const isFieldUnavailable: (store: EntityStore, key: EntityKey, field: string) => boolean;
243
258
  /** Records that the entity is known to be absent, so it is not refetched. */
244
259
  export declare const tombstone: (store: EntityStore, key: EntityKey) => EntityStore;
245
260
  /** Forgets everything known about the entity, including a tombstone. */
@@ -257,7 +272,8 @@ export declare const isFieldStale: (store: EntityStore, key: EntityKey, field: s
257
272
  export declare const readField: (store: EntityStore, key: EntityKey, field: string) => Option.Option<unknown>;
258
273
  /**
259
274
  * The fields the planner must fetch. A tombstone makes every field known
260
- * (absent), so it returns an empty list and the entity is not refetched. A
275
+ * (absent), so it returns an empty list and the entity is not refetched, and a
276
+ * field the server settled without a value is known the same way. A
261
277
  * requested window that differs from the one a field was fetched with also
262
278
  * marks it missing, but only when the stored window is known (never `""`), so a
263
279
  * writer that does not record windows cannot cause a refetch loop.
@@ -304,15 +320,23 @@ export interface Reconciled {
304
320
  readonly store: EntityStore;
305
321
  readonly state: MutationState;
306
322
  }
323
+ /** What a settled mutation wrote, as `MutationSucceeded` carries it. */
324
+ export interface MutationAnswer {
325
+ readonly entities: ReadonlyArray<NormalizedPatch>;
326
+ /** Entities the mutation deleted; each is tombstoned. */
327
+ readonly deleted?: ReadonlyArray<{
328
+ readonly entity: string;
329
+ readonly id: string;
330
+ }> | undefined;
331
+ /** Injected clock reading of the answer, which dates what it writes. */
332
+ readonly now: number;
333
+ }
307
334
  /**
308
335
  * Applies a mutation result once and marks the request settled. A second call
309
336
  * with the same `requestId` (a retry, or a live event describing the same change)
310
337
  * does not re-apply the entities, but still clears `pending`.
311
338
  */
312
- export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, deleted?: ReadonlyArray<{
313
- readonly entity: string;
314
- readonly id: string;
315
- }>) => Reconciled;
339
+ export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, answer: MutationAnswer) => Reconciled;
316
340
  /** A mutation an application declares: its name and input/output codecs. */
317
341
  export interface MutationDescriptor<Name extends string, Input, Output> {
318
342
  readonly name: Name;
@@ -593,7 +617,12 @@ export declare const addLayer: (optimistic: OptimisticState, layer: EntityLayer)
593
617
  export declare const removeLayer: (optimistic: OptimisticState, id: string) => OptimisticState;
594
618
  export declare const addOverlay: (optimistic: OptimisticState, overlay: ConnectionOverlay) => OptimisticState;
595
619
  export declare const removeOverlay: (optimistic: OptimisticState, id: string) => OptimisticState;
596
- /** Base store with every layer applied in order. Later layers win. */
620
+ /**
621
+ * Base store with every layer applied in order. Later layers win. A patch is
622
+ * not news from the server, so it keeps the date of the value under it; an
623
+ * entity only a request holds (a temporary id) is not the server's to age, and
624
+ * is dated `Infinity`, so freshness never plans or times it.
625
+ */
597
626
  export declare const visibleStore: (base: EntityStore, optimistic: OptimisticState) => EntityStore;
598
627
  /**
599
628
  * A fresh page is newer than any settled overlay it covers: an edge the page
@@ -607,10 +636,10 @@ export declare const pruneOverlays: (optimistic: OptimisticState, connection: st
607
636
  * a later layer re-wins on rebase. Confirmed connection changes are recorded
608
637
  * once per request, as overlays the request no longer owns.
609
638
  */
610
- export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>, deleted?: ReadonlyArray<{
611
- readonly entity: string;
612
- readonly id: string;
613
- }>) => {
639
+ export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, answer: MutationAnswer & {
640
+ /** Connection changes the server confirmed; they replace the request's own. */
641
+ readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
642
+ }) => {
614
643
  readonly store: EntityStore;
615
644
  readonly state: MutationState;
616
645
  readonly optimistic: OptimisticState;
@@ -675,11 +704,6 @@ export type LiveOutcome = 'applied' | 'duplicate' | 'gap';
675
704
  * spurious gap.
676
705
  */
677
706
  export declare const classifyLive: (state: LiveState, cursor: LiveCursor) => LiveOutcome;
678
- /**
679
- * A subscriber is woken only if the event changed a field it selects. A
680
- * change to an unselected field is skipped entirely.
681
- */
682
- export declare const shouldWake: (changed: ReadonlyArray<string>, selected: ReadonlyArray<string>) => boolean;
683
707
  export interface EntityApplied {
684
708
  readonly state: LiveState;
685
709
  readonly store: EntityStore;
@@ -740,7 +764,7 @@ export declare const gc: (state: Retained & {
740
764
  //#endregion
741
765
  //#region src/persistence.d.ts
742
766
  /** Bump when the serialized shape changes; a mismatch discards the cache. */
743
- export declare const REMOTE_CACHE_VERSION = 4;
767
+ export declare const REMOTE_CACHE_VERSION = 5;
744
768
  /**
745
769
  * What survives a reload: the entity cache, and the connections an application
746
770
  * **declared** should come back.
@@ -832,7 +856,7 @@ export declare const RemotePersistence: {
832
856
  * server refuses a mismatch with `RemoteProtocolError`, so a shape change never
833
857
  * drifts silently: bump it whenever `ReadRequest` or `LiveRequirement` change.
834
858
  */
835
- export declare const REMOTE_PROTOCOL_VERSION = 3;
859
+ export declare const REMOTE_PROTOCOL_VERSION = 4;
836
860
  declare const RemoteReadError_base: Schema.Class<RemoteReadError, Schema.TaggedStruct<"RemoteReadError", {
837
861
  readonly message: Schema.String;
838
862
  }>, import("effect/Cause").YieldableError>;
@@ -875,12 +899,27 @@ export declare const NormalizedEntity: Schema.Struct<{
875
899
  readonly id: Schema.String;
876
900
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
877
901
  }>;
902
+ /**
903
+ * Fields a read asked for that the server answered without, and will not
904
+ * answer with: the client stops asking. It says nothing about why, so a rule
905
+ * that withholds a field is not itself on the wire.
906
+ */
907
+ export declare const SettledFields: Schema.Struct<{
908
+ readonly entity: Schema.String;
909
+ readonly id: Schema.String;
910
+ readonly fields: Schema.$Array<Schema.String>;
911
+ }>;
878
912
  export declare const ReadBatchResult: Schema.Struct<{
879
913
  readonly entities: Schema.$Array<Schema.Struct<{
880
914
  readonly entity: Schema.String;
881
915
  readonly id: Schema.String;
882
916
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
883
917
  }>>;
918
+ readonly settled: Schema.$Array<Schema.Struct<{
919
+ readonly entity: Schema.String;
920
+ readonly id: Schema.String;
921
+ readonly fields: Schema.$Array<Schema.String>;
922
+ }>>;
884
923
  }>;
885
924
  export declare const MutationRequest: Schema.Struct<{
886
925
  /** Stable across transport retries so a mutation is not applied twice. */
@@ -999,6 +1038,11 @@ export declare const Read: Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
999
1038
  readonly id: Schema.String;
1000
1039
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1001
1040
  }>>;
1041
+ readonly settled: Schema.$Array<Schema.Struct<{
1042
+ readonly entity: Schema.String;
1043
+ readonly id: Schema.String;
1044
+ readonly fields: Schema.$Array<Schema.String>;
1045
+ }>>;
1002
1046
  }>, Schema.Union<readonly [typeof RemoteReadError, typeof RemoteProtocolError]>, never, never>;
1003
1047
  export declare const Mutate: Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
1004
1048
  /** Stable across transport retries so a mutation is not applied twice. */
@@ -1099,6 +1143,12 @@ export declare const QueryRequest: Schema.Struct<{
1099
1143
  readonly after: Schema.optional<Schema.String>;
1100
1144
  readonly before: Schema.optional<Schema.String>;
1101
1145
  }>;
1146
+ /**
1147
+ * What to read of each item, as the relation slice a read asks the server
1148
+ * for. Absent for a query run without one: the response carries only edges,
1149
+ * and the client's read entry fetches fields in a second round trip.
1150
+ */
1151
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1102
1152
  }>;
1103
1153
  export declare const QueryEdge: Schema.Struct<{
1104
1154
  readonly entity: Schema.String;
@@ -1127,6 +1177,21 @@ export declare const QueryResult: Schema.Struct<{
1127
1177
  }>, Schema.Struct<{
1128
1178
  readonly _tag: Schema.Literal<"Unknown">;
1129
1179
  }>]>;
1180
+ /**
1181
+ * The selected fields of the page's items, in the same shape a read batch
1182
+ * returns. Absent from a server that predates payload planning: the client
1183
+ * reads it as empty and fetches fields as before.
1184
+ */
1185
+ readonly entities: Schema.optional<Schema.$Array<Schema.Struct<{
1186
+ readonly entity: Schema.String;
1187
+ readonly id: Schema.String;
1188
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1189
+ }>>>;
1190
+ readonly settled: Schema.optional<Schema.$Array<Schema.Struct<{
1191
+ readonly entity: Schema.String;
1192
+ readonly id: Schema.String;
1193
+ readonly fields: Schema.$Array<Schema.String>;
1194
+ }>>>;
1130
1195
  }>;
1131
1196
  export declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
1132
1197
  readonly query: Schema.String;
@@ -1137,6 +1202,12 @@ export declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
1137
1202
  readonly after: Schema.optional<Schema.String>;
1138
1203
  readonly before: Schema.optional<Schema.String>;
1139
1204
  }>;
1205
+ /**
1206
+ * What to read of each item, as the relation slice a read asks the server
1207
+ * for. Absent for a query run without one: the response carries only edges,
1208
+ * and the client's read entry fetches fields in a second round trip.
1209
+ */
1210
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1140
1211
  }>, Schema.Struct<{
1141
1212
  readonly edges: Schema.$Array<Schema.Struct<{
1142
1213
  readonly entity: Schema.String;
@@ -1159,6 +1230,21 @@ export declare const QueryRpc: Rpc.Rpc<"FoldkitRemoteQuery", Schema.Struct<{
1159
1230
  }>, Schema.Struct<{
1160
1231
  readonly _tag: Schema.Literal<"Unknown">;
1161
1232
  }>]>;
1233
+ /**
1234
+ * The selected fields of the page's items, in the same shape a read batch
1235
+ * returns. Absent from a server that predates payload planning: the client
1236
+ * reads it as empty and fetches fields as before.
1237
+ */
1238
+ readonly entities: Schema.optional<Schema.$Array<Schema.Struct<{
1239
+ readonly entity: Schema.String;
1240
+ readonly id: Schema.String;
1241
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1242
+ }>>>;
1243
+ readonly settled: Schema.optional<Schema.$Array<Schema.Struct<{
1244
+ readonly entity: Schema.String;
1245
+ readonly id: Schema.String;
1246
+ readonly fields: Schema.$Array<Schema.String>;
1247
+ }>>>;
1162
1248
  }>, typeof RemoteQueryError, never, never>;
1163
1249
  export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", Schema.Struct<{
1164
1250
  readonly version: Schema.Number;
@@ -1169,6 +1255,11 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
1169
1255
  readonly id: Schema.String;
1170
1256
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1171
1257
  }>>;
1258
+ readonly settled: Schema.$Array<Schema.Struct<{
1259
+ readonly entity: Schema.String;
1260
+ readonly id: Schema.String;
1261
+ readonly fields: Schema.$Array<Schema.String>;
1262
+ }>>;
1172
1263
  }>, Schema.Union<readonly [typeof RemoteReadError, typeof RemoteProtocolError]>, never, never> | Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
1173
1264
  /** Stable across transport retries so a mutation is not applied twice. */
1174
1265
  readonly requestId: Schema.String;
@@ -1254,6 +1345,12 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
1254
1345
  readonly after: Schema.optional<Schema.String>;
1255
1346
  readonly before: Schema.optional<Schema.String>;
1256
1347
  }>;
1348
+ /**
1349
+ * What to read of each item, as the relation slice a read asks the server
1350
+ * for. Absent for a query run without one: the response carries only edges,
1351
+ * and the client's read entry fetches fields in a second round trip.
1352
+ */
1353
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1257
1354
  }>, Schema.Struct<{
1258
1355
  readonly edges: Schema.$Array<Schema.Struct<{
1259
1356
  readonly entity: Schema.String;
@@ -1276,6 +1373,21 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
1276
1373
  }>, Schema.Struct<{
1277
1374
  readonly _tag: Schema.Literal<"Unknown">;
1278
1375
  }>]>;
1376
+ /**
1377
+ * The selected fields of the page's items, in the same shape a read batch
1378
+ * returns. Absent from a server that predates payload planning: the client
1379
+ * reads it as empty and fetches fields as before.
1380
+ */
1381
+ readonly entities: Schema.optional<Schema.$Array<Schema.Struct<{
1382
+ readonly entity: Schema.String;
1383
+ readonly id: Schema.String;
1384
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1385
+ }>>>;
1386
+ readonly settled: Schema.optional<Schema.$Array<Schema.Struct<{
1387
+ readonly entity: Schema.String;
1388
+ readonly id: Schema.String;
1389
+ readonly fields: Schema.$Array<Schema.String>;
1390
+ }>>>;
1279
1391
  }>, typeof RemoteQueryError, never, never>>;
1280
1392
  //#endregion
1281
1393
  //#region src/model.d.ts
@@ -1288,6 +1400,12 @@ export interface RemoteModel {
1288
1400
  readonly entities: EntityStore;
1289
1401
  /** Normalized ordered connections, keyed by connection identity. */
1290
1402
  readonly connections: Readonly<Record<string, Connection>>;
1403
+ /**
1404
+ * How many rows `Data.more` has grown a read's window to, by
1405
+ * `windowGrowthKey`. A read shows at most its window, so this is what "load
1406
+ * more" changes; it lives here because a list holds no state of its own.
1407
+ */
1408
+ readonly grown: Readonly<Record<string, number>>;
1291
1409
  /** Optimistic entity layers and connection overlays over the base store. */
1292
1410
  readonly optimistic: OptimisticState;
1293
1411
  /** Live cursor and boundary state, keyed by the subscription's stream key. */
@@ -1348,8 +1466,22 @@ export interface RefreshState {
1348
1466
  readonly generation: number;
1349
1467
  readonly requested: ReadonlyMap<string, number>;
1350
1468
  readonly started: ReadonlyMap<string, number>;
1469
+ /**
1470
+ * The generation every entry is refreshed at, at least: `forgetRemote` moves
1471
+ * it, so every read and live entry restarts, and a read or stream begun for
1472
+ * the principal before is interrupted rather than landing after.
1473
+ */
1474
+ readonly floor: number;
1351
1475
  }
1352
1476
  export declare const emptyRefresh: RefreshState;
1477
+ /**
1478
+ * The Model with everything the server told it forgotten: values, tombstones,
1479
+ * unavailable fields, connections, live cursors, failures, and what is in
1480
+ * flight. For a change of principal, whose facts these were. The mutation
1481
+ * sequence is kept, so request ids stay unique, and a mutation in flight is
1482
+ * treated as applied: its answer, when it comes, writes nothing here.
1483
+ */
1484
+ export declare const forgetRemote: (model: RemoteModel) => RemoteModel;
1353
1485
  export declare const initialRemoteModel: RemoteModel;
1354
1486
  export declare const remoteModelSchema: () => Schema.Codec<RemoteModel, unknown>;
1355
1487
  /** The submodel's Messages; each reduces to `RemoteModel` through `updateRemote`. */
@@ -1425,6 +1557,8 @@ export type RemoteMessage = {
1425
1557
  readonly entity: string;
1426
1558
  readonly id: string;
1427
1559
  }> | undefined;
1560
+ /** Injected clock reading of the answer: how fresh the written entities are. */
1561
+ readonly now: number;
1428
1562
  } | {
1429
1563
  readonly _tag: 'MutationFailed';
1430
1564
  readonly requestId: string;
@@ -1442,6 +1576,12 @@ export type RemoteMessage = {
1442
1576
  } | {
1443
1577
  readonly _tag: 'OverlayLifted';
1444
1578
  readonly id: string;
1579
+ } |
1580
+ /** `Data.more`: a read's window, by `windowGrowthKey`, now shows `size` rows. */
1581
+ {
1582
+ readonly _tag: 'WindowGrown';
1583
+ readonly window: string;
1584
+ readonly size: number;
1445
1585
  } | {
1446
1586
  readonly _tag: 'LiveReceived';
1447
1587
  readonly stream: string;
@@ -1457,6 +1597,26 @@ export type RemoteMessage = {
1457
1597
  readonly page: Segment;
1458
1598
  /** The page answers the connection's refresh, so the merge also clears `stale`. */
1459
1599
  readonly refreshes?: boolean | undefined;
1600
+ /**
1601
+ * The slice the query asked for, so the payload's entities write like a
1602
+ * read: one request per matching edge. Absent for a page from a server
1603
+ * that predates payload planning, which carries edges only.
1604
+ */
1605
+ readonly select?: RelationRequirement | undefined;
1606
+ /** The selected fields of the page's items, as a read batch returns them. */
1607
+ readonly entities?: ReadonlyArray<{
1608
+ readonly entity: string;
1609
+ readonly id: string;
1610
+ readonly values: Record<string, unknown>;
1611
+ }> | undefined;
1612
+ /** Fields asked for that the server settled without a value. */
1613
+ readonly settled?: ReadonlyArray<{
1614
+ readonly entity: string;
1615
+ readonly id: string;
1616
+ readonly fields: ReadonlyArray<string>;
1617
+ }> | undefined;
1618
+ /** Injected clock reading of the answer, dating what the payload writes. */
1619
+ readonly now?: number | undefined;
1460
1620
  } | {
1461
1621
  readonly _tag: 'ConnectionInvalidated';
1462
1622
  readonly connection: string;
@@ -1494,6 +1654,11 @@ export declare const remoteMessageCases: {
1494
1654
  readonly id: Schema.String;
1495
1655
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1496
1656
  }>>;
1657
+ readonly settled: Schema.$Array<Schema.Struct<{
1658
+ readonly entity: Schema.String;
1659
+ readonly id: Schema.String;
1660
+ readonly fields: Schema.$Array<Schema.String>;
1661
+ }>>;
1497
1662
  }>;
1498
1663
  now: Schema.Number;
1499
1664
  };
@@ -1545,6 +1710,7 @@ export declare const remoteMessageCases: {
1545
1710
  readonly entity: Schema.String;
1546
1711
  readonly id: Schema.String;
1547
1712
  }>>>;
1713
+ now: Schema.Number;
1548
1714
  };
1549
1715
  MutationFailed: {
1550
1716
  requestId: Schema.String;
@@ -1560,6 +1726,10 @@ export declare const remoteMessageCases: {
1560
1726
  OverlayLifted: {
1561
1727
  id: Schema.String;
1562
1728
  };
1729
+ WindowGrown: {
1730
+ window: Schema.String;
1731
+ size: Schema.Number;
1732
+ };
1563
1733
  LiveReceived: {
1564
1734
  stream: Schema.String;
1565
1735
  event: Schema.Unknown;
@@ -1573,6 +1743,18 @@ export declare const remoteMessageCases: {
1573
1743
  connection: Schema.String;
1574
1744
  page: Schema.Unknown;
1575
1745
  refreshes: Schema.optional<Schema.Boolean>;
1746
+ select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
1747
+ entities: Schema.optional<Schema.$Array<Schema.Struct<{
1748
+ readonly entity: Schema.String;
1749
+ readonly id: Schema.String;
1750
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1751
+ }>>>;
1752
+ settled: Schema.optional<Schema.$Array<Schema.Struct<{
1753
+ readonly entity: Schema.String;
1754
+ readonly id: Schema.String;
1755
+ readonly fields: Schema.$Array<Schema.String>;
1756
+ }>>>;
1757
+ now: Schema.optional<Schema.Number>;
1576
1758
  };
1577
1759
  ConnectionInvalidated: {
1578
1760
  connection: Schema.String;
@@ -1607,6 +1789,14 @@ export declare const isRemoteMessage: <M extends {
1607
1789
  readonly _tag: RemoteMessageTag;
1608
1790
  }>;
1609
1791
  export declare const remoteMessageSchema: Schema.Schema<RemoteMessage>;
1792
+ /** The key a grown window is kept under: its connection and the window first asked for. */
1793
+ export declare const windowGrowthKey: (identity: string, window: string) => string;
1794
+ /**
1795
+ * Whether only overlays show this entity: the server has told the store
1796
+ * nothing of it and no request's layer writes it, so nothing will fetch what an
1797
+ * overlay leaves out.
1798
+ */
1799
+ export declare const onlyOverlaid: (model: RemoteModel, entity: string, id: string) => boolean;
1610
1800
  /** Whether a query for this connection is in flight. */
1611
1801
  export declare const isQueryLoading: (model: RemoteModel, identity: string) => boolean;
1612
1802
  /**
@@ -1637,7 +1827,12 @@ export declare const isLoading: (model: RemoteModel, entity: string, id: string,
1637
1827
  /**
1638
1828
  * The pure reducer all four producers share. A live event that arrives ahead of
1639
1829
  * its cursor is a gap: it is not applied, and the stream is recorded so the host
1640
- * can resubscribe rather than silently miss facts.
1830
+ * can resubscribe rather than silently miss facts. When every field a Message
1831
+ * touches keeps its identity, `model` itself is returned, so the application's
1832
+ * root keeps its identity and Foldkit does not render. The common no-ops do (a
1833
+ * duplicate live event, a repeated `ReadStarted`); a repeated failure, or a
1834
+ * `preserve-existing` restore of entities already held, still makes an equal
1835
+ * copy.
1641
1836
  */
1642
1837
  export declare const updateRemote: (model: RemoteModel, message: RemoteMessage) => RemoteModel;
1643
1838
  /** Whether this field's last read failed and nothing has settled it since. */
@@ -1664,6 +1859,23 @@ export declare const failureOf: (model: RemoteModel, entity: string, id: string,
1664
1859
  */
1665
1860
  export declare const writeRead: (store: EntityStore, requests: ReadonlyArray<Requirement>, result: Schema.Schema.Type<typeof ReadBatchResult>, now?: number) => EntityStore;
1666
1861
  //#endregion
1862
+ //#region src/resume.d.ts
1863
+ /**
1864
+ * A resume part, in the shape `foldkit-ssr`'s `SSR.plan` takes in `parts`.
1865
+ * Declared here structurally, so neither package depends on the other.
1866
+ */
1867
+ interface RemoteResumePart<AppModel> {
1868
+ readonly id: string;
1869
+ /** The metadata key names whose reads this part resumes. */
1870
+ readonly covers: ReadonlyArray<string>;
1871
+ readonly capture: (model: AppModel, projections: ReadonlyArray<{
1872
+ readonly metadata: Metadata;
1873
+ }>) => unknown;
1874
+ readonly restore: (model: AppModel, value: unknown) => Result.Result<AppModel, string>;
1875
+ /** Whether a Subscription entry is one of this domain's, which may start late. */
1876
+ readonly deferrable: (key: string, entry: unknown) => boolean;
1877
+ }
1878
+ //#endregion
1667
1879
  //#region src/coalesce.d.ts
1668
1880
  type Batch = Schema.Schema.Type<typeof ReadBatch>;
1669
1881
  type BatchResult = Schema.Schema.Type<typeof ReadBatchResult>;
@@ -1882,6 +2094,12 @@ interface Assembled {
1882
2094
  * list), so the Selection's codec decides whether that is a failure.
1883
2095
  */
1884
2096
  export declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement) => Assembled | undefined;
2097
+ /**
2098
+ * The first field `requirement` reads, at any depth, that the server settled
2099
+ * without a value, as `Entity:id.field`. A read that consults it says why it
2100
+ * cannot assemble rather than waiting on a field nothing will fetch.
2101
+ */
2102
+ export declare const unavailableOf: (store: EntityStore, key: string, requirement: RelationRequirement) => string | undefined;
1885
2103
  //#endregion
1886
2104
  //#region src/entity.d.ts
1887
2105
  export type AnySchema = Schema.Schema<unknown>;
@@ -2078,6 +2296,7 @@ export interface RemoteInspection {
2078
2296
  readonly key: string;
2079
2297
  readonly present: ReadonlyArray<string>;
2080
2298
  readonly stale: ReadonlyArray<string>;
2299
+ readonly unavailable: ReadonlyArray<string>;
2081
2300
  readonly tombstone: boolean;
2082
2301
  readonly updatedAt: number;
2083
2302
  readonly windows: Readonly<Record<string, string>>;
@@ -2215,6 +2434,23 @@ export interface PlanOptions {
2215
2434
  /** Plan every requested field, present or not, tombstoned or not. */
2216
2435
  readonly force?: boolean | undefined;
2217
2436
  }
2437
+ /** When present values next go stale, and the requirements of the entities that do. */
2438
+ export interface Deadline {
2439
+ readonly at: number;
2440
+ readonly due: ReadonlyArray<Requirement>;
2441
+ }
2442
+ /**
2443
+ * The earliest moment a value `requirements` read, following the relations the
2444
+ * store holds as `plan` does, goes stale under `freshness`, with the
2445
+ * requirements of the entities that go stale then. A field the server settled
2446
+ * without a value ages with its entity too, since `plan` asks for it again once
2447
+ * the entity expires. Nothing when no such field is still fresh: what is
2448
+ * already expired or stale is planned, not awaited, which is what keeps a
2449
+ * timer from firing on what it already fired on. It is the next moment the
2450
+ * plan can change with the clock alone, which the read entry relies on to
2451
+ * reuse its plan until then.
2452
+ */
2453
+ export declare const deadlineOf: (store: EntityStore, requirements: readonly Requirement[], freshness: PlanFreshness) => Deadline | undefined;
2218
2454
  export declare const plan: (store: EntityStore, requirements: readonly Requirement[], options?: PlanOptions) => ReadonlyArray<Requirement>;
2219
2455
  //#endregion
2220
2456
  //#region src/policy.d.ts
@@ -2323,6 +2559,8 @@ export interface DomainMutateOptions {
2323
2559
  readonly requestId: string;
2324
2560
  readonly tempId: string;
2325
2561
  }) => ReadonlyArray<OptimisticOperation>) | undefined;
2562
+ /** The clock `MutationSucceeded` stamps the answer with; default `Date.now`, read at each use. */
2563
+ readonly now?: (() => number) | undefined;
2326
2564
  }
2327
2565
  /** A Foldkit Subscription entry of the Remote domain, emitting its Messages through `RemoteClient`. */
2328
2566
  export type RemoteEntry<AppModel, Dependencies> = EntryWithoutKeepAlive<AppModel, RemoteMessage, Dependencies, RemoteClient>;
@@ -2331,9 +2569,15 @@ export type RemoteEntry<AppModel, Dependencies> = EntryWithoutKeepAlive<AppModel
2331
2569
  * and a live entry per key (the live one idles when nothing is read live), and
2332
2570
  * `retain`.
2333
2571
  */
2334
- export type SubscriptionEntries<AppModel, Active> = { readonly [K in keyof Active & (string | number) as `${K}.read` | `${K}.live`]: RemoteEntry<AppModel, any>; } & {
2335
- readonly retain: RemoteEntry<AppModel, any>;
2572
+ export type SubscriptionEntries<AppModel, Active, Message = RemoteMessage> = { readonly [K in keyof Active & (string | number) as `${K}.read`]: EntryWithoutKeepAlive<AppModel, Message, ReadDependencies, RemoteClient>; } & { readonly [K in keyof Active & (string | number) as `${K}.live`]: EntryWithoutKeepAlive<AppModel, Message, LiveDependencies, RemoteClient>; } & {
2573
+ readonly retain: EntryWithoutKeepAlive<AppModel, Message, RetentionRoots, never>;
2336
2574
  };
2575
+ /** The dependencies of a live entry: what it subscribes to, and where a restart resumes. */
2576
+ export interface LiveDependencies {
2577
+ readonly requirements: ReadonlyArray<Requirement>;
2578
+ readonly cursor: LiveCursor;
2579
+ readonly floor: number;
2580
+ }
2337
2581
  export interface SubscriptionsOptions extends ObserveOptions, LiveOptions, RetainOptions {}
2338
2582
  /** 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. */
2339
2583
  export type RemoteWiring<AppModel> = Wiring<AppModel, RemoteMessage | RemoteMessageInput, RemoteClient>;
@@ -2368,10 +2612,13 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
2368
2612
  * onto the connection read through the same projection.
2369
2613
  */
2370
2614
  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>>;
2371
- /** The `QueryRef` for the page after the loaded end (same page size), or `undefined` when there is none or its cursor is unknown. */
2372
- next<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
2373
- /** The `QueryRef` for the page before the loaded start, or `undefined`. */
2374
- previous<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
2615
+ /**
2616
+ * "Load more": the Model with the read's window grown by one page, so it
2617
+ * shows that many more rows; the read entry fetches what the connection
2618
+ * lacks. None when the read shows everything there is (or is not a sized
2619
+ * window). Called from `update`.
2620
+ */
2621
+ more<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): Option.Option<AppModel>;
2375
2622
  /**
2376
2623
  * What a query read is and what it currently is, as one serializable value —
2377
2624
  * data-query-DESIGN §29.1: the domain, the definition and its input, the
@@ -2422,30 +2669,44 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
2422
2669
  * fetch. The server stays authoritative for which rows exist.
2423
2670
  */
2424
2671
  filtered<Value, Name extends string, Input, Q extends QueryDescriptor<any, any, any>>(model: AppModel, over: QueryProjection<AppModel, Value, Name, Input>, by: Q & Registered<Q['name'], QueryName<Queries[number]>, 'Query'>, input: QueryInput<Q>): Matched<Value>;
2425
- /** A Command that runs the query and yields the `ConnectionMerged` (or `QueryFailed`) that reduces it: "load more". */
2426
- fetch(ref: QueryRef<string, unknown>): Command<RemoteMessage, never, RemoteClient>;
2427
2672
  /**
2428
2673
  * Shows operations over the store with no request behind them, as a mutation's
2429
2674
  * `optimistic` ones show while it is in flight: every Selection and view draws
2430
2675
  * them. For a preview of a change nobody has made. They stay until `lift`;
2431
- * showing an id again replaces what it showed. Called from `update`.
2676
+ * showing an id again replaces what it showed. Called from `update`. A read
2677
+ * of an entity only overlays show, lacking a field it selects, is `Failed`
2678
+ * (`Overlaid`): nothing will fetch that field.
2432
2679
  */
2433
2680
  overlay(model: AppModel, id: string, optimistic: ReadonlyArray<OptimisticOperation>): AppModel;
2434
2681
  /** Lifts what `overlay` showed under this id. Lifting nothing returns the same Model. */
2435
2682
  lift(model: AppModel, id: string): AppModel;
2436
2683
  /** `Remote.refresh`: marks what a projection or a Surface requires as due, for its read entry to refetch. */
2437
2684
  refresh(model: AppModel, target: Projection<AppModel, unknown> | Surface<AppModel, any, any, void>): AppModel;
2685
+ /** `Remote.forget`: the Model with every server-derived fact gone, for a change of principal. */
2686
+ forget(model: AppModel): AppModel;
2687
+ /**
2688
+ * A read of this domain as an active Surface, for `subscriptions` and
2689
+ * `wiring`: `projectionOf` is what it reads for a Model, none while it
2690
+ * reads nothing. It belongs to the domain's application, and lists no
2691
+ * Messages: it is a requirement, not a sender. A domain made from a raw
2692
+ * optic names no application, so this throws for one.
2693
+ */
2694
+ active<Value>(name: string, projectionOf: (model: AppModel) => Option.Option<Projection<AppModel, Value>>): ActiveSurface<AppModel>;
2438
2695
  /**
2439
2696
  * The Foldkit Subscription entries for the active Surfaces, keyed for
2440
2697
  * `Subscription.make`: a read entry per Surface (`Remote.observe`), a live
2441
2698
  * entry per Surface that reads through `live` (`Remote.live`), and one
2442
- * retain entry with every active Surface as a root (`Remote.retain`). A
2699
+ * retain entry (`Remote.retain`). Retention is the domain's: the retain
2700
+ * entry of every call roots the active Surfaces of every call, so reads
2701
+ * split over calls (one per policy) do not collect each other's data. A
2443
2702
  * Surface's params are a function of the Model (`Surface.at`), so what is
2444
2703
  * fetched, subscribed, and retained follows the Model.
2445
2704
  */
2446
2705
  subscriptions<const Active extends Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>>(active: Active, options?: SubscriptionsOptions): SubscriptionEntries<AppModel, Active>;
2447
2706
  /** `Remote.plan`: the requirements the store does not satisfy. */
2448
2707
  plan<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions): ReadonlyArray<Requirement>;
2708
+ /** `Remote.meta`: when what a projection shows was last received, and whether it is stale or loading. */
2709
+ meta<Value>(model: AppModel, projection: Projection<AppModel, Value>): ReadMeta;
2449
2710
  /** `Remote.storeOf`: the visible store, base under the pending optimistic layers. */
2450
2711
  storeOf(model: AppModel): EntityStore;
2451
2712
  /**
@@ -2478,6 +2739,17 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
2478
2739
  * items included). For SSR, route or hover prefetch, and tests.
2479
2740
  */
2480
2741
  prefetch<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: ObserveOptions): Effect.Effect<AppModel, RemoteReadError | RemoteProtocolError | RemoteQueryError, RemoteClient>;
2742
+ /**
2743
+ * The Model with everything the active Surfaces read, for a render that
2744
+ * fetches nothing (SSR, a prerender). Each pass prefetches every Surface
2745
+ * that plans a read, over the Model the one before it left, so a Surface
2746
+ * active only once another's read has arrived is read in the next pass (or
2747
+ * the same one, when it comes later in `active`). It stops at the first
2748
+ * pass that plans nothing, and fails with `RemoteUnsatisfied` when
2749
+ * `options.passes` run out first. Reads are cache-first: a field already
2750
+ * held is not asked again.
2751
+ */
2752
+ satisfy(model: AppModel, active: Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>, options?: SatisfyOptions): Effect.Effect<AppModel, RemoteReadError | RemoteProtocolError | RemoteQueryError | RemoteUnsatisfied, RemoteClient>;
2481
2753
  /**
2482
2754
  * Starts a registered mutation from `update`: applies `MutationStarted` (with
2483
2755
  * the optimistic operations) to the Model and returns the Command that runs
@@ -2503,6 +2775,28 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
2503
2775
  /** `Remote.inspect` of the bound slice. */
2504
2776
  inspect(model: AppModel): RemoteInspection;
2505
2777
  }
2778
+ /** What `Remote.fold(Data, …).mutate` starts: `Data.mutate`'s result with its Command lifted. */
2779
+ export type FoldedMutationStarted<AppModel, ParentMessage> = Omit<MutationStarted<AppModel>, 'command'> & {
2780
+ readonly command: Command<ParentMessage, never, RemoteClient>;
2781
+ };
2782
+ /**
2783
+ * A bound domain folded under one of the application's own Message variants,
2784
+ * from `Remote.fold`. Calling it reduces a Remote Message into the Model; the
2785
+ * members that produce Messages, `fetch`, `mutate`, and `subscriptions`,
2786
+ * yield the wrapper Message instead of `RemoteMessage`, with the lift recorded
2787
+ * so Story and Scene can resolve a fetch or a mutation by Remote's own answer.
2788
+ * Members that only read or write the Model (`get`, `refresh`, `next`,
2789
+ * `overlay`, and the rest) stay on the domain itself.
2790
+ */
2791
+ export interface RemoteFold<AppModel, ParentMessage, Domain extends RemoteDomain<AppModel, any, any, any, any>> {
2792
+ (model: AppModel, message: RemoteMessage | RemoteMessageInput): Update.Return<AppModel, ParentMessage>;
2793
+ /** `Data.mutate`, its Command lifted. */
2794
+ readonly mutate: (...args: Parameters<Domain['mutate']>) => FoldedMutationStarted<AppModel, ParentMessage>;
2795
+ /** `Data.subscriptions`, every entry lifted to the wrapper Message. */
2796
+ readonly subscriptions: <const Active extends Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>>(active: Active, options?: SubscriptionsOptions) => SubscriptionEntries<AppModel, Active, ParentMessage>;
2797
+ }
2798
+ /** The application Model a bound domain is over. */
2799
+ export type ModelOfDomain<Domain> = Domain extends RemoteDomain<infer AppModel, any, any, any, any> ? AppModel : never;
2506
2800
  /** A projection's connection requirement with the `QueryRef` that runs it. */
2507
2801
  export interface QueryRequirement extends ConnectionRequirement {
2508
2802
  readonly ref: QueryRef<string, unknown>;
@@ -2533,9 +2827,23 @@ export interface QueryProjection<AppModel, Value, Name extends string, Input> ex
2533
2827
  export type QueryInput<Q> = Q extends QueryDescriptor<any, infer Input, any> ? Input : never;
2534
2828
  /** The entity a query's connection is over. */
2535
2829
  export type QueryEntity<Q> = Q extends QueryDescriptor<any, any, ConnectionSpec<infer Entity>> ? Entity : string;
2830
+ /**
2831
+ * When what a projection shows was last received, and whether it is stale
2832
+ * or loading. See `Remote.meta`.
2833
+ */
2834
+ export interface ReadMeta {
2835
+ /** The newest server write among what is shown; none received reads `undefined`. */
2836
+ readonly updatedAt: number | undefined;
2837
+ /** Any shown field or connection is marked stale. */
2838
+ readonly stale: boolean;
2839
+ /** Any shown field or connection is in flight. */
2840
+ readonly loading: boolean;
2841
+ }
2536
2842
  export interface MutateOptions {
2537
2843
  /** What the request changes before the server answers; released when it settles. */
2538
2844
  readonly optimistic?: ReadonlyArray<OptimisticOperation> | undefined;
2845
+ /** The clock `MutationSucceeded` stamps the answer with; default `Date.now`, read at each use. */
2846
+ readonly now?: (() => number) | undefined;
2539
2847
  }
2540
2848
  export interface RetainOptions {
2541
2849
  /** The query connections the application shows, by `QueryRef` or identity. */
@@ -2547,11 +2855,29 @@ export interface RetainOptions {
2547
2855
  export interface ObserveOptions {
2548
2856
  /** Default `RemotePolicy.cacheFirst`. */
2549
2857
  readonly policy?: RemotePolicy | undefined;
2550
- /** The clock a refreshing policy reads; default `Date.now`. */
2858
+ /** The clock a refreshing policy reads; default `Date.now`, read at each use. */
2551
2859
  readonly now?: (() => number) | undefined;
2552
2860
  }
2861
+ /** How `Data.satisfy` reads: how many passes it may take, and the clock. */
2862
+ export interface SatisfyOptions {
2863
+ /** At most this many passes over the Surfaces; default 8. */
2864
+ readonly passes?: number | undefined;
2865
+ /** The clock the reads are stamped with; default `Date.now`, read at each use. */
2866
+ readonly now?: (() => number) | undefined;
2867
+ }
2868
+ declare const RemoteUnsatisfied_base: Schema.Class<RemoteUnsatisfied, Schema.TaggedStruct<"RemoteUnsatisfied", {
2869
+ readonly surfaces: Schema.$Array<Schema.String>;
2870
+ readonly passes: Schema.Number;
2871
+ }>, import("effect/Cause").YieldableError>;
2872
+ /**
2873
+ * `Data.satisfy` reached its bound with Surfaces still reading, such as a
2874
+ * chain whose every read reveals one more. It names them, so a page that
2875
+ * would have rendered them loading fails instead. (A read the server leaves
2876
+ * unanswered settles as missing and ends the loop.)
2877
+ */
2878
+ export declare class RemoteUnsatisfied extends RemoteUnsatisfied_base {}
2553
2879
  export interface LiveOptions {
2554
- /** The clock `LiveReceived` stamps events with; default `Date.now`. */
2880
+ /** The clock `LiveReceived` stamps events with; default `Date.now`, read at each use. */
2555
2881
  readonly now?: (() => number) | undefined;
2556
2882
  }
2557
2883
  /** A query the read entry runs, as its dependencies carry it: plain data Foldkit compares. */
@@ -2575,6 +2901,14 @@ export interface ReadDependencies {
2575
2901
  * leaves it running.
2576
2902
  */
2577
2903
  readonly refresh: number;
2904
+ /**
2905
+ * Under a refreshing policy, when a value the entry holds next ages out and
2906
+ * what is due then. Time reaches Remote only as a Message: the entry sleeps
2907
+ * until then and emits `RefreshStarted`, which marks the fields stale, and
2908
+ * the plan that follows fetches them. A Model that does not change past its
2909
+ * `maxAge` is otherwise never looked at again.
2910
+ */
2911
+ readonly expires: Deadline | null;
2578
2912
  }
2579
2913
  export declare const Remote: {
2580
2914
  /** The submodel's schema, the same for every domain; embed it in the application Model. */
@@ -2595,6 +2929,11 @@ export declare const Remote: {
2595
2929
  readonly id: Schema.String;
2596
2930
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
2597
2931
  }>>;
2932
+ readonly settled: Schema.$Array<Schema.Struct<{
2933
+ readonly entity: Schema.String;
2934
+ readonly id: Schema.String;
2935
+ readonly fields: Schema.$Array<Schema.String>;
2936
+ }>>;
2598
2937
  }>;
2599
2938
  now: Schema.Number;
2600
2939
  };
@@ -2646,6 +2985,7 @@ export declare const Remote: {
2646
2985
  readonly entity: Schema.String;
2647
2986
  readonly id: Schema.String;
2648
2987
  }>>>;
2988
+ now: Schema.Number;
2649
2989
  };
2650
2990
  MutationFailed: {
2651
2991
  requestId: Schema.String;
@@ -2661,6 +3001,10 @@ export declare const Remote: {
2661
3001
  OverlayLifted: {
2662
3002
  id: Schema.String;
2663
3003
  };
3004
+ WindowGrown: {
3005
+ window: Schema.String;
3006
+ size: Schema.Number;
3007
+ };
2664
3008
  LiveReceived: {
2665
3009
  stream: Schema.String;
2666
3010
  event: Schema.Unknown;
@@ -2674,6 +3018,18 @@ export declare const Remote: {
2674
3018
  connection: Schema.String;
2675
3019
  page: Schema.Unknown;
2676
3020
  refreshes: Schema.optional<Schema.Boolean>;
3021
+ select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
3022
+ entities: Schema.optional<Schema.$Array<Schema.Struct<{
3023
+ readonly entity: Schema.String;
3024
+ readonly id: Schema.String;
3025
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
3026
+ }>>>;
3027
+ settled: Schema.optional<Schema.$Array<Schema.Struct<{
3028
+ readonly entity: Schema.String;
3029
+ readonly id: Schema.String;
3030
+ readonly fields: Schema.$Array<Schema.String>;
3031
+ }>>>;
3032
+ now: Schema.optional<Schema.Number>;
2677
3033
  };
2678
3034
  ConnectionInvalidated: {
2679
3035
  connection: Schema.String;
@@ -2695,6 +3051,160 @@ export declare const Remote: {
2695
3051
  }>(message: M) => message is Extract<M, {
2696
3052
  readonly _tag: RemoteMessageTag;
2697
3053
  }>;
3054
+ /**
3055
+ * Remote's Messages as one Schema, for a wrapper variant in the
3056
+ * application's union: `GotRemoteMessage: { message: Remote.Message }`. With
3057
+ * a wrapper, `update` matches the application's union exhaustively and
3058
+ * `Remote.fold` reduces what arrives inside it.
3059
+ */
3060
+ Message: import("foldkit/message").MessageUnion<{
3061
+ ReadReceived: {
3062
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
3063
+ result: Schema.Struct<{
3064
+ readonly entities: Schema.$Array<Schema.Struct<{
3065
+ readonly entity: Schema.String;
3066
+ readonly id: Schema.String;
3067
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
3068
+ }>>;
3069
+ readonly settled: Schema.$Array<Schema.Struct<{
3070
+ readonly entity: Schema.String;
3071
+ readonly id: Schema.String;
3072
+ readonly fields: Schema.$Array<Schema.String>;
3073
+ }>>;
3074
+ }>;
3075
+ now: Schema.Number;
3076
+ };
3077
+ ReadFailed: {
3078
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
3079
+ error: Schema.Struct<{
3080
+ readonly _tag: Schema.String;
3081
+ readonly message: Schema.String;
3082
+ }>;
3083
+ stream: Schema.optional<Schema.String>;
3084
+ };
3085
+ RefreshStarted: {
3086
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
3087
+ };
3088
+ ReadStarted: {
3089
+ requests: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
3090
+ refresh: Schema.optional<Schema.Number>;
3091
+ };
3092
+ QueryStarted: {
3093
+ connections: Schema.$Array<Schema.String>;
3094
+ };
3095
+ RetentionChanged: {
3096
+ roots: Schema.Struct<{
3097
+ readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
3098
+ readonly connections: Schema.$Array<Schema.Struct<{
3099
+ readonly identity: Schema.String;
3100
+ readonly select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
3101
+ }>>;
3102
+ }>;
3103
+ };
3104
+ Hydrated: {
3105
+ connections: Schema.optional<Schema.Unknown>;
3106
+ entities: Schema.Unknown;
3107
+ merge: Schema.Union<readonly [Schema.Literal<"replace">, Schema.Literal<"preserve-existing">]>;
3108
+ };
3109
+ MutationStarted: {
3110
+ requestId: Schema.String;
3111
+ optimistic: Schema.optional<Schema.$Array<Schema.Unknown>>;
3112
+ };
3113
+ MutationSucceeded: {
3114
+ requestId: Schema.String;
3115
+ entities: Schema.$Array<Schema.Struct<{
3116
+ readonly entity: Schema.String;
3117
+ readonly id: Schema.String;
3118
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
3119
+ }>>;
3120
+ connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
3121
+ deleted: Schema.optional<Schema.$Array<Schema.Struct<{
3122
+ readonly entity: Schema.String;
3123
+ readonly id: Schema.String;
3124
+ }>>>;
3125
+ now: Schema.Number;
3126
+ };
3127
+ MutationFailed: {
3128
+ requestId: Schema.String;
3129
+ error: Schema.Struct<{
3130
+ readonly _tag: Schema.String;
3131
+ readonly message: Schema.String;
3132
+ }>;
3133
+ };
3134
+ OverlayShown: {
3135
+ id: Schema.String;
3136
+ optimistic: Schema.$Array<Schema.Unknown>;
3137
+ };
3138
+ OverlayLifted: {
3139
+ id: Schema.String;
3140
+ };
3141
+ WindowGrown: {
3142
+ window: Schema.String;
3143
+ size: Schema.Number;
3144
+ };
3145
+ LiveReceived: {
3146
+ stream: Schema.String;
3147
+ event: Schema.Unknown;
3148
+ policy: Schema.optional<Schema.Unknown>;
3149
+ now: Schema.Number;
3150
+ };
3151
+ GapCleared: {
3152
+ stream: Schema.String;
3153
+ };
3154
+ ConnectionMerged: {
3155
+ connection: Schema.String;
3156
+ page: Schema.Unknown;
3157
+ refreshes: Schema.optional<Schema.Boolean>;
3158
+ select: Schema.optional<Schema.Codec<RelationRequirement, RelationRequirement, never, never>>;
3159
+ entities: Schema.optional<Schema.$Array<Schema.Struct<{
3160
+ readonly entity: Schema.String;
3161
+ readonly id: Schema.String;
3162
+ readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
3163
+ }>>>;
3164
+ settled: Schema.optional<Schema.$Array<Schema.Struct<{
3165
+ readonly entity: Schema.String;
3166
+ readonly id: Schema.String;
3167
+ readonly fields: Schema.$Array<Schema.String>;
3168
+ }>>>;
3169
+ now: Schema.optional<Schema.Number>;
3170
+ };
3171
+ ConnectionInvalidated: {
3172
+ connection: Schema.String;
3173
+ };
3174
+ ConnectionRefreshed: {
3175
+ connection: Schema.String;
3176
+ };
3177
+ QueryFailed: {
3178
+ connection: Schema.String;
3179
+ error: Schema.Struct<{
3180
+ readonly _tag: Schema.String;
3181
+ readonly message: Schema.String;
3182
+ }>;
3183
+ };
3184
+ }>;
3185
+ /**
3186
+ * A bound domain under one wrapper variant of the application's union, the
3187
+ * same shape Foldkit gives a Submodel: `toParentMessage` wraps Remote's
3188
+ * Messages, the fold reduces them, and its `fetch`, `mutate`, and
3189
+ * `subscriptions` yield the wrapper. Spreading `Remote.messages` and
3190
+ * narrowing with `Remote.reduces` remains the shorter path for an
3191
+ * application whose `update` only reduces.
3192
+ *
3193
+ * @example
3194
+ * ```ts
3195
+ * const Message = defineMessageUnion({ GotRemoteMessage: { message: Remote.Message } })
3196
+ * const foldData = Remote.fold(Data, message => Message.GotRemoteMessage({ message }))
3197
+ *
3198
+ * const update = (model: Model, message: Message): Return =>
3199
+ * Message.match(message, {
3200
+ * GotRemoteMessage: ({ message }) => foldData(model, message),
3201
+ * })
3202
+ * const subscriptions = Subscription.make<Model, Message, RemoteClient>()(() =>
3203
+ * foldData.subscriptions({ page: Surface.at(ProjectPage, …) }),
3204
+ * )
3205
+ * ```
3206
+ */
3207
+ fold: <Domain extends RemoteDomain<any, any, any, any, any>, ParentMessage>(domain: Domain, toParentMessage: (message: RemoteMessage) => ParentMessage) => RemoteFold<ModelOfDomain<Domain>, ParentMessage, Domain>;
2698
3208
  /**
2699
3209
  * A patch of one entity's values, for a mutation's `optimistic` list or an
2700
3210
  * overlay. Takes a `foldkit-entity` Entity or a Remote descriptor alike, so
@@ -2737,6 +3247,17 @@ export declare const Remote: {
2737
3247
  * rejects a selection for an entity this domain never declared.
2738
3248
  */
2739
3249
  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]>>;
3250
+ /**
3251
+ * The resume part for this domain, for `foldkit-ssr`'s `SSR.plan({ parts })`:
3252
+ * a server render sends what the plan's active Surfaces read from the store,
3253
+ * each connection with its boundaries and each live cursor with it, and
3254
+ * nothing else. `id` tells two domains in one application apart.
3255
+ */
3256
+ resume: <AppModel, Store extends RemoteModel>(domain: {
3257
+ readonly store: ModelRef<AppModel, Store>;
3258
+ }, options?: {
3259
+ readonly id?: string | undefined;
3260
+ }) => RemoteResumePart<AppModel>;
2740
3261
  /**
2741
3262
  * A Projection node that reads a `RemoteData` value out of the store. The id
2742
3263
  * is supplied by the caller, usually from a Surface's params. The assembled
@@ -2745,6 +3266,17 @@ export declare const Remote: {
2745
3266
  * stale field reads as `Refreshing`: an observer is refetching it.
2746
3267
  */
2747
3268
  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>>;
3269
+ /**
3270
+ * When what a projection shows was last received, and whether it is stale
3271
+ * or loading. Pure, so a view can show "updated 5s ago" without I/O.
3272
+ *
3273
+ * `updatedAt` is the newest server write among what is shown, as the
3274
+ * store dates it; `undefined` when nothing shown was received (nothing
3275
+ * loaded, or only an optimistic preview). `stale` is any shown field or
3276
+ * connection marked stale; `loading` is any of them in flight. Optimistic
3277
+ * previews do not date: showing only one reads `updatedAt: undefined`.
3278
+ */
3279
+ meta: <AppModel, Store extends RemoteModel, Value>(bound: BoundRemote<AppModel, Store>, model: AppModel, projection: Projection<AppModel, Value>) => ReadMeta;
2748
3280
  /**
2749
3281
  * The pure plan for a projection against a Model: the requirements its
2750
3282
  * remote store does not satisfy, under `options` (freshness, force). A
@@ -2797,6 +3329,17 @@ export declare const Remote: {
2797
3329
  * already being refreshed returns the same Model.
2798
3330
  */
2799
3331
  refresh: <AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store>, model: AppModel, target: Projection<AppModel, unknown> | Surface<AppModel, any, any, void>) => AppModel;
3332
+ /**
3333
+ * Forgets everything the server told this Model: values, tombstones,
3334
+ * unavailable fields, connections, live cursors, failures. What is known is
3335
+ * known for a principal, and this is the one boundary for a login, a logout
3336
+ * or a switch of organization: called from `update`, it performs no I/O, and
3337
+ * every active Surface's read and live entries restart, so the screen asks
3338
+ * again as whoever the client now is. A read or stream begun before is
3339
+ * interrupted rather than landing after. A mutation in flight is treated as
3340
+ * applied: its answer writes nothing here.
3341
+ */
3342
+ forget: <AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store>, model: AppModel) => AppModel;
2800
3343
  /**
2801
3344
  * Writes a read result into the store, recording each field's applied window.
2802
3345
  * `requests` are the planned requirements the result answers.
@@ -2825,8 +3368,10 @@ export declare const Remote: {
2825
3368
  /**
2826
3369
  * Runs a `Query` through `RemoteClient`, encoding its input from the ref.
2827
3370
  * Pair the result with `Remote.queryMessage` to merge the page into the Model.
3371
+ * With `select`, the server also returns the selected fields of the page's
3372
+ * items, so one response populates both the connection and the store.
2828
3373
  */
2829
- query: <Name extends string, Input>(ref: QueryRef<Name, Input>) => Effect.Effect<{
3374
+ query: <Name extends string, Input>(ref: QueryRef<Name, Input>, select?: RelationRequirement | undefined) => Effect.Effect<{
2830
3375
  readonly edges: readonly {
2831
3376
  readonly entity: string;
2832
3377
  readonly id: string;
@@ -2848,9 +3393,21 @@ export declare const Remote: {
2848
3393
  } | {
2849
3394
  readonly _tag: "Unknown";
2850
3395
  };
3396
+ readonly entities?: readonly {
3397
+ readonly entity: string;
3398
+ readonly id: string;
3399
+ readonly values: {
3400
+ readonly [x: string]: unknown;
3401
+ };
3402
+ }[] | undefined;
3403
+ readonly settled?: readonly {
3404
+ readonly entity: string;
3405
+ readonly id: string;
3406
+ readonly fields: readonly string[];
3407
+ }[] | undefined;
2851
3408
  }, RemoteQueryError, RemoteClient>;
2852
3409
  /** The `RemoteMessage` that merges a query page into its connection. */
2853
- queryMessage: <Name extends string, Input>(ref: QueryRef<Name, Input>, result: Schema.Schema.Type<typeof QueryResult>) => RemoteMessage;
3410
+ queryMessage: <Name extends string, Input>(ref: QueryRef<Name, Input>, result: Schema.Schema.Type<typeof QueryResult>, select?: RelationRequirement | undefined, now?: number | undefined) => RemoteMessage;
2854
3411
  /**
2855
3412
  * The edges a connection shows: its server-known region with pending and
2856
3413
  * confirmed overlays placed around it, minus removed edges and edges whose
@@ -2909,11 +3466,8 @@ export declare const Remote: {
2909
3466
  * read, since nothing was being read. The resume cursor is read
2910
3467
  * from `RemoteModel.live`, so the application tracks no cursor of its own.
2911
3468
  */
2912
- 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, {
2913
- readonly requirements: ReadonlyArray<Requirement>;
2914
- readonly cursor: LiveCursor;
2915
- }, RemoteClient>;
3469
+ live: <AppModel, Store extends RemoteModel, Names extends string, Model, SurfaceMessage, Params, Message = RemoteMessage>(bound: BoundRemote<AppModel, Store, Names>, surface: Surface<AppModel, Model, SurfaceMessage, Params>, params: Params, toMessage?: (message: RemoteMessage) => Message, options?: LiveOptions) => EntryWithoutKeepAlive<AppModel, Message, LiveDependencies, RemoteClient>;
2916
3470
  };
2917
3471
  //#endregion
2918
- export { Entity$1 as Entity };
3472
+ export { Entity$1 as Entity, type RemoteResumePart };
2919
3473
  //# sourceMappingURL=index.d.mts.map