foldkit-remote 0.3.0 → 0.5.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,65 @@
1
1
  import { Context, Duration, Effect, Layer, Option, Schema, Stream } from "effect";
2
- import { ActiveSurface, Contract, Invalid, Metadata, ModelRef, Projection, Surface } from "foldkit-surface";
2
+ import * as Domain from "foldkit-entity";
3
+ import { AnyEntity, AnyQuery, InputExpr, Query as Query$1 } from "foldkit-entity";
4
+ import { EntryWithoutKeepAlive } from "foldkit/subscription";
5
+ import { ActiveSurface, Contract, Invalid, Metadata, ModelRef, Projection, Surface, Wiring } from "foldkit-surface";
3
6
  import { Rpc, RpcGroup } from "effect/unstable/rpc";
4
7
  import { KeyValueStore } from "effect/unstable/persistence";
5
8
  import { Command } from "foldkit/command";
6
- import { EntryWithoutKeepAlive } from "foldkit/subscription";
9
+ //#region ../metadata/dist/index.d.mts
10
+ //#region src/index.d.ts
11
+ /** Marks a `Metadata` value. Its entries are private to this module. */
12
+ declare const MetadataTypeId: unique symbol;
13
+ type MetadataTypeId = typeof MetadataTypeId;
14
+ /**
15
+ * Declarative facts an interpreter attaches to a node it does not own, such as
16
+ * the server data a Remote selection needs. The carrier holds and combines
17
+ * them without knowing what they mean; a package reads only the key it owns.
18
+ *
19
+ * Opaque: only a key's `of` and `Metadata.combine` make one, so entries cannot
20
+ * be forged past a key's type or `merge`, and they are frozen.
21
+ */
22
+ interface Metadata$1 {
23
+ readonly [MetadataTypeId]: MetadataTypeId;
24
+ }
25
+ /**
26
+ * An interpreter's typed slot in `Metadata`. Lookup is by the key object, never
27
+ * its `name`, so two packages cannot collide by choosing the same string.
28
+ */
29
+ interface MetadataKey<A> {
30
+ /** For tooling output only. */
31
+ readonly name: string;
32
+ /** Normalizes the entries gathered from combined values, e.g. unioning duplicates. */
33
+ readonly merge: (values: ReadonlyArray<A>) => ReadonlyArray<A>;
34
+ /** One line per entry for tooling output. */
35
+ readonly summarize: (value: A) => string;
36
+ readonly of: (...values: ReadonlyArray<A>) => Metadata$1;
37
+ readonly get: (metadata: Metadata$1) => ReadonlyArray<A>;
38
+ }
39
+ /** One key's entries as serializable text, named by the key. */
40
+ interface MetadataSummary {
41
+ readonly name: string;
42
+ readonly entries: readonly string[];
43
+ }
44
+ declare const Metadata$1: {
45
+ /**
46
+ * Declares an interpreter's slot. Call once per package, at module level:
47
+ * entries are found by the key object, so two copies of a package (a
48
+ * duplicated install, a reloaded module) do not see each other's entries.
49
+ */
50
+ key: <A>(name: string, options: {
51
+ readonly merge: (values: ReadonlyArray<A>) => ReadonlyArray<A>;
52
+ readonly summarize: (value: A) => string;
53
+ }) => MetadataKey<A>;
54
+ empty: Metadata$1;
55
+ /** True only for a value this module made; a copy or a hand-built brand is not one. */
56
+ is: (value: unknown) => value is Metadata$1;
57
+ /** Gathers every part's entries and runs each key's `merge` over its group. */
58
+ combine: (parts: ReadonlyArray<Metadata$1>) => Metadata$1;
59
+ summarize: (metadata: Metadata$1) => readonly MetadataSummary[];
60
+ };
61
+ //#endregion
62
+ //#endregion
7
63
  //#region src/connection.d.ts
