foldkit-remote 0.18.1 → 0.20.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.
@@ -1,14 +1,14 @@
1
1
  import { Context, Data, Deferred, Duration, Effect, Layer, Match, Option, Predicate, Record, Request, RequestResolver, Result, Schema, SchemaAST, SchemaGetter, Stream } from "effect";
2
2
  import { KeyValueStore } from "effect/persistence";
3
3
  import * as Domain from "foldkit-entity";
4
- import { Entity, Expr, Query, QueryEvaluateError, ReadFilter, SchemaShape, SelectionTypeId, Write, compareRows, dependenciesOf, evaluate } from "foldkit-entity";
4
+ import { Entity, Expr, Operators, Query, QueryEvaluateError, ReadFilter, SchemaShape, SelectionTypeId, Write, compareRows, dependenciesOf, evaluate } from "foldkit-entity";
5
5
  import { mapMessage } from "foldkit/command";
6
6
  import { defineMessageUnion } from "foldkit/message";
7
7
  import * as Subscription from "foldkit/subscription";
8
8
  import { Metadata } from "foldkit-surface";
9
9
  import { Rpc, RpcGroup } from "effect/rpc";
10
10
  import { defineTaggedUnion } from "foldkit/schema";
11
- //#region src/requirement.ts
11
+ // src/requirement.ts
12
12
  /**
13
13
  * What a Remote Projection needs from the server: entity slices and query
14
14
  * connections. They ride on `Projection.metadata` under Remote's own keys, so
@@ -110,8 +110,7 @@ const RemoteConnections = Metadata.key("remote.connection", {
110
110
  const requirementsOf = (projection) => RemoteRequirements.get(projection.metadata);
111
111
  /** The query connections a Projection carries. */
112
112
  const connectionsOf = (projection) => RemoteConnections.get(projection.metadata);
113
- //#endregion
114
- //#region src/data.ts
113
+ // src/data.ts
115
114
  /**
116
115
  * Whether two values the server sent are the same data: equal primitives, or
117
116
  * arrays and plain objects whose entries are. Anything else is compared by
@@ -129,8 +128,7 @@ const isPlain = (value) => {
129
128
  const prototype = Object.getPrototypeOf(value);
130
129
  return prototype === Object.prototype || prototype === null;
131
130
  };
132
- //#endregion
133
- //#region src/relation.ts
131
+ // src/relation.ts
134
132
  /**
135
133
  * Relation values on the wire and in the store: a ref key (`"Entity:id"`), a
136
134
  * nullable ref key, an array of ref keys, or a page of ref keys. The planner
@@ -218,8 +216,7 @@ const shapeOf = (ast, nullable) => {
218
216
  }
219
217
  }
220
218
  };
221
- //#endregion
222
- //#region src/store.ts
219
+ // src/store.ts
223
220
  /**
224
221
  * The pure entity store: values, per-field presence, staleness, and tombstones.
225
222
  *
@@ -406,8 +403,7 @@ const missingFields = (store, key, fields, windows) => {
406
403
  return requested !== void 0 && stored !== void 0 && stored !== "" && stored !== requested;
407
404
  });
408
405
  };
409
- //#endregion
410
- //#region src/mutation.ts
406
+ // src/mutation.ts
411
407
  /**
412
408
  * Mutation status and idempotent reconciliation.
413
409
  *
@@ -420,6 +416,7 @@ const emptyMutationState = {
420
416
  applied: /* @__PURE__ */ new Set(),
421
417
  failed: /* @__PURE__ */ new Set(),
422
418
  errors: /* @__PURE__ */ new Map(),
419
+ operations: /* @__PURE__ */ new Map(),
423
420
  sequence: 0
424
421
  };
425
422
  /**
@@ -442,17 +439,20 @@ const beginMutation = (state, requestId) => ({
442
439
  pending: /* @__PURE__ */ new Set([...state.pending, requestId]),
443
440
  sequence: state.sequence + 1
444
441
  });