8
64
  export interface EdgeRef {
9
65
  readonly entity: string;
@@ -49,6 +105,96 @@ export declare const hasNext: (connection: Connection) => boolean;
49
105
  /** A connection with more than one segment has an explicit unknown gap. */
50
106
  export declare const isGapped: (connection: Connection) => boolean;
51
107
  //#endregion
108
+ //#region src/remoteData.d.ts
109
+ export interface RemoteError {
110
+ readonly _tag: string;
111
+ readonly message: string;
112
+ }
113
+ export type RemoteData<A> = {
114
+ readonly _tag: 'Initial';
115
+ } | {
116
+ readonly _tag: 'Loading';
117
+ } | {
118
+ readonly _tag: 'Ready';
119
+ readonly value: A;
120
+ } | {
121
+ readonly _tag: 'Refreshing';
122
+ readonly value: A;
123
+ } | {
124
+ readonly _tag: 'Failed';
125
+ readonly error: RemoteError;
126
+ readonly previous?: A;
127
+ } | {
128
+ readonly _tag: 'NotFound';
129
+ };
130
+ /**
131
+ * What `RemoteData.render` tells the `data` branch about the value it is
132
+ * given: whether a newer answer is on its way, and whether this one is what
133
+ * was last known good before a read failed. It is one tag rather than two
134
+ * booleans because a value cannot be both at once, and a type that can say so
135
+ * invites a view to handle a state that never arrives.
136
+ */
137
+ export type Freshness = {
138
+ readonly _tag: 'Fresh';
139
+ } | {
140
+ readonly _tag: 'Refreshing';
141
+ } | {
142
+ readonly _tag: 'Stale';
143
+ readonly error: RemoteError;
144
+ };
145
+ export declare const remoteErrorSchema: Schema.Struct<{
146
+ readonly _tag: Schema.String;
147
+ readonly message: Schema.String;
148
+ }>;
149
+ export declare const remoteDataSchema: <A>(value: Schema.Schema<A>) => Schema.Codec<RemoteData<A>, unknown>;
150
+ export declare const RemoteData: {
151
+ /**
152
+ * The `RemoteData` schema for a value schema. Exposed so a `RemoteData` can
153
+ * be embedded in a hand-written Model schema, not only through `Remote.select`.
154
+ */
155
+ schema: <A>(value: Schema.Schema<A>) => Schema.Schema<RemoteData<A>>;
156
+ /** Exhaustive: omitting a state is a compile error. */
157
+ match: <A, R>(data: RemoteData<A>, cases: {
158
+ readonly Initial: () => R;
159
+ readonly Loading: () => R;
160
+ readonly Ready: (value: A) => R;
161
+ readonly Refreshing: (value: A) => R;
162
+ readonly Failed: (error: RemoteError, previous: Option.Option<A>) => R;
163
+ readonly NotFound: () => R;
164
+ }) => R;
165
+ /**
166
+ * The view-oriented fold: the six states as the three things a view actually
167
+ * draws, under the policy that useful data stays on screen. A value that is
168
+ * being refetched, or that a later read failed to replace, still reaches
169
+ * `data` — with `freshness` saying which — instead of being replaced by a
170
+ * spinner or an error the reader cannot act on.
171
+ *
172
+ * ```ts
173
+ * RemoteData.render(model.user, {
174
+ * loading: () => UserSkeleton(),
175
+ * notFound: () => NoSuchUser(),
176
+ * failed: error => ErrorView(error),
177
+ * data: (user, freshness) => UserView({ user, dimmed: freshness._tag !== 'Fresh' }),
178
+ * })
179
+ * ```
180
+ *
181
+ * `notFound` is its own branch and not optional: a row the server answered
182
+ * for and does not have is neither loading nor a failure, and drawing it as
183
+ * either is a spinner that never ends or an error nobody can fix.
184
+ *
185
+ * This does not replace `match`, which is the exhaustive fold over the states
186
+ * themselves. Reach for `match` when the six states really do draw
187
+ * differently, and for this when they draw the usual three ways.
188
+ */
189
+ render: <A, R>(data: RemoteData<A>, cases: {
190
+ readonly loading: () => R;
191
+ readonly notFound: () => R;
192
+ readonly failed: (error: RemoteError) => R;
193
+ readonly data: (value: A, freshness: Freshness) => R;
194
+ }) => R;
195
+ map: <A, B>(data: RemoteData<A>, f: (value: A) => B) => RemoteData<B>;
196
+ };
197
+ //#endregion
52
198
  //#region src/store.d.ts
53
199
  export type EntityKey = string;
54
200
  export interface EntityEntry {
@@ -128,6 +274,8 @@ export interface MutationState {
128
274
  readonly pending: ReadonlySet<string>;
129
275
  readonly applied: ReadonlySet<string>;
130
276
  readonly failed: ReadonlySet<string>;
277
+ /** Why each request in `failed` failed, kept exactly as long as `failed` keeps its id. */
278
+ readonly errors: ReadonlyMap<string, RemoteError>;
131
279
  /**
132
280
  * How many mutations this model has started. A bound domain takes its next
133
281
  * request id from here, so `update` stays pure and the id exists before the
@@ -137,7 +285,21 @@ export interface MutationState {
137
285
  }
138
286
  export declare const emptyMutationState: MutationState;
139
287
  export declare const beginMutation: (state: MutationState, requestId: string) => MutationState;
140
- export declare const failMutation: (state: MutationState, requestId: string) => MutationState;
288
+ export declare const failMutation: (state: MutationState, requestId: string, error: RemoteError) => MutationState;
289
+ /** What Remote knows of one mutation request, by the id `mutate` returned. */
290
+ export type MutationStatus =
291
+ /** Never started here, or settled so long ago its id has left the window. */
292
+ {
293
+ readonly _tag: 'Unknown';
294
+ } | {
295
+ readonly _tag: 'Pending';
296
+ } | {
297
+ readonly _tag: 'Applied';
298
+ } | {
299
+ readonly _tag: 'Failed';
300
+ readonly error: RemoteError;
301
+ };
302
+ export declare const mutationStatus: (state: MutationState, requestId: string) => MutationStatus;
141
303
  export interface Reconciled {
142
304
  readonly store: EntityStore;
143
305
  readonly state: MutationState;
@@ -147,7 +309,10 @@ export interface Reconciled {
147
309
  * with the same `requestId` (a retry, or a live event describing the same change)
148
310
  * does not re-apply the entities, but still clears `pending`.
149
311
  */
150
- export declare const reconcileMutation: (store: EntityStore, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>) => Reconciled;
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;
151
316
  /** A mutation an application declares: its name and input/output codecs. */
152
317
  export interface MutationDescriptor<Name extends string, Input, Output> {
153
318
  readonly name: Name;
@@ -202,7 +367,20 @@ export interface QueryDescriptor<Name extends string, Input, Result> {
202
367
  readonly Input: Schema.Codec<Input>;
203
368
  readonly Result: Result;
204
369
  readonly ref: (input: Input) => QueryRef<Name, Input>;
370
+ /**
371
+ * What the query means, when it was declared with `Query.define`: the rows it
372
+ * is about, as a value an interpreter can compile. A descriptor from
373
+ * `Query.make` has none — its meaning lives in whatever the server registered
374
+ * to answer it — and a source is free to answer either.
375
+ */
376
+ readonly body?: AnyQuery | undefined;
205
377
  }
378
+ /**
379
+ * The inputs of a definition's body: one placeholder per key of `Input`, typed
380
+ * as that key's value. A body is built once, so these stand for what the query
381
+ * will be given rather than being it.
382
+ */
383
+ export type QueryInputs<Input> = { readonly [K in keyof Input & string]: InputExpr<Input[K]>; };
206
384
  /** Stable stringify: object keys sorted, undefined-valued keys dropped, so equal inputs encode equally. */
207
385
  export declare const stableStringify: (value: unknown) => string;
208
386
  /**
@@ -213,6 +391,8 @@ export declare const stableStringify: (value: unknown) => string;
213
391
  export type ResultOf<Result> = Result extends {
214
392
  readonly name: infer Entity extends string;
215
393
  } ? ConnectionSpec<Entity> : Result;
394
+ /** A relational `Query` over one Entity, as `Query.define`'s body returns. */
395
+ type RelationalQueryOf<E extends AnyEntity> = ReturnType<typeof Query$1.from<E>>;
216
396
  export declare const Query: {
217
397
  /** Declares the entity and options a query's result is a connection over. */
218
398
  connection: <Entity extends string>(entity: {
@@ -230,10 +410,44 @@ export declare const Query: {
230
410
  readonly Input: Input;
231
411
  readonly Result: Result;
232
412
  }) => QueryDescriptor<Name, TypeOf<Input>, ResultOf<Result>>;
413
+ /**
414
+ * Declares a query by what it means. The body is built once, here, and the
415
+ * `input` it is given holds placeholders rather than values — there is
416
+ * nothing yet to branch on, so a condition that depends on what was passed is
417
+ * a comparison over the placeholder:
418
+ *
419
+ * ```ts
420
+ * const PostsBySlug = Query.define('PostsBySlug', { slug: Schema.String }, ({ input }) =>
421
+ * Query.from(Post).pipe(
422
+ * Query.where(Expr.eq(Post.fields.slug, input.slug)),
423
+ * Query.orderBy(Order.asc(Post.fields.id)),
424
+ * ),
425
+ * )
426
+ * ```
427
+ *
428
+ * What comes back is an ordinary `QueryDescriptor` — the same name, `Input`,
429
+ * `ref` and connection identity `Query.make` gives — carrying its `body`
430
+ * besides. A server can compile that body instead of being told the same
431
+ * thing again in its own dialect, and one that would rather answer the query
432
+ * its own way still can.
433
+ *
434
+ * The result is a connection over the Entity the body reads, so it is not
435
+ * named twice.
436
+ */
437
+ define: <const Name extends string, Input extends SchemaOrFields, E extends AnyEntity>(name: Name, Input: Input, body: (context: {
438
+ readonly input: QueryInputs<TypeOf<Input>>;
439
+ }) => RelationalQueryOf<E>, options?: {
440
+ readonly edgeKey?: Schema.Schema<unknown>;
441
+ readonly live?: LivePolicy;
442
+ }) => QueryDescriptor<Name, TypeOf<Input>, ConnectionSpec<E["name"]>>;
233
443
  first: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
234
444
  last: (count: number) => <R extends QueryRef<string, unknown>>(ref: R) => R;
235
445
  after: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
236
446
  before: (cursor: Cursor) => <R extends QueryRef<string, unknown>>(ref: R) => R;
447
+ from: <E extends AnyEntity>(entity: E) => Query$1<E>;
448
+ where: (...predicates: ReadonlyArray<import("foldkit-entity").Predicate>) => <E extends AnyEntity>(self: Query$1<E>) => Query$1<E>;
449
+ orderBy: (...terms: ReadonlyArray<import("foldkit-entity").OrderTerm>) => <E extends AnyEntity>(self: Query$1<E>) => Query$1<E>;
450
+ dependencies: (self: AnyQuery) => import("foldkit-entity").Dependencies;
237
451
  };
238
452
  //#endregion
239
453
  //#region src/requirement.d.ts
@@ -283,9 +497,9 @@ export declare const Requirement: {
283
497
  mergeConnections: typeof mergeConnections;
284
498
  };
285
499
  /** Remote's entity requirements on a Projection, unioned per entity and id as nodes compose. */
286
- export declare const RemoteRequirements: import("foldkit-surface").MetadataKey<Requirement>;
500
+ export declare const RemoteRequirements: MetadataKey<Requirement>;
287
501
  /** Remote's query connections on a Projection, unioned per connection and window. */
288
- export declare const RemoteConnections: import("foldkit-surface").MetadataKey<ConnectionRequirement>;
502
+ export declare const RemoteConnections: MetadataKey<ConnectionRequirement>;
289
503
  /** The entity requirements a Projection carries. */
290
504
  export declare const requirementsOf: (projection: {
291
505
  readonly metadata: Metadata;
@@ -381,7 +595,10 @@ export declare const pruneOverlays: (optimistic: OptimisticState, connection: st
381
595
  * a later layer re-wins on rebase. Confirmed connection changes are recorded
382
596
  * once per request, as overlays the request no longer owns.
383
597
  */
384
- export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>) => {
598
+ export declare const settleSuccess: (base: EntityStore, optimistic: OptimisticState, state: MutationState, requestId: string, entities: ReadonlyArray<NormalizedPatch>, connections?: ReadonlyArray<ConnectionChange>, deleted?: ReadonlyArray<{
599
+ readonly entity: string;
600
+ readonly id: string;
601
+ }>) => {
385
602
  readonly store: EntityStore;
386
603
  readonly state: MutationState;
387
604
  readonly optimistic: OptimisticState;
@@ -672,6 +889,11 @@ export declare const MutationResult: Schema.Struct<{
672
889
  readonly key: Schema.String;
673
890
  }>;
674
891
  }>]>>>;
892
+ /** Entities the mutation deleted; the client knows them absent from then on. */
893
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
894
+ readonly entity: Schema.String;
895
+ readonly id: Schema.String;
896
+ }>>>;
675
897
  }>;
676
898
  export declare const LiveRequirement: Schema.Struct<{
677
899
  readonly version: Schema.Number;
@@ -760,6 +982,11 @@ export declare const Mutate: Rpc.Rpc<"FoldkitRemoteMutate", Schema.Struct<{
760
982
  readonly key: Schema.String;
761
983
  }>;
762
984
  }>]>>>;
985
+ /** Entities the mutation deleted; the client knows them absent from then on. */
986
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
987
+ readonly entity: Schema.String;
988
+ readonly id: Schema.String;
989
+ }>>>;
763
990
  }>, typeof RemoteMutationError, never, never>;
764
991
  export declare const Live: Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
765
992
  readonly version: Schema.Number;
@@ -924,6 +1151,11 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
924
1151
  readonly key: Schema.String;
925
1152
  }>;
926
1153
  }>]>>>;
1154
+ /** Entities the mutation deleted; the client knows them absent from then on. */
1155
+ readonly deleted: Schema.optional<Schema.$Array<Schema.Struct<{
1156
+ readonly entity: Schema.String;
1157
+ readonly id: Schema.String;
1158
+ }>>>;
927
1159
  }>, typeof RemoteMutationError, never, never> | Rpc.Rpc<"FoldkitRemoteLive", Schema.Struct<{
928
1160
  readonly version: Schema.Number;
929
1161
  readonly requirements: Schema.$Array<Schema.Codec<Requirement, Requirement, never, never>>;
@@ -997,51 +1229,6 @@ export declare const RemoteRpc: RpcGroup.RpcGroup<Rpc.Rpc<"FoldkitRemoteRead", S
997
1229
  }>]>;
998
1230
  }>, typeof RemoteQueryError, never, never>>;
999
1231
  //#endregion
1000
- //#region src/remoteData.d.ts
1001
- export interface RemoteError {
1002
- readonly _tag: string;
1003
- readonly message: string;
1004
- }
1005
- export type RemoteData<A> = {
1006
- readonly _tag: 'Initial';
1007
- } | {
1008
- readonly _tag: 'Loading';
1009
- } | {
1010
- readonly _tag: 'Ready';
1011
- readonly value: A;
1012
- } | {
1013
- readonly _tag: 'Refreshing';
1014
- readonly value: A;
1015
- } | {
1016
- readonly _tag: 'Failed';
1017
- readonly error: RemoteError;
1018
- readonly previous?: A;
1019
- } | {
1020
- readonly _tag: 'NotFound';
1021
- };
1022
- export declare const remoteErrorSchema: Schema.Struct<{
1023
- readonly _tag: Schema.String;
1024
- readonly message: Schema.String;
1025
- }>;
1026
- export declare const remoteDataSchema: <A>(value: Schema.Schema<A>) => Schema.Codec<RemoteData<A>, unknown>;
1027
- export declare const RemoteData: {
1028
- /**
1029
- * The `RemoteData` schema for a value schema. Exposed so a `RemoteData` can
1030
- * be embedded in a hand-written Model schema, not only through `Remote.select`.
1031
- */
1032
- schema: <A>(value: Schema.Schema<A>) => Schema.Schema<RemoteData<A>>;
1033
- /** Exhaustive: omitting a state is a compile error. */
1034
- match: <A, R>(data: RemoteData<A>, cases: {
1035
- readonly Initial: () => R;
1036
- readonly Loading: () => R;
1037
- readonly Ready: (value: A) => R;
1038
- readonly Refreshing: (value: A) => R;
1039
- readonly Failed: (error: RemoteError, previous: Option.Option<A>) => R;
1040
- readonly NotFound: () => R;
1041
- }) => R;
1042
- map: <A, B>(data: RemoteData<A>, f: (value: A) => B) => RemoteData<B>;
1043
- };
1044
- //#endregion
1045
1232
  //#region src/model.d.ts