445
- const failMutation = (state, requestId, error) => {
442
+ const failMutation = (state, requestId, error, operation) => {
446
443
  const pending = new Set(state.pending);
447
444
  pending.delete(requestId);
448
445
  const failed = remember(state.failed, requestId);
449
446
  const errors = new Map([...state.errors, [requestId, error]]);
447
+ const operations = new Map([...state.operations, [requestId, operation]]);
450
448
  for (const id of errors.keys()) if (!failed.has(id)) errors.delete(id);
449
+ for (const id of operations.keys()) if (!failed.has(id)) operations.delete(id);
451
450
  return {
452
451
  ...state,
453
452
  pending,
454
453
  failed,
455
- errors
454
+ errors,
455
+ operations
456
456
  };
457
457
  };
458
458
  const mutationStatus = (state, requestId) => {
@@ -487,6 +487,23 @@ const reconcileMutation = (store, state, requestId, answer) => {
487
487
  };
488
488
  };
489
489
  const conflict = Schema.TaggedStruct("Conflict", {});
490
+ const unmet = Schema.TaggedStruct("Unmet", {});
491
+ /**
492
+ * The row the write would leave breaks one of its Entity's invariants: which
493
+ * one, what to tell the author, and the fields to show it beside. None and
494
+ * empty when the invariant reads a member hidden from whoever asked.
495
+ */
496
+ const invalid = Schema.TaggedStruct("Invalid", {
497
+ rule: Schema.OptionFromNullOr(Schema.String),
498
+ message: Schema.String,
499
+ path: Schema.Array(Schema.String)
500
+ });
501
+ const conflictOrInvalid = Schema.Union([conflict, invalid]);
502
+ const conflictUnmetOrInvalid = Schema.Union([
503
+ conflict,
504
+ unmet,
505
+ invalid
506
+ ]);
490
507
  const anyField = Schema.TaggedStruct("Field", {
491
508
  key: Schema.String,
492
509
  reason: Schema.Unknown
@@ -500,10 +517,24 @@ const Refusal = {
500
517
  }),
501
518
  /** The row moved on since the client read it; the author decides what wins. */
502
519
  conflict,
520
+ /** The row does not hold what the write's `when` asks of it, where it would commit. */
521
+ unmet,
522
+ /** The row the write would leave breaks an invariant of its Entity. */
523
+ invalid,
503
524
  /** Whether a refusal, of whatever mutation, is a `Refusal.field`. */
504
525
  isField: Schema.is(anyField),
505
526
  /** Whether a refusal, of whatever mutation, is `Refusal.conflict`. */
506
- isConflict: Schema.is(conflict)
527
+ isConflict: Schema.is(conflict),
528
+ /** Whether a refusal, of whatever mutation, is `Refusal.unmet`. */
529
+ isUnmet: Schema.is(unmet),
530
+ /** Whether a refusal, of whatever mutation, is `Refusal.invalid`. */
531
+ isInvalid: Schema.is(invalid),
532
+ /**
533
+ * Whether a refusal is `Refusal.invalid` naming this invariant: the one
534
+ * `Entity.invariant` returned, or one `Entity.invariants` reads. An invariant
535
+ * over a member hidden from the asker names none, so it matches nothing.
536
+ */
537
+ isInvalidBy: (refusal, invariant) => Schema.is(invalid)(refusal) && Option.contains(refusal.rule, invariant.id)
507
538
  };
508
539
  /** The codec itself, or a `Schema.Struct` over the fields. */
509
540
  const schemaOf = (shape) => Schema.isSchema(shape) ? shape : Schema.Struct(shape);
@@ -525,11 +556,18 @@ const patchOfWrite = (bound) => ({
525
556
  /**
526
557
  * What a declared write shows before the server answers: an update's or an
527
558
  * insert's row as a patch (an update's only for the keys named, when some
528
- * are). A delete shows nothing, since no operation removes a row from every
559
+ * are), and an update's increments as amounts over the value the store holds. A delete shows nothing, since no operation removes a row from every
529
560
  * list it is in; its answer does.
530
561
  */
531
562
  const optimisticOfWrite = (write, input, keys) => Match.value(write).pipe(Match.tagsExhaustive({
532
- Update: () => [patchOfWrite(Write.bind(write, input, keys))],
563
+ Update: () => {
564
+ const bound = Write.bind(write, input, keys);
565
+ const patch = patchOfWrite(bound);
566
+ return [Object.keys(bound.increments).length === 0 ? patch : {
567
+ ...patch,
568
+ adds: bound.increments
569
+ }];
570
+ },
533
571
  Insert: () => {
534
572
  const patch = patchOfWrite(Write.bind(write, input));
535
573
  return [{
@@ -553,13 +591,14 @@ const Mutation = {
553
591
  * A mutation that is a declared `Write` (`update`, `insert` or `delete`): its
554
592
  * input is the write's, and it answers nothing but the row it changed, as a
555
593
  * patch, or its deletion. It may be refused as a conflict, for a write that
556
- * `expect`s a revision the row has moved past.
594
+ * `expect`s a revision the row has moved past, for a write with a `when` as
595
+ * unmet, and as invalid when the row it would leave breaks an invariant.
557
596
  */
558
597
  write: (name, write) => ({
559
598
  name,
560
599
  Input: write.input.schema,
561
600
  Output: Schema.Struct({}),
562
- Refusal: Refusal.conflict,
601
+ Refusal: Option.isSome(write.when) ? conflictUnmetOrInvalid : conflictOrInvalid,
563
602
  write
564
603
  }),
565
604
  make: (name, config) => ({
@@ -569,8 +608,7 @@ const Mutation = {
569
608
  Refusal: config.Refusal ?? Schema.Never
570
609
  })
571
610
  };
572
- //#endregion
573
- //#region src/query.ts
611
+ // src/query.ts
574
612
  /**
575
613
  * Queries and connections. A connection's identity is its descriptor plus the
576
614
  * canonical encoded filter/sort input — **never** the pagination window, so
@@ -712,8 +750,7 @@ const Query$1 = {
712
750
  }
713
751
  })
714
752
  };
715
- //#endregion
716
- //#region src/wire.ts
753
+ // src/wire.ts
717
754
  /**
718
755
  * The Remote wire: Effect RPC semantics over `effect/rpc`. Remote owns
719
756
  * the message shapes; Effect owns the transport. `Make`ing reads batch, mutations
@@ -822,9 +859,21 @@ const ReadBatchResult = Schema.Struct({
822
859
  entities: Schema.Array(NormalizedEntity),
823
860
  settled: Schema.Array(SettledFields)
824
861
  });
862
+ /**
863
+ * One operation's identity across every client: minted where it is first sent
864
+ * and sent again with each retry of it. Bounded, since a server keys a record
865
+ * of the write by it.
866
+ */
867
+ const OperationId = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(128), Schema.isPattern(/^[A-Za-z0-9:._-]+$/));
825
868
  const MutationRequest = Schema.Struct({
826
- /** Stable across transport retries so a mutation is not applied twice. */
869
+ /**
870
+ * This client's id for the request, the same on each retry of it. It is
871
+ * unique within one client's Model only (a counter there), so it names a
872
+ * request to that client; `operation` names it to a server.
873
+ */
827
874
  requestId: Schema.String,
875
+ /** The operation's identity across clients: what a server keys a record of the write by. */
876
+ operation: Schema.optional(OperationId),
828
877
  mutation: Schema.String,
829
878
  input: Schema.Unknown,
830
879
  /** For a mutation that is a `Write`: the input keys to write, when not all of them. */
@@ -972,8 +1021,7 @@ const QueryRpc = Rpc.make("FoldkitRemoteQuery", {
972
1021
  error: Schema.Union([RemoteQueryError, RemoteUnauthenticated])
973
1022
  });
974
1023
  const RemoteRpc = RpcGroup.make(Read, Mutate, QueryRpc, Live);
975
- //#endregion
976
- //#region src/coalesce.ts
1024
+ // src/coalesce.ts
977
1025
  /**
978
1026
  * Read coalescing: every requirement a client asks for goes through one
979
1027
  * `RequestResolver`, so requirements issued together become one `ReadBatch`
@@ -1097,8 +1145,7 @@ const coalesceReads = (read, options = {}) => Effect.gen(function* () {
1097
1145
  };
1098
1146
  }));
1099
1147
  });
1100
- //#endregion
1101
- //#region src/client.ts
1148
+ // src/client.ts
1102
1149
  /**
1103
1150
  * The transport seam: the `RemoteClient` Effect service, the RPC client it is
1104
1151
  * built from, the wire-to-client reconstructions, and the mutation call.
@@ -1198,18 +1245,28 @@ const coalescedLayer = (layer, options = {}) => Layer.effect(RemoteClient, Effec
1198
1245
  };
1199
1246
  })).pipe(Layer.provide(layer));
1200
1247
  /**
1248
+ * A new operation's identity: random, so unique across clients and reloads.
1249
+ * `randomUUID` exists only in a secure context, so a page served over plain
1250
+ * HTTP draws 128 random bits from `getRandomValues`, which exists in all.
1251
+ */
1252
+ const mintOperation = () => typeof globalThis.crypto.randomUUID === "function" ? globalThis.crypto.randomUUID() : Array.from(globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
1253
+ /**
1201
1254
  * `Remote.mutate` as a standalone effect, so `Remote.mutateInto` can reuse it
1202
1255
  * without the object literal referencing itself.
1203
1256
  */
1204
- const mutateRemote = Effect.fn("Remote.mutate")(function* (mutation, input, requestId, keys) {
1257
+ const mutateRemote = Effect.fn("Remote.mutate")(function* (mutation, input, requestId, options = {}) {
1258
+ const { keys } = options;
1259
+ const operation = options.operation ?? (yield* Effect.sync(mintOperation));
1205
1260
  yield* Effect.annotateCurrentSpan({
1206
1261
  mutation: mutation.name,
1207
- requestId
1262
+ requestId,
1263
+ operation
1208
1264
  });
1209
1265
  const client = yield* RemoteClient;
1210
1266
  const encoded = yield* Schema.encodeUnknownEffect(mutation.Input)(input).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(new RemoteMutationError({ message: error.message }))));
1211
1267
  const result = yield* client.mutate({
1212
1268
  requestId,
1269
+ operation,
1213
1270
  mutation: mutation.name,
1214
1271
  input: encoded,
1215
1272
  ...keys === void 0 ? {} : { keys }
@@ -1221,8 +1278,7 @@ const mutateRemote = Effect.fn("Remote.mutate")(function* (mutation, input, requ
1221
1278
  deleted: result.deleted ?? []
1222
1279
  };
1223
1280
  });
1224
- //#endregion
1225
- //#region src/connection.ts
1281
+ // src/connection.ts
1226
1282
  /**
1227
1283
  * The pure connection model: an ordered normalized structure of edges with
1228
1284
  * explicit known boundaries. Pages, live events, and optimistic inserts are all
@@ -1385,8 +1441,7 @@ const hasNext = (connection) => {
1385
1441
  };
1386
1442
  /** A connection with more than one segment has an explicit unknown gap. */
1387
1443
  const isGapped = (connection) => connection.segments.length > 1;
1388
- //#endregion
1389
- //#region src/selection.ts
1444
+ // src/selection.ts
1390
1445
  /**
1391
1446
  * Selections: the fields a Surface picks of an entity (nested through
1392
1447
  * relations, paged through connections), the requirement graph they imply,
@@ -1568,8 +1623,7 @@ const assembleRelation = (store, value, relation) => {
1568
1623
  refreshing
1569
1624
  };
1570
1625
  };
1571
- //#endregion
1572
- //#region src/entity.ts
1626
+ // src/entity.ts
1573
1627
  /**
1574
1628
  * Entities: the descriptor an application declares, refs, ref pages, and
1575
1629
  * patches, with the codecs that carry refs on the wire.
@@ -1657,8 +1711,7 @@ const Entity$1 = {
1657
1711
  values: patch
1658
1712
  })
1659
1713
  };
1660
- //#endregion
1661
- //#region src/placement.ts
1714
+ // src/placement.ts
1662
1715
  /**
1663
1716
  * Where one row falls in a loaded list, by the list's own declared order:
1664
1717
  * the decidable half of placing a row instead of fetching the list again.
@@ -1675,16 +1728,14 @@ const Entity$1 = {
1675
1728
  */
1676
1729
  const RowPlace = Data.taggedEnum();
1677
1730
  /**
1678
- * The values a row holds of the fields an order reads, or none when it lacks
1679
- * one. An `id` no Selection stored is its key's, when the id is stored as
1731
+ * The values a row holds of the fields an order reads, a call's arguments
1732
+ * included, or none when it lacks one. An `id` no Selection stored is its key's, when the id is stored as
1680
1733
  * text as a key holds it, so the id tie-break every order ends on does not
1681
1734
  * make such a row unplaceable; a number id is never compared as text.
1682
1735
  */
1683
1736
  const keysOf = (store, key, id, idIsText, terms) => {
1684
1737
  const values = Object.create(null);
1685
- for (const term of terms) {
1686
- if (term.expr._tag !== "Field") return Option.none();
1687
- const field = term.expr.key;
1738
+ for (const { key: field } of dependenciesOf(...terms).fields) {
1688
1739
  const stored = readField(store, key, field);
1689
1740
  const value = field === "id" && Option.isNone(stored) && idIsText ? id : stored;
1690
1741
  if (Option.isNone(value)) return Option.none();
@@ -1694,12 +1745,12 @@ const keysOf = (store, key, id, idIsText, terms) => {
1694
1745
  };
1695
1746
  /**
1696
1747
  * Where the row stored under `key` falls in `connection`, by `body`'s order
1697
- * for `input` (encoded, as a connection's identity carries it). The row's own
1698
- * edge, if the list holds it, is left out: placing a row that moved asks
1699
- * where it goes now.
1748
+ * for `input` (encoded, as a connection's identity carries it), a call in it
1749
+ * run by `operators`. The row's own edge, if the list holds it, is left out:
1750
+ * placing a row that moved asks where it goes now.
1700
1751
  */
1701
- const placeIn = (store, connection, body, input, key) => {
1702
- const placement = Query.placement(body, input);
1752
+ const placeIn = (store, connection, body, input, key, operators) => {
1753
+ const placement = Query.placement(body, input, { operators });
1703
1754
  if (placement._tag === "NotPlaceable") return RowPlace.Unknown({ reason: placement.reason });
1704
1755
  const terms = Query.orderFor(body, input);
1705
1756
  const prefix = `${body.entity.name}:`;
@@ -1711,7 +1762,10 @@ const placeIn = (store, connection, body, input, key) => {
1711
1762
  /** Negative when the row sorts before the edge; none when the edge cannot be compared. */
1712
1763
  const against = (edge) => Option.flatMap(keysOf(store, entityKey(edge.ref.entity, edge.ref.id), Option.some(edge.ref.id), idIsText, terms), (values) => {
1713
1764
  try {
1714
- return Option.some(compareRows(terms, row.value, values, body.entity.name));
1765
+ return Option.some(compareRows(terms, row.value, values, body.entity.name, {
1766
+ input,
1767
+ operators
1768
+ }));
1715
1769
  } catch {
1716
1770
  return Option.none();
1717
1771
  }
@@ -1767,8 +1821,7 @@ const withEdge = (connection, added, place) => ({
1767
1821
  };
1768
1822
  })
1769
1823
  });
1770
- //#endregion
1771
- //#region src/matching.ts
1824
+ // src/matching.ts
1772
1825
  /**
1773
1826
  * Running a query body against the rows the client already holds.
1774
1827
  *
@@ -1855,7 +1908,7 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
1855
1908
  });
1856
1909
  }
1857
1910
  return {
1858
- matched: evaluate(body, encoded, rows).map((row) => row.__key),
1911
+ matched: evaluate(body, encoded, rows, { operators: options.operators }).map((row) => row.__key),
1859
1912
  skipped
1860
1913
  };
1861
1914
  };
@@ -1868,7 +1921,7 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
1868
1921
  * asymmetry with `matching`, which takes a decoded input, is the shape of the
1869
1922
  * two real callers rather than an oversight.
1870
1923
  */
1871
- const belongsEncoded = (store, descriptor, encoded, key) => {
1924
+ const belongsEncoded = (store, descriptor, encoded, key, operators) => {
1872
1925
  const entry = store[key];
1873
1926
  if (entry === void 0) return "unknown";
1874
1927
  if (entry.tombstone) return "no";
@@ -1876,7 +1929,10 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
1876
1929
  if (body !== void 0 && decidableOn(body).some((field) => entry.stale.has(field))) return "unknown";
1877
1930
  let judged;
1878
1931
  try {
1879
- judged = matchingEncoded(store, descriptor, encoded, { among: [key] });
1932
+ judged = matchingEncoded(store, descriptor, encoded, {
1933
+ among: [key],
1934
+ operators
1935
+ });
1880
1936
  } catch (error) {
1881
1937
  if (error instanceof QueryEvaluateError) return "unknown";
1882
1938
  throw error;
@@ -1885,8 +1941,7 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
1885
1941
  if (judged.skipped.includes(key)) return "unknown";
1886
1942
  return "no";
1887
1943
  };
1888
- //#endregion
1889
- //#region src/impact.ts
1944
+ // src/impact.ts
1890
1945
  /**
1891
1946
  * What a write did to the lists the client holds: given one change and one
1892
1947
  * loaded connection, whether the connection is still right as it stands.
@@ -1949,7 +2004,7 @@ const sameOrder = (left, right) => left.segments.length === right.segments.lengt
1949
2004
  * What `change` does to `connection`, judged against `store`, the store after
1950
2005
  * the write.
1951
2006
  */
1952
- const impactOn = (connection, store, change) => {
2007
+ const impactOn = (connection, store, change, operators) => {
1953
2008
  const { descriptor } = connection;
1954
2009
  const body = descriptor.body;
1955
2010
  if ((body?.entity.name ?? descriptor.Result.entity) !== change.entity) return kept;
@@ -1975,7 +2030,7 @@ const impactOn = (connection, store, change) => {
1975
2030
  const refilters = touches(roles.predicate);
1976
2031
  const unloaded = hasPrevious(pages) || hasNext(pages) || isGapped(pages);
1977
2032
  if (!(held && reorders) && !refilters && !(!held && (created || reorders && unloaded))) return kept;
1978
- const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key);
2033
+ const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key, operators);
1979
2034
  if (belongs === "unknown") return Impact.Invalidated({ reason: `${key} changed a field "${descriptor.name}" filters on, and the client cannot judge it` });
1980
2035
  if (!held && belongs === "no") return kept;
1981
2036
  if (held && belongs === "yes" && !reorders) return kept;
@@ -1990,7 +2045,7 @@ const impactOn = (connection, store, change) => {
1990
2045
  }), place);
1991
2046
  return sameOrder(pages, next) ? kept : Impact.Placed({ connection: next });
1992
2047
  };
1993
- return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key), {
2048
+ return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key, operators), {
1994
2049
  Before: placedAt,
1995
2050
  End: placedAt,
1996
2051
  Outside: () => held ? Impact.Placed({ connection: withoutEdge(pages, key) }) : kept,
@@ -1999,8 +2054,7 @@ const impactOn = (connection, store, change) => {
1999
2054
  }
2000
2055
  });
2001
2056
  };
2002
- //#endregion
2003
- //#region src/inspect.ts
2057
+ // src/inspect.ts
2004
2058
  const inspectEntry = (key, entry) => ({
2005
2059
  key,
2006
2060
  present: [...entry.present],
@@ -2030,8 +2084,7 @@ const inspectEntity = (model, key) => {
2030
2084
  const entry = model.entities[key];
2031
2085
  return entry === void 0 ? void 0 : inspectEntry(key, entry);
2032
2086
  };
2033
- //#endregion
2034
- //#region src/optimistic.ts
2087
+ // src/optimistic.ts
2035
2088
  /**
2036
2089
  * Optimistic layers. Pending changes are held as ordered layers over a base
2037
2090
  * store and as overlays over a connection; the visible value is recomputed, never
@@ -2137,7 +2190,7 @@ const removeOverlay = (optimistic, id) => {
2137
2190
  * entity only a request holds (a temporary id) is not the server's to age, and
2138
2191
  * is dated `Infinity`, so freshness never plans or times it.
2139
2192
  */
2140
- const visibleStore = (base, optimistic) => writeEntities(base, optimistic.layers.flatMap((layer) => layer.patches.map((patch) => {
2193
+ const visibleStore = (base, optimistic) => writeEntities(base, resolvedPatches(base, optimistic).map((patch) => {
2141
2194
  const key = entityKey(patch.entity, patch.id);
2142
2195
  const under = base[key];
2143
2196
  return {
@@ -2145,7 +2198,34 @@ const visibleStore = (base, optimistic) => writeEntities(base, optimistic.layers
2145
2198
  values: patch.values,
2146
2199
  updatedAt: under === void 0 || under.tombstone ? Infinity : under.updatedAt
2147
2200
  };
2148
- })));
2201
+ }));
2202
+ /**
2203
+ * Every pending patch in order, each amount added to the value under it: the
2204
+ * store's, or an earlier layer's. A prediction, so only over a number the
2205
+ * client holds: a field it has not read, or holds as anything else, keeps
2206
+ * what it shows until the server answers with the sum.
2207
+ */
2208
+ const resolvedPatches = (base, optimistic) => {
2209
+ const shown = /* @__PURE__ */ new Map();
2210
+ return optimistic.layers.flatMap((layer) => layer.patches.map(({ adds, ...patch }) => {
2211
+ const key = entityKey(patch.entity, patch.id);
2212
+ const earlier = shown.get(key) ?? {};
2213
+ const values = { ...patch.values };
2214
+ const under = base[key];
2215
+ const valueUnder = (field) => Object.hasOwn(earlier, field) ? Option.some(earlier[field]) : Option.fromUndefinedOr(under?.values[field]);
2216
+ for (const [field, amount] of Object.entries(adds ?? {})) Option.map(Option.filter(valueUnder(field), Predicate.isNumber), (current) => {
2217
+ values[field] = current + amount;
2218
+ });
2219
+ shown.set(key, {
2220
+ ...earlier,
2221
+ ...values
2222
+ });
2223
+ return {
2224
+ ...patch,
2225
+ values
2226
+ };
2227
+ }));
2228
+ };
2149
2229
  /**
2150
2230
  * A fresh page is newer than any settled overlay it covers: an edge the page
2151
2231
  * carries no longer needs an insert overlay, and a `remove` overlay hiding it
@@ -2219,8 +2299,7 @@ const visibleItems = (connection, connectionId, overlays, store) => {
2219
2299
  ...take("append")
2220
2300
  ];
2221
2301
  };
2222
- //#endregion
2223
- //#region src/live.ts
2302
+ // src/live.ts
2224
2303
  const emptyLiveState = {
2225
2304
  cursor: 0,
2226
2305
  boundary: {}
@@ -2340,8 +2419,7 @@ const applyConnectionEvent = (state, optimistic, event, policy = {}) => {
2340
2419
  const liveHasPrevious = (connection, state, connectionId) => hasPrevious(connection) || (state.boundary[connectionId]?.before ?? 0) > 0;
2341
2420
  /** `hasNext` accounting for edges recorded outside the loaded boundary. */
2342
2421
  const liveHasNext = (connection, state, connectionId) => hasNext(connection) || (state.boundary[connectionId]?.after ?? 0) > 0;
2343
- //#endregion
2344
- //#region src/plan.ts
2422
+ // src/plan.ts
2345
2423
  /**
2346
2424
  * The pure requirement planner.
2347
2425
  *
@@ -2434,8 +2512,7 @@ const plan = (store, requirements, options = {}) => {
2434
2512
  const nested = followed.length === 0 ? [] : plan(store, followed, options);
2435
2513
  return [...Requirement.merge([...planned, ...nested])].sort((a, b) => entityKey(a.entity, a.id) < entityKey(b.entity, b.id) ? -1 : 1);
2436
2514
  };
2437
- //#endregion
2438
- //#region src/retain.ts
2515
+ // src/retain.ts
2439
2516
  /**
2440
2517
  * The entity keys the roots reach: each root entity, the targets its retained
2441
2518
  * fields refer to, and recursively the targets a nested relation selects.
@@ -2507,8 +2584,7 @@ const keptOf = (record, keep) => {
2507
2584
  const kept = entries.filter(([key]) => keep(key));
2508
2585
  return kept.length === entries.length ? record : Object.fromEntries(kept);
2509
2586
  };
2510
- //#endregion
2511
- //#region src/persistence.ts
2587
+ // src/persistence.ts
2512
2588
  /**
2513
2589
  * Remote cache persistence: a snapshot of the entity store and nothing else.
2514
2590
  * Runtime state (connections' live cursors, optimistic layers, the mutation
@@ -2705,8 +2781,7 @@ const RemotePersistence = {
2705
2781
  return restored;
2706
2782
  })
2707
2783
  };
2708
- //#endregion
2709
- //#region src/remoteData.ts
2784
+ // src/remoteData.ts
2710
2785
  /** `RemoteData`: the state of a value the store may not hold yet. */
2711
2786
  /**
2712
2787
  * The server would not answer who is asking: their session ended or was
@@ -2862,8 +2937,7 @@ const RemoteData = {
2862
2937
  }
2863
2938
  }
2864
2939
  };
2865
- //#endregion
2866
- //#region src/model.ts
2940
+ // src/model.ts
2867
2941
  /**
2868
2942
  * The Remote submodel: the store, connections, mutations, live state, and
2869
2943
  * optimistic layers an application keeps in its Model, the Messages that
@@ -2991,7 +3065,8 @@ const remoteMessageCases = {
2991
3065
  },
2992
3066
  MutationFailed: {
2993
3067
  requestId: Schema.String,
2994
- error: remoteErrorSchema
3068
+ error: remoteErrorSchema,
3069
+ operation: Schema.String
2995
3070
  },
2996
3071
  OverlayShown: {
2997
3072
  id: Schema.String,
@@ -3432,7 +3507,7 @@ const reduceRemote = (model, message) => {
3432
3507
  }
3433
3508
  case "MutationFailed": return {
3434
3509
  ...model,
3435
- mutations: failMutation(model.mutations, message.requestId, message.error),
3510
+ mutations: failMutation(model.mutations, message.requestId, message.error, message.operation),
3436
3511
  optimistic: settleFailure(model.optimistic, message.requestId)
3437
3512
  };
3438
3513
  case "LiveReceived": {
@@ -3749,8 +3824,7 @@ const writeRead = (store, requests, result, now = 0) => {
3749
3824
  }
3750
3825
  return setUnavailable(writeEntities(answered, writes, now), result.settled.map((entry) => [entityKey(entry.entity, entry.id), entry.fields]), true);
3751
3826
  };
3752
- //#endregion
3753
- //#region src/policy.ts
3827
+ // src/policy.ts
3754
3828
  const RemotePolicy = {
3755
3829
  /** Fetch only what the store lacks. */
3756
3830
  cacheFirst: { _tag: "CacheFirst" },
@@ -3779,8 +3853,7 @@ const RemotePolicy = {
3779
3853
  */
3780
3854
  refreshes: (policy) => policy._tag !== "CacheFirst"
3781
3855
  };
3782
- //#endregion
3783
- //#region src/resume.ts
3856
+ // src/resume.ts
3784
3857
  /**
3785
3858
  * What of Remote's state crosses from a server render to the browser.
3786
3859
  *
@@ -3994,8 +4067,7 @@ const resumePart = (domain, options = {}) => ({
3994
4067
  onSuccess: (capture) => Result.succeed(domain.store.set(model, restoreRemote(domain.store.get(model), capture)))
3995
4068
  })
3996
4069
  });
3997
- //#endregion
3998
- //#region src/json.ts
4070
+ // src/json.ts
3999
4071
  /**
4000
4072
  * Remote's three calls as JSON: one request, `{ operation, payload }`, and one
4001
4073
  * answer, `{ result }` or `{ error }`. `RemoteServer.answer` is the other end.
@@ -4100,8 +4172,7 @@ const http = (url, options = {}) => json(async (request) => {
4100
4172
  if (body === notJson) throw new Error(status);
4101
4173
  return body;
4102
4174
  });
4103
- //#endregion
4104
- //#region src/sse.ts
4175
+ // src/sse.ts
4105
4176
  /**
4106
4177
  * Remote live over fetch with SSE framing: the other end of
4107
4178
  * `foldkit-remote-server/fetch`'s live open. One `POST` carries the live
@@ -4221,8 +4292,7 @@ const httpWithLive = (url, options = {}) => ({
4221
4292
  ...http(url, options),
4222
4293
  FoldkitRemoteLive: liveFetch(url, options)
4223
4294
  });
4224
- //#endregion
4225
- //#region src/index.ts
4295
+ // src/index.ts
4226
4296
  /**
4227
4297
  * `foldkit-remote` — normalized application-facing server state.
4228
4298
  *
@@ -4237,7 +4307,11 @@ const explainedDependencies = (dependencies) => ({
4237
4307
  key
4238
4308
  })),
4239
4309
  inputs: dependencies.inputs,
4240
- operations: dependencies.operations
4310
+ operations: dependencies.operations,
4311
+ operators: dependencies.operators.map(({ id, version }) => ({
4312
+ id,
4313
+ version
4314
+ }))
4241
4315
  });
4242
4316
  const descriptorOf = (entity) => Entity.is(entity) ? Entity$1.from(entity) : entity;
4243
4317
  const selectionOf = (selection) => SelectionTypeId in selection ? Selection.from(selection) : selection;
@@ -4264,11 +4338,11 @@ const readContract = (source, shape, window) => {
4264
4338
  * compared with neighbours that hold those fields. What the view reads, and so
4265
4339
  * decodes, stays its Selection.
4266
4340
  */
4267
- const placeableReadContract = (contract, body) => {
4341
+ const placeableReadContract = (contract, body, operators) => {
4268
4342
  if (body === void 0) return contract;
4269
4343
  const { requirement, ref } = contract;
4270
4344
  const encoded = Schema.encodeSync(ref.Input)(ref.input);
4271
- if (Query.placement(body, encoded)._tag !== "Placeable") return contract;
4345
+ if (Query.placement(body, encoded, { operators })._tag !== "Placeable") return contract;
4272
4346
  const missing = Query.dependencies(body).fields.filter((field) => !requirement.select.fields.includes(field.key));
4273
4347
  if (missing.length === 0) return contract;
4274
4348
  return {
@@ -5029,7 +5103,10 @@ const Remote = {
5029
5103
  * in one step; the result carries the application-facing operations. The
5030
5104
  * descriptor alone is `Remote.define`, the binding alone `Remote.at`.
5031
5105
  */
5032
- make: (config) => bindDomain(defineRemote(config), config.model, { verifyPlacement: config.verifyPlacement }),
5106
+ make: (config) => bindDomain(defineRemote(config), config.model, {
5107
+ verifyPlacement: config.verifyPlacement,
5108
+ operators: config.operators
5109
+ }),
5033
5110
  /**
5034
5111
  * Declares a Remote domain without binding it: its entities, queries, and
5035
5112
  * mutations, plus the submodel. For a domain reused across applications or
@@ -5391,6 +5468,7 @@ const failedReadWords = (error) => {
5391
5468
  };
5392
5469
  /** The bound domain: the descriptor, the binding, and the operations over them. */
5393
5470
  const bindDomain = (definition, store, options = {}) => {
5471
+ const operators = options.operators ?? Operators.kernel;
5394
5472
  const bound = bindRemote(definition, store);
5395
5473
  const readers = /* @__PURE__ */ new Map();
5396
5474
  const keptConnections = /* @__PURE__ */ new Set();
@@ -5423,7 +5501,7 @@ const bindDomain = (definition, store, options = {}) => {
5423
5501
  const declared = (descriptor?.Result)?.live;
5424
5502
  if (descriptor?.body === void 0) return declared;
5425
5503
  const encoded = JSON.parse(identity.slice(identity.indexOf("\0") + 1));
5426
- return belongsEncoded(storeOf(bound, model), descriptor, encoded, entityKey(event.edge.ref.entity, event.edge.ref.id)) === "no" ? {
5504
+ return belongsEncoded(storeOf(bound, model), descriptor, encoded, entityKey(event.edge.ref.entity, event.edge.ref.id), operators) === "no" ? {
5427
5505
  prepend: "ignore",
5428
5506
  append: "ignore"
5429
5507
  } : declared;
@@ -5472,7 +5550,7 @@ const bindDomain = (definition, store, options = {}) => {
5472
5550
  ...query.value,
5473
5551
  connection: placed,
5474
5552
  holds
5475
- }, store, change), {
5553
+ }, store, change, operators), {
5476
5554
  Kept: () => placed,
5477
5555
  Placed: ({ connection }) => connection,
5478
5556
  Invalidated: () => placed
@@ -5492,7 +5570,7 @@ const bindDomain = (definition, store, options = {}) => {
5492
5570
  pages,
5493
5571
  layers,
5494
5572
  remote.entities
5495
- ], `placed:${identity}`, () => placedHeld(identity, pages, changesOf({ entities: layers.flatMap((layer) => layer.patches) }, remote.entities), visibleStoreOf(remote.entities, remote.optimistic)));
5573
+ ], `placed:${identity}`, () => placedHeld(identity, pages, changesOf({ entities: resolvedPatches(remote.entities, remote.optimistic) }, remote.entities), visibleStoreOf(remote.entities, remote.optimistic)));
5496
5574
  };
5497
5575
  /**
5498
5576
  * The edges a loaded list shows: its pages with pending edits placed, and
@@ -5535,7 +5613,7 @@ const bindDomain = (definition, store, options = {}) => {
5535
5613
  for (const edge of inserted.values()) {
5536
5614
  if (held.has(edge.key)) continue;
5537
5615
  const key = entityKey(edge.ref.entity, edge.ref.id);
5538
- RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key), {
5616
+ RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key, operators), {
5539
5617
  Before: (place) => void (placed = withEdge(placed, edge, place)),
5540
5618
  End: (place) => void (placed = withEdge(placed, edge, place)),
5541
5619
  Outside: () => void outside.push(edge),
@@ -5624,7 +5702,7 @@ const bindDomain = (definition, store, options = {}) => {
5624
5702
  connection: pages,
5625
5703
  holds
5626
5704
  };
5627
- const after = Impact.$match(impactOn(held, visible, change), {
5705
+ const after = Impact.$match(impactOn(held, visible, change, operators), {
5628
5706
  Kept: () => Option.some(pages),
5629
5707
  Placed: ({ connection }) => Option.some(connection),
5630
5708
  Invalidated: () => Option.none()
@@ -5806,7 +5884,7 @@ const bindDomain = (definition, store, options = {}) => {
5806
5884
  const listed = query.Result.entity;
5807
5885
  if (listed === void 0) throw new Error(`Remote: query "${query.name}" is not a connection over an entity, so it has no page to select`);
5808
5886
  if (select.entity !== listed) throw new Error(`Remote: the selection is of "${select.entity}", but query "${query.name}" lists "${listed}"`);
5809
- const { ref, relation, requirement } = placeableReadContract(readContract(query.ref(input), select, window), query.body);
5887
+ const { ref, relation, requirement } = placeableReadContract(readContract(query.ref(input), select, window), query.body, operators);
5810
5888
  const relationKey = stableStringify(relation);
5811
5889
  const sizeOf = (remote) => windowSize(remote, ref);
5812
5890
  const shown = (remote, connection) => cutToWindow(shownEdges(remote, ref.identity, connection), ref.window, sizeOf(remote));
@@ -6021,7 +6099,10 @@ const bindDomain = (definition, store, options = {}) => {
6021
6099
  const among = (connection === void 0 ? [] : shownEdges(remote, over.ref.identity, connection)).map((edge) => entityKey(edge.ref.entity, edge.ref.id));
6022
6100
  let judged;
6023
6101
  try {
6024
- judged = matching(visible, by, input, { among });
6102
+ judged = matching(visible, by, input, {
6103
+ among,
6104
+ operators
6105
+ });
6025
6106
  } catch (error) {
6026
6107
  if (error instanceof QueryEvaluateError) return {
6027
6108
  items: [],
@@ -6071,6 +6152,7 @@ const bindDomain = (definition, store, options = {}) => {
6071
6152
  const remote = store.get(model);
6072
6153
  const requestId = options.requestId ?? `${bound.contract.name}-${remote.mutations.sequence + 1}`;
6073
6154
  const tempId = `${requestId}.tmp`;
6155
+ const known = Option.fromUndefinedOr(remote.mutations.operations.get(requestId));
6074
6156
  const optimistic = typeof options.optimistic === "function" ? options.optimistic({
6075
6157
  requestId,
6076
6158
  tempId
@@ -6087,11 +6169,15 @@ const bindDomain = (definition, store, options = {}) => {
6087
6169
  command: {
6088
6170
  name: `Remote.mutate(${mutation.name})`,
6089
6171
  args: { requestId },
6090
- effect: mutateRemote(mutation, input, requestId, options.keys).pipe(Effect.match({
6172
+ effect: Effect.flatMap(Effect.sync(() => Option.getOrElse(known, mintOperation)), (operation) => mutateRemote(mutation, input, requestId, {
6173
+ keys: options.keys,
6174
+ operation
6175
+ }).pipe(Effect.match({
6091
6176
  onFailure: (error) => ({
6092
6177
  _tag: "MutationFailed",
6093
6178
  requestId,
6094
- error: remoteError(error)
6179
+ error: remoteError(error),
6180
+ operation
6095
6181
  }),
6096
6182
  onSuccess: (outcome) => ({
6097
6183
  _tag: "MutationSucceeded",
@@ -6101,7 +6187,7 @@ const bindDomain = (definition, store, options = {}) => {
6101
6187
  deleted: outcome.deleted,
6102
6188
  now: (options.now ?? wallClock)()
6103
6189
  })
6104
- }))
6190
+ })))
6105
6191
  }
6106
6192
  };
6107
6193
  },
@@ -6253,7 +6339,6 @@ const pickWindow = (window) => ({
6253
6339
  ...window.after === void 0 ? {} : { after: window.after },
6254
6340
  ...window.before === void 0 ? {} : { before: window.before }
6255
6341
  });
6256
- //#endregion
6257
- export { emptyOptimistic as $, refParts as $n, QueryResult as $t, writeRead as A, schemaOf as An, RemoteClient as At, plan as B, missingFields as Bn, Live as Bt, remoteMessageCases as C, beginMutation as Cn, hasPrevious as Ct, updateRemote as D, optimisticOfWrite as Dn, segment as Dt, retentionRootsSchema as E, mutationStatus as En, merge as Et, REMOTE_CACHE_VERSION as F, hasField as Fn, remoteError as Ft, emptyLiveState as G, tombstone as Gn, MAX_RELATION_DEPTH as Gt, applyConnectionEvent as H, remove as Hn, LiveEdge as Ht, RemotePersistence as I, isFieldStale as In, coalesceQueries as It, ConnectionChange as J, RELATION_ALIAS as Jn, MutationResult as Jt, liveHasNext as K, writeEntities as Kn, Mutate as Kt, gc as L, isFieldUnavailable as Ln, coalesceReads as Lt, RemoteData as M, emptyStore as Mn, connectionChangeOf as Mt, remoteDataSchema as N, entityKey as Nn, liveEventOf as Nt, windowGrowthKey as O, patchOfWrite as On, terminal as Ot, remoteErrorSchema as P, entry as Pn, mutateRemote as Pt, connectionIdentity as Q, isRefPage as Qn, QueryRequest as Qt, reachable as R, isTombstone as Rn, requirementKey as Rt, refreshedAt as S, Refusal as Sn, hasNext as St, remoteModelSchema as T, failMutation as Tn, items as Tt, applyEntityEvent as U, setStale as Un, LiveRequirement as Ut, windowKey as V, readField as Vn, LiveChange as Vt, classifyLive as W, setUnavailable as Wn, MAX_FIELDS_PER_REQUEST as Wt, addOverlay as X, RelationEntityAnnotation as Xn, PageSize as Xt, addLayer as Y, RelationAnnotation as Yn, NormalizedEntity as Yt, beginOptimistic as Z, aliasedField as Zn, QueryEdge as Zt, isRemoteMessage as _, WireBoundary as _n, relationOf as _t, RemoteJsonAnswer as a, ReadRequest as an, RemoteRequirements as ar, visibleItems as at, overlaysOf as b, stableStringify as bn, edge as bt, emptyRefresh as c, RemoteLiveError as cn, requirementsOf as cr, inspectRemote as ct, initialRemoteModel as d, RemoteQueryError as dn, RowPlace as dt, QueryRpc as en, refsIn as er, pruneOverlays as et, invalidateConnections as f, RemoteReadError as fn, placeIn as ft, isQueryLoading as g, WindowSchema as gn, pageSchema as gt, isLoadingThrough as h, SettledFields as hn, assemble as ht, liveFetch as i, ReadBatchResult as in, RemoteConnections as ir, settleSuccess as it, Denied as j, clearStale as jn, coalescedLayer as jt, withRefreshRequested as k, reconcileMutation as kn, unknown as kt, failureOf as l, RemoteMutationError as ln, belongsEncoded as lt, isLoading as m, RemoteUnauthenticated as mn, Selection as mt, RemoteUnsatisfied as n, Read as nn, relationShape as nr, removeOverlay as nt, RemoteJsonRequest as o, RelationRequest as on, Requirement as or, visibleStore as ot, isFieldFailed as p, RemoteRpc as pn, Entity$1 as pt, liveHasPrevious as q, writeEntity as qn, MutationRequest as qt, httpWithLive as r, ReadBatch as rn, targetsOf as rr, settleFailure as rt, RemotePolicy as s, RemoteForbidden as sn, connectionsOf as sr, inspectEntity as st, Remote as t, REMOTE_PROTOCOL_VERSION as tn, relationAlias as tr, removeLayer as tt, forgetRemote as u, RemoteProtocolError as un, matching as ut, noFailures as v, IDENTITY_SEPARATOR as vn, unavailableOf as vt, remoteMessageSchema as w, emptyMutationState as wn, isGapped as wt, refreshIsInFlight as x, Mutation as xn, emptyConnection as xt, onlyOverlaid as y, Query$1 as yn, cursor as yt, deadlineOf as z, markStale as zn, ConnectionChangeSchema as zt };
6342
+ export { emptyOptimistic as $, RelationEntityAnnotation as $n, PageSize as $t, writeRead as A, optimisticOfWrite as An, unknown as At, plan as B, isFieldUnavailable as Bn, requirementKey as Bt, remoteMessageCases as C, stableStringify as Cn, hasNext as Ct, updateRemote as D, emptyMutationState as Dn, merge as Dt, retentionRootsSchema as E, beginMutation as En, items as Et, REMOTE_CACHE_VERSION as F, emptyStore as Fn, mintOperation as Ft, emptyLiveState as G, remove as Gn, LiveRequirement as Gt, applyConnectionEvent as H, markStale as Hn, Live as Ht, RemotePersistence as I, entityKey as In, mutateRemote as It, ConnectionChange as J, tombstone as Jn, Mutate as Jt, liveHasNext as K, setStale as Kn, MAX_FIELDS_PER_REQUEST as Kt, gc as L, entry as Ln, remoteError as Lt, RemoteData as M, reconcileMutation as Mn, coalescedLayer as Mt, remoteDataSchema as N, schemaOf as Nn, connectionChangeOf as Nt, windowGrowthKey as O, failMutation as On, segment as Ot, remoteErrorSchema as P, clearStale as Pn, liveEventOf as Pt, connectionIdentity as Q, RelationAnnotation as Qn, OperationId as Qt, reachable as R, hasField as Rn, coalesceQueries as Rt, refreshedAt as S, Query$1 as Sn, emptyConnection as St, remoteModelSchema as T, Refusal as Tn, isGapped as Tt, applyEntityEvent as U, missingFields as Un, LiveChange as Ut, windowKey as V, isTombstone as Vn, ConnectionChangeSchema as Vt, classifyLive as W, readField as Wn, LiveEdge as Wt, addOverlay as X, writeEntity as Xn, MutationResult as Xt, addLayer as Y, writeEntities as Yn, MutationRequest as Yt, beginOptimistic as Z, RELATION_ALIAS as Zn, NormalizedEntity as Zt, isRemoteMessage as _, RemoteUnauthenticated as _n, pageSchema as _t, RemoteJsonAnswer as a, Read as an, relationShape as ar, settleSuccess as at, overlaysOf as b, WireBoundary as bn, cursor as bt, emptyRefresh as c, ReadRequest as cn, RemoteRequirements as cr, inspectEntity as ct, initialRemoteModel as d, RemoteLiveError as dn, requirementsOf as dr, matching as dt, QueryEdge as en, aliasedField as er, pruneOverlays as et, invalidateConnections as f, RemoteMutationError as fn, RowPlace as ft, isQueryLoading as g, RemoteRpc as gn, assemble as gt, isLoadingThrough as h, RemoteReadError as hn, Selection as ht, liveFetch as i, REMOTE_PROTOCOL_VERSION as in, relationAlias as ir, settleFailure as it, Denied as j, patchOfWrite as jn, RemoteClient as jt, withRefreshRequested as k, mutationStatus as kn, terminal as kt, failureOf as l, RelationRequest as ln, Requirement as lr, inspectRemote as lt, isLoading as m, RemoteQueryError as mn, Entity$1 as mt, RemoteUnsatisfied as n, QueryResult as nn, refParts as nr, removeOverlay as nt, RemoteJsonRequest as o, ReadBatch as on, targetsOf as or, visibleItems as ot, isFieldFailed as p, RemoteProtocolError as pn, placeIn as pt, liveHasPrevious as q, setUnavailable as qn, MAX_RELATION_DEPTH as qt, httpWithLive as r, QueryRpc as rn, refsIn as rr, resolvedPatches as rt, RemotePolicy as s, ReadBatchResult as sn, RemoteConnections as sr, visibleStore as st, Remote as t, QueryRequest as tn, isRefPage as tr, removeLayer as tt, forgetRemote as u, RemoteForbidden as un, connectionsOf as ur, belongsEncoded as ut, noFailures as v, SettledFields as vn, relationOf as vt, remoteMessageSchema as w, Mutation as wn, hasPrevious as wt, refreshIsInFlight as x, IDENTITY_SEPARATOR as xn, edge as xt, onlyOverlaid as y, WindowSchema as yn, unavailableOf as yt, deadlineOf as z, isFieldStale as zn, coalesceReads as zt };
6258
6343
 
6259
- //# sourceMappingURL=src-Cp71fJac.mjs.map
6344
+ //# sourceMappingURL=src-BDqn7Ocr.mjs.map