1046
1233
  /**
1047
1234
  * The normalized cache as a Foldkit Submodel. `Remote.define` returns a schema
@@ -1068,15 +1255,25 @@ export interface RemoteModel {
1068
1255
  */
1069
1256
  readonly loading: ReadonlySet<string>;
1070
1257
  /**
1071
- * `Remote.refresh` generations. The read entries restart when `requested`
1072
- * moves, so a read sent before a refresh cannot land after it; `started` is
1073
- * the latest generation a read began under.
1258
+ * `Remote.refresh` generations, held per field rather than for the store as a
1259
+ * whole. A read entry restarts when the generation over the fields it plans
1260
+ * moves, so a read sent before a refresh of its own fields cannot land after
1261
+ * it, and a refresh of one field leaves every other entry's read alone.
1074
1262
  */
1075
- readonly refresh: {
1076
- readonly requested: number;
1077
- readonly started: number;
1078
- };
1263
+ readonly refresh: RefreshState;
1079
1264
  }
1265
+ /**
1266
+ * `Remote.refresh` generations, per field mark. `generation` is the last one
1267
+ * handed out; `requested` is when each field was last refreshed, and `started`
1268
+ * is the generation each field's read last began under. Holding them per field
1269
+ * is what keeps one Projection's refresh from restarting every read entry.
1270
+ */
1271
+ export interface RefreshState {
1272
+ readonly generation: number;
1273
+ readonly requested: ReadonlyMap<string, number>;
1274
+ readonly started: ReadonlyMap<string, number>;
1275
+ }
1276
+ export declare const emptyRefresh: RefreshState;
1080
1277
  export declare const initialRemoteModel: RemoteModel;
1081
1278
  export declare const remoteModelSchema: () => Schema.Codec<RemoteModel, unknown>;
1082
1279
  /** The submodel's Messages; each reduces to `RemoteModel` through `updateRemote`. */
@@ -1124,10 +1321,28 @@ export type RemoteMessage = {
1124
1321
  readonly entities: readonly NormalizedPatch[];
1125
1322
  /** Connection changes the server confirmed; they replace the request's own. */
1126
1323
  readonly connections?: ReadonlyArray<ConnectionChange> | undefined;
1324
+ /** Entities the mutation deleted: tombstoned, which hides them from every connection. */
1325
+ readonly deleted?: ReadonlyArray<{
1326
+ readonly entity: string;
1327
+ readonly id: string;
1328
+ }> | undefined;
1127
1329
  } | {
1128
1330
  readonly _tag: 'MutationFailed';
1129
1331
  readonly requestId: string;
1130
1332
  readonly error: RemoteError;
1333
+ } |
1334
+ /**
1335
+ * Operations shown over the store with no request behind them, until they are
1336
+ * lifted: a preview of a change nobody has made. Showing an id again replaces
1337
+ * what it showed.
1338
+ */
1339
+ {
1340
+ readonly _tag: 'OverlayShown';
1341
+ readonly id: string;
1342
+ readonly optimistic: ReadonlyArray<OptimisticOperation>;
1343
+ } | {
1344
+ readonly _tag: 'OverlayLifted';
1345
+ readonly id: string;
1131
1346
  } | {
1132
1347
  readonly _tag: 'LiveReceived';
1133
1348
  readonly stream: string;
@@ -1218,6 +1433,10 @@ export declare const remoteMessageCases: {
1218
1433
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1219
1434
  }>>;
1220
1435
  connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
1436
+ deleted: Schema.optional<Schema.$Array<Schema.Struct<{
1437
+ readonly entity: Schema.String;
1438
+ readonly id: Schema.String;
1439
+ }>>>;
1221
1440
  };
1222
1441
  MutationFailed: {
1223
1442
  requestId: Schema.String;
@@ -1226,6 +1445,13 @@ export declare const remoteMessageCases: {
1226
1445
  readonly message: Schema.String;
1227
1446
  }>;
1228
1447
  };
1448
+ OverlayShown: {
1449
+ id: Schema.String;
1450
+ optimistic: Schema.$Array<Schema.Unknown>;
1451
+ };
1452
+ OverlayLifted: {
1453
+ id: Schema.String;
1454
+ };
1229
1455
  LiveReceived: {
1230
1456
  stream: Schema.String;
1231
1457
  event: Schema.Unknown;
@@ -1273,6 +1499,25 @@ export declare const isRemoteMessage: <M extends {
1273
1499
  readonly _tag: RemoteMessageTag;
1274
1500
  }>;
1275
1501
  export declare const remoteMessageSchema: Schema.Schema<RemoteMessage>;
1502
+ /**
1503
+ * The generation a read is planned under: the highest any of the fields it
1504
+ * reads or connections it runs was refreshed at. A read entry carries this as a
1505
+ * dependency, so it restarts when what it observes is refreshed and not when
1506
+ * anything else is.
1507
+ */
1508
+ export declare const refreshedAt: (refresh: RefreshState, requests: ReadonlyArray<Requirement>, connections?: ReadonlyArray<string>) => number;
1509
+ /**
1510
+ * Marks every field of `requests` and every connection in `connections`
1511
+ * refreshed at the next generation.
1512
+ */
1513
+ export declare const withRefreshRequested: (refresh: RefreshState, requests: ReadonlyArray<Requirement>, connections?: ReadonlyArray<string>) => RefreshState;
1514
+ /**
1515
+ * Whether one field's read already began under the generation that field was
1516
+ * last refreshed at. Such a read is in flight and would otherwise outlive the
1517
+ * refresh, so the refresh takes a new generation to restart it even though the
1518
+ * field is already stale.
1519
+ */
1520
+ export declare const refreshIsInFlight: (refresh: RefreshState, request: Requirement, field: string) => boolean;
1276
1521
  /**
1277
1522
  * Whether a read is fetching any of `fields` for this entity. Consulted only
1278
1523
  * when the store lacks the value, which is what separates `Loading` from
@@ -1374,6 +1619,10 @@ export declare const mutateRemote: <Name extends string, Input, Output>(mutation
1374
1619
  };
1375
1620
  }[];
1376
1621
  connections: ConnectionChange[];
1622
+ deleted: readonly {
1623
+ readonly entity: string;
1624
+ readonly id: string;
1625
+ }[];
1377
1626
  }, RemoteMutationError, RemoteClient>;
1378
1627
  //#endregion
1379
1628
  //#region src/relation.d.ts
@@ -1397,6 +1646,25 @@ export interface RelationShape {
1397
1646
  readonly nullable: boolean;
1398
1647
  readonly entity: string;
1399
1648
  }
1649
+ /**
1650
+ * A page of a relation that is a whole list is read under a name of its own, the
1651
+ * field's name and the page's size: `comments@first=10`. It is a field like any
1652
+ * other to the store, the planner, and the wire, so the whole list and a page of
1653
+ * it are held side by side, merged, marked stale, and persisted each on its own.
1654
+ * The server reads the name apart, reads the relation with the window, and
1655
+ * answers under the alias. A cursor is not part of the name: a page read from a
1656
+ * cursor merges onto the page it continues.
1657
+ */
1658
+ export declare const RELATION_ALIAS = "@";
1659
+ /** The alias a relation field is read under, for a window of this size. */
1660
+ export declare const relationAlias: (field: string, window: {
1661
+ readonly first?: number | undefined;
1662
+ readonly last?: number | undefined;
1663
+ readonly after?: string | undefined;
1664
+ readonly before?: string | undefined;
1665
+ }) => string;
1666
+ /** The field an alias reads; a name that is no alias is its own field. */
1667
+ export declare const aliasedField: (name: string) => string;
1400
1668
  /** Splits a ref key (`"Entity:id"`, the store key too) back into its parts. */
1401
1669
  export declare const refParts: (encoded: string) => RefParts;
1402
1670
  /**
@@ -1458,6 +1726,11 @@ export declare const pageSchema: (item: AnySchema) => AnySchema;
1458
1726
  /** The requirement a nested selection contributes for its relation's target. */
1459
1727
  export declare const relationOf: (selection: Selection<unknown>) => RelationRequirement;
1460
1728
  export declare const Selection: {
1729
+ /**
1730
+ * The Remote Selection of a `foldkit-entity` Selection: the same members, read
1731
+ * from Remote's store. `true` on a relation reads its refs, as it does here.
1732
+ */
1733
+ from: <Name extends string, S extends Schema.Constraint>(selection: Domain.Selection<Name, unknown, S>) => Selection<S["Type"], Name, "entity">;
1461
1734
  /**
1462
1735
  * The fields to read of `entity`. A nested `Selection` on a relation field
1463
1736
  * reads through the ref (or refs, or page of refs) the field holds into the
@@ -1526,7 +1799,25 @@ export interface RefPage<Name extends string, F extends Schema.Struct.Fields = S
1526
1799
  readonly hasNext: boolean;
1527
1800
  readonly hasPrevious: boolean;
1528
1801
  }
1802
+ /** The ref codec a `foldkit-entity` relation becomes: one ref, a nullable ref, or an array of refs. */
1803
+ 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;
1804
+ /**
1805
+ * The fields Remote stores for a `foldkit-entity` Entity: its own fields, its
1806
+ * derived members (the server supplies them like any field), and each relation
1807
+ * as refs.
1808
+ */
1809
+ 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;
1529
1810
  declare const Entity$1: {
1811
+ /**
1812
+ * The Remote descriptor of a `foldkit-entity` Entity. Relations declared with
1813
+ * `Entity.relate` become ref fields, so the store, the planner, and the server
1814
+ * treat it as they treat an `Entity.make` descriptor.
1815
+ */
1816
+ from: <E extends Domain.AnyEntity>(entity: E & {
1817
+ readonly fields: {
1818
+ readonly id: unknown;
1819
+ };
1820
+ }) => EntityDescriptor<E["name"], FieldsFrom<E>>;
1530
1821
  make: <const Name extends string, const F extends Schema.Struct.Fields & {
1531
1822
  readonly id: Schema.Schema<unknown>;
1532
1823
  }>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
@@ -1571,6 +1862,13 @@ export interface RemoteInspection {
1571
1862
  readonly connections: ReadonlyArray<string>;
1572
1863
  readonly live: ReadonlyArray<string>;
1573
1864
  readonly gaps: ReadonlyArray<string>;
1865
+ /**
1866
+ * The `entity\0id\0field` marks of reads in flight. This is what "Remote is
1867
+ * working" means here, and it is read from the Model rather than from the
1868
+ * fibers doing the work: a tool that shows it shows something the Model can
1869
+ * be replayed to, and nothing that needs the runtime to be asked.
1870
+ */
1871
+ readonly loading: ReadonlyArray<string>;
1574
1872
  readonly mutations: {
1575
1873
  readonly pending: ReadonlyArray<string>;
1576
1874
  readonly failed: ReadonlyArray<string>;
@@ -1640,7 +1938,18 @@ export declare const RemotePolicy: {
1640
1938
  };
1641
1939
  //#endregion
1642
1940
  //#region src/index.d.ts
1643
- type EntityName<D> = D extends EntityDescriptor<infer Name, any> ? Name : never;
1941
+ /** What a domain registers: a Remote descriptor, or a `foldkit-entity` Entity (read through `Entity.from`). */
1942
+ export type EntityLike = EntityDescriptor<any, any> | Domain.AnyEntity;
1943
+ /**
1944
+ * What a read selects: a Remote Selection, or a `foldkit-entity` Selection
1945
+ * (read through `Selection.from`).
1946
+ */
1947
+ export type EntitySelection<Value, Name extends string, Id extends string = string> = Selection<Value, Name, 'entity'> | Domain.Selection<Name, unknown, Schema.Constraint & {
1948
+ readonly Type: Value;
1949
+ }, Id>;
1950
+ type EntityName<D> = D extends {
1951
+ readonly name: infer Name extends string;
1952
+ } ? Name : never;
1644
1953
  type QueryName<D> = D extends QueryDescriptor<infer Name, any, any> ? Name : never;
1645
1954
  type MutationName<D> = D extends MutationDescriptor<infer Name, any, any> ? Name : never;
1646
1955
  /**
@@ -1651,7 +1960,7 @@ type MutationName<D> = D extends MutationDescriptor<infer Name, any, any> ? Name
1651
1960
  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`>;
1652
1961
  /** Nothing when a selection is of the query's entity; otherwise a branded failure naming both. */
1653
1962
  export type SelectsEntity<Entity extends string, Of extends string> = [Entity] extends [Of] ? unknown : Invalid<`the selection is of "${Entity}", but the query lists "${Of}"`>;
1654
- 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>[]> {
1963
+ 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>[]> {
1655
1964
  readonly entities: Entities;
1656
1965
  readonly queries: Queries;
1657
1966
  readonly mutations: Mutations;
@@ -1701,6 +2010,8 @@ export type SubscriptionEntries<AppModel, Active> = { readonly [K in keyof Activ
1701
2010
  readonly retain: RemoteEntry<AppModel, any>;
1702
2011
  };
1703
2012
  export interface SubscriptionsOptions extends ObserveOptions, LiveOptions, RetainOptions {}
2013
+ /** 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. */
2014
+ export type RemoteWiring<AppModel> = Wiring<AppModel, RemoteMessage | RemoteMessageInput, RemoteClient>;
1704
2015
  /** What `RemoteDomain.mutate` hands `update`: the Model with the request started, and the Command that settles it. */
1705
2016
  export interface MutationStarted<AppModel> {
1706
2017
  readonly model: AppModel;
@@ -1715,15 +2026,15 @@ export interface MutationStarted<AppModel> {
1715
2026
  * operations over them. Every method compiles to the `Remote.*` function of the
1716
2027
  * same name, which stays exported for tooling, SSR, and tests.
1717
2028
  */
1718
- 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> {
2029
+ 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> {
1719
2030
  /** `Remote.select`: a Projection reading one entity through a selection of a registered entity. */
1720
- get<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
2031
+ get<Value, Name extends string, Id extends string = string>(selection: EntitySelection<Value, Name, Id> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: NoInfer<Id>): Projection<AppModel, RemoteData<Value>>;
1721
2032
  /**
1722
2033
  * `get`, and the projection also subscribes to the entity's changes: its
1723
2034
  * requirements are marked `live`, so `subscriptions` derives a live entry for
1724
2035
  * the Surfaces that read it.
1725
2036
  */
1726
- live<Value, Name extends string>(selection: Selection<Value, Name, 'entity'> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: string): Projection<AppModel, RemoteData<Value>>;
2037
+ live<Value, Name extends string, Id extends string = string>(selection: EntitySelection<Value, Name, Id> & Registered<Name, EntityName<Entities[number]>, 'Entity'>, id: NoInfer<Id>): Projection<AppModel, RemoteData<Value>>;
1727
2038
  /**
1728
2039
  * A query connection read as a `Page` of items selected of the query's
1729
2040
  * entity: `Initial` until the page and every item's selected fields are
@@ -1738,6 +2049,15 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1738
2049
  previous<Name extends string, Input>(model: AppModel, projection: QueryProjection<AppModel, any, Name, Input>): QueryRef<Name, Input> | undefined;
1739
2050
  /** A Command that runs the query and yields the `ConnectionMerged` (or `QueryFailed`) that reduces it: "load more". */
1740
2051
  fetch(ref: QueryRef<string, unknown>): Command<RemoteMessage, never, RemoteClient>;
2052
+ /**
2053
+ * Shows operations over the store with no request behind them, as a mutation's
2054
+ * `optimistic` ones show while it is in flight: every Selection and view draws
2055
+ * them. For a preview of a change nobody has made. They stay until `lift`;
2056
+ * showing an id again replaces what it showed. Called from `update`.
2057
+ */
2058
+ overlay(model: AppModel, id: string, optimistic: ReadonlyArray<OptimisticOperation>): AppModel;
2059
+ /** Lifts what `overlay` showed under this id. Lifting nothing returns the same Model. */
2060
+ lift(model: AppModel, id: string): AppModel;
1741
2061
  /** `Remote.refresh`: marks what a projection or a Surface requires as due, for its read entry to refetch. */
1742
2062
  refresh(model: AppModel, target: Projection<AppModel, unknown> | Surface<AppModel, any, any, void>): AppModel;
1743
2063
  /**
@@ -1753,6 +2073,30 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1753
2073
  plan<Value>(model: AppModel, projection: Projection<AppModel, Value>, options?: PlanOptions): ReadonlyArray<Requirement>;
1754
2074
  /** `Remote.storeOf`: the visible store, base under the pending optimistic layers. */
1755
2075
  storeOf(model: AppModel): EntityStore;
2076
+ /**
2077
+ * `Remote.confirmed`: the same projection read against the server-derived
2078
+ * store alone, with every pending optimistic layer and connection overlay
2079
+ * left off. What it plans is unchanged — the requirements are the
2080
+ * projection's own — so observing it reads exactly what observing the
2081
+ * projection reads; only what it *shows* differs.
2082
+ *
2083
+ * A view usually wants the projection itself, which is the visible read:
2084
+ * the optimistic layers are there so a change shows before the server has
2085
+ * agreed to it. This is for the reader that must not believe a change until
2086
+ * the server has confirmed it, which in practice is an Agent capability
2087
+ * reporting that what it was asked to do is done:
2088
+ *
2089
+ * ```ts
2090
+ * Agent.when({
2091
+ * projection: Data.confirmed(ProjectPage.model.project),
2092
+ * predicate: (project, request) => project.name === request.name,
2093
+ * })
2094
+ * ```
2095
+ *
2096
+ * There is deliberately no `visible`: a projection is already the visible
2097
+ * read, and a wrapper that only forwards would be a second name for it.
2098
+ */
2099
+ confirmed<P extends Projection<AppModel, any>>(projection: P): P;
1756
2100
  /**
1757
2101
  * The plan run through `RemoteClient` and reduced into the Model: the
1758
2102
  * projection's pending queries first, then the fields it lacks (the pages'
@@ -1766,8 +2110,21 @@ export interface RemoteDomain<AppModel, Store extends RemoteModel, Entities exte
1766
2110
  * mutation sequence unless `options.requestId` is given.
1767
2111
  */
1768
2112
  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>;
2113
+ /**
2114
+ * What Remote knows of a mutation `mutate` started, by its request id:
2115
+ * pending, applied, or failed with the error the server or transport gave.
2116
+ */
2117
+ mutation(model: AppModel, requestId: string): MutationStatus;
1769
2118
  /** `updateRemote` on the bound slice: reduces one of Remote's Messages, as `RemoteMessage` or as the application's union constructs it. */
1770
2119
  reduce(model: AppModel, message: RemoteMessage | RemoteMessageInput): AppModel;
2120
+ /**
2121
+ * How this domain joins an assembly: it routes Remote's Messages into
2122
+ * `reduce`, brings its Subscriptions and contract, and requires
2123
+ * `RemoteClient` from the runtime's resources Layer. One assembly holds at
2124
+ * most one Remote wiring: every domain claims the same tags, and routing
2125
+ * takes the first claimant.
2126
+ */
2127
+ wiring: <const Active extends Readonly<Record<string, ActiveSurface<AppModel> | Surface<AppModel, any, any, void>>>>(active: Active, options?: SubscriptionsOptions) => RemoteWiring<AppModel>;
1771
2128
  /** `Remote.inspect` of the bound slice. */
1772
2129
  inspect(model: AppModel): RemoteInspection;
1773
2130
  }
@@ -1789,7 +2146,7 @@ export type QueryWindowOptions = {
1789
2146
  };
1790
2147
  export type QueryOptions<Value, Entity extends string, Of extends string = Entity> = {
1791
2148
  /** What to read of each item: a selection of the query's entity (`Of`). */
1792
- readonly select: Selection<Value, Entity, 'entity'> & SelectsEntity<Entity, Of>;
2149
+ readonly select: EntitySelection<Value, Entity> & SelectsEntity<Entity, Of>;
1793
2150
  } & QueryWindowOptions;
1794
2151
  /** A query connection read as a `Page` of selected items; `ref` is the connection with its first window. */
1795
2152
  export interface QueryProjection<AppModel, Value, Name extends string, Input> extends Projection<AppModel, RemoteData<Page<Value>>> {
@@ -1835,7 +2192,11 @@ declare const PlannedQuery: Schema.Struct<{
1835
2192
  export interface ReadDependencies {
1836
2193
  readonly requirements: ReadonlyArray<Requirement>;
1837
2194
  readonly queries: ReadonlyArray<Schema.Schema.Type<typeof PlannedQuery>>;
1838
- /** The Model's requested refresh generation: a refresh restarts the entry. */
2195
+ /**
2196
+ * The highest generation the fields this entry reads were refreshed at: a
2197
+ * refresh of any of them restarts the entry, and a refresh of anything else
2198
+ * leaves it running.
2199
+ */
1839
2200
  readonly refresh: number;
1840
2201
  }
1841
2202
  export declare const Remote: {
@@ -1899,6 +2260,10 @@ export declare const Remote: {
1899
2260
  readonly values: Schema.$Record<Schema.String, Schema.Unknown>;
1900
2261
  }>>;
1901
2262
  connections: Schema.optional<Schema.$Array<Schema.Unknown>>;
2263
+ deleted: Schema.optional<Schema.$Array<Schema.Struct<{
2264
+ readonly entity: Schema.String;
2265
+ readonly id: Schema.String;
2266
+ }>>>;
1902
2267
  };
1903
2268
  MutationFailed: {
1904
2269
  requestId: Schema.String;
@@ -1907,6 +2272,13 @@ export declare const Remote: {
1907
2272
  readonly message: Schema.String;
1908
2273
  }>;
1909
2274
  };
2275
+ OverlayShown: {
2276
+ id: Schema.String;
2277
+ optimistic: Schema.$Array<Schema.Unknown>;
2278
+ };
2279
+ OverlayLifted: {
2280
+ id: Schema.String;
2281
+ };
1910
2282
  LiveReceived: {
1911
2283
  stream: Schema.String;
1912
2284
  event: Schema.Unknown;
@@ -1946,7 +2318,7 @@ export declare const Remote: {
1946
2318
  * in one step; the result carries the application-facing operations. The
1947
2319
  * descriptor alone is `Remote.define`, the binding alone `Remote.at`.
1948
2320
  */
1949
- 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: {
2321
+ 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: {
1950
2322
  readonly model: ModelRef<AppModel, Store>;
1951
2323
  readonly entities: Entities;
1952
2324
  readonly queries?: Queries;
@@ -1957,7 +2329,7 @@ export declare const Remote: {
1957
2329
  * mutations, plus the submodel. For a domain reused across applications or
1958
2330
  * bound in a test; `Remote.make` is the one-step form.
1959
2331
  */
1960
- 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: {
2332
+ 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: {
1961
2333
  readonly entities: Entities;
1962
2334
  readonly queries?: Queries;
1963
2335
  readonly mutations?: Mutations;
@@ -1967,7 +2339,7 @@ export declare const Remote: {
1967
2339
  * registered entity names are carried on the returned value, so `Remote.select`
1968
2340
  * rejects a selection for an entity this domain never declared.
1969
2341
  */
1970
- 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]>>;
2342
+ 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]>>;
1971
2343
  /**
1972
2344
  * A Projection node that reads a `RemoteData` value out of the store. The id
1973
2345
  * is supplied by the caller, usually from a Surface's params. The assembled
@@ -1975,7 +2347,7 @@ export declare const Remote: {
1975
2347
  * as `Failed` instead of being asserted into `Value`. A present value with a
1976
2348
  * stale field reads as `Refreshing`: an observer is refetching it.
1977
2349
  */
1978
- 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>>;
2350
+ 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>>;
1979
2351
  /**
1980
2352
  * The pure plan for a projection against a Model: the requirements its
1981
2353
  * remote store does not satisfy, under `options` (freshness, force). A
@@ -1993,6 +2365,12 @@ export declare const Remote: {
1993
2365
  * has not changed.
1994
2366
  */
1995
2367
  storeOf: <AppModel, Store extends RemoteModel>(bound: BoundRemote<AppModel, Store>, model: AppModel) => EntityStore;
2368
+ /**
2369
+ * The projection read against the server-derived store alone: the same
2370
+ * requirements, planned the same way, with the pending optimistic layers and
2371
+ * connection overlays left off. See the bound `Remote.confirmed`.
2372
+ */
2373
+ confirmed: <AppModel, Store extends RemoteModel, P extends Projection<AppModel, any>>(bound: BoundRemote<AppModel, Store>, projection: P) => P;
1996
2374
  /**
1997
2375
  * Executes the plan against the `RemoteClient` and returns a new store. Used
1998
2376
  * for SSR route prefetch, hover prefetch, and tests. Never called during render.
@@ -2098,6 +2476,10 @@ export declare const Remote: {
2098
2476
  };
2099
2477
  }[];
2100
2478
  connections: ConnectionChange[];
2479
+ deleted: readonly {
2480
+ readonly entity: string;
2481
+ readonly id: string;
2482
+ }[];
2101
2483
  }, RemoteMutationError, RemoteClient>;
2102
2484
  /**
2103
2485
  * Runs a mutation and reconciles its patches into a `RemoteModel` in one step,