foldkit-remote 0.19.0 → 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
  *
@@ -612,8 +608,7 @@ const Mutation = {
612
608
  Refusal: config.Refusal ?? Schema.Never
613
609
  })
614
610
  };
615
- //#endregion
616
- //#region src/query.ts
611
+ // src/query.ts
617
612
  /**
618
613
  * Queries and connections. A connection's identity is its descriptor plus the
619
614
  * canonical encoded filter/sort input — **never** the pagination window, so
@@ -755,8 +750,7 @@ const Query$1 = {
755
750
  }
756
751
  })
757
752
  };
758
- //#endregion
759
- //#region src/wire.ts
753
+ // src/wire.ts
760
754
  /**
761
755
  * The Remote wire: Effect RPC semantics over `effect/rpc`. Remote owns
762
756
  * the message shapes; Effect owns the transport. `Make`ing reads batch, mutations
@@ -1027,8 +1021,7 @@ const QueryRpc = Rpc.make("FoldkitRemoteQuery", {
1027
1021
  error: Schema.Union([RemoteQueryError, RemoteUnauthenticated])
1028
1022
  });
1029
1023
  const RemoteRpc = RpcGroup.make(Read, Mutate, QueryRpc, Live);
1030
- //#endregion
1031
- //#region src/coalesce.ts
1024
+ // src/coalesce.ts
1032
1025
  /**
1033
1026
  * Read coalescing: every requirement a client asks for goes through one
1034
1027
  * `RequestResolver`, so requirements issued together become one `ReadBatch`
@@ -1152,8 +1145,7 @@ const coalesceReads = (read, options = {}) => Effect.gen(function* () {
1152
1145
  };
1153
1146
  }));
1154
1147
  });
1155
- //#endregion
1156
- //#region src/client.ts
1148
+ // src/client.ts
1157
1149
  /**
1158
1150
  * The transport seam: the `RemoteClient` Effect service, the RPC client it is
1159
1151
  * built from, the wire-to-client reconstructions, and the mutation call.
@@ -1286,8 +1278,7 @@ const mutateRemote = Effect.fn("Remote.mutate")(function* (mutation, input, requ
1286
1278
  deleted: result.deleted ?? []
1287
1279
  };
1288
1280
  });
1289
- //#endregion
1290
- //#region src/connection.ts
1281
+ // src/connection.ts
1291
1282
  /**
1292
1283
  * The pure connection model: an ordered normalized structure of edges with
1293
1284
  * explicit known boundaries. Pages, live events, and optimistic inserts are all
@@ -1450,8 +1441,7 @@ const hasNext = (connection) => {
1450
1441
  };
1451
1442
  /** A connection with more than one segment has an explicit unknown gap. */
1452
1443
  const isGapped = (connection) => connection.segments.length > 1;
1453
- //#endregion
1454
- //#region src/selection.ts
1444
+ // src/selection.ts
1455
1445
  /**
1456
1446
  * Selections: the fields a Surface picks of an entity (nested through
1457
1447
  * relations, paged through connections), the requirement graph they imply,
@@ -1633,8 +1623,7 @@ const assembleRelation = (store, value, relation) => {
1633
1623
  refreshing
1634
1624
  };
1635
1625
  };
1636
- //#endregion
1637
- //#region src/entity.ts
1626
+ // src/entity.ts
1638
1627
  /**
1639
1628
  * Entities: the descriptor an application declares, refs, ref pages, and
1640
1629
  * patches, with the codecs that carry refs on the wire.
@@ -1722,8 +1711,7 @@ const Entity$1 = {
1722
1711
  values: patch
1723
1712
  })
1724
1713
  };
1725
- //#endregion
1726
- //#region src/placement.ts
1714
+ // src/placement.ts
1727
1715
  /**
1728
1716
  * Where one row falls in a loaded list, by the list's own declared order:
1729
1717
  * the decidable half of placing a row instead of fetching the list again.
@@ -1740,16 +1728,14 @@ const Entity$1 = {
1740
1728
  */
1741
1729
  const RowPlace = Data.taggedEnum();
1742
1730
  /**
1743
- * The values a row holds of the fields an order reads, or none when it lacks
1744
- * 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
1745
1733
  * text as a key holds it, so the id tie-break every order ends on does not
1746
1734
  * make such a row unplaceable; a number id is never compared as text.
1747
1735
  */
1748
1736
  const keysOf = (store, key, id, idIsText, terms) => {
1749
1737
  const values = Object.create(null);
1750
- for (const term of terms) {
1751
- if (term.expr._tag !== "Field") return Option.none();
1752
- const field = term.expr.key;
1738
+ for (const { key: field } of dependenciesOf(...terms).fields) {
1753
1739
  const stored = readField(store, key, field);
1754
1740
  const value = field === "id" && Option.isNone(stored) && idIsText ? id : stored;
1755
1741
  if (Option.isNone(value)) return Option.none();
@@ -1759,12 +1745,12 @@ const keysOf = (store, key, id, idIsText, terms) => {
1759
1745
  };
1760
1746
  /**
1761
1747
  * Where the row stored under `key` falls in `connection`, by `body`'s order
1762
- * for `input` (encoded, as a connection's identity carries it). The row's own
1763
- * edge, if the list holds it, is left out: placing a row that moved asks
1764
- * 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.
1765
1751
  */
1766
- const placeIn = (store, connection, body, input, key) => {
1767
- const placement = Query.placement(body, input);
1752
+ const placeIn = (store, connection, body, input, key, operators) => {
1753
+ const placement = Query.placement(body, input, { operators });
1768
1754
  if (placement._tag === "NotPlaceable") return RowPlace.Unknown({ reason: placement.reason });
1769
1755
  const terms = Query.orderFor(body, input);
1770
1756
  const prefix = `${body.entity.name}:`;
@@ -1776,7 +1762,10 @@ const placeIn = (store, connection, body, input, key) => {
1776
1762
  /** Negative when the row sorts before the edge; none when the edge cannot be compared. */
1777
1763
  const against = (edge) => Option.flatMap(keysOf(store, entityKey(edge.ref.entity, edge.ref.id), Option.some(edge.ref.id), idIsText, terms), (values) => {
1778
1764
  try {
1779
- 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
+ }));
1780
1769
  } catch {
1781
1770
  return Option.none();
1782
1771
  }
@@ -1832,8 +1821,7 @@ const withEdge = (connection, added, place) => ({
1832
1821
  };
1833
1822
  })
1834
1823
  });
1835
- //#endregion
1836
- //#region src/matching.ts
1824
+ // src/matching.ts
1837
1825
  /**
1838
1826
  * Running a query body against the rows the client already holds.
1839
1827
  *
@@ -1920,7 +1908,7 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
1920
1908
  });
1921
1909
  }
1922
1910
  return {
1923
- matched: evaluate(body, encoded, rows).map((row) => row.__key),
1911
+ matched: evaluate(body, encoded, rows, { operators: options.operators }).map((row) => row.__key),
1924
1912
  skipped
1925
1913
  };
1926
1914
  };
@@ -1933,7 +1921,7 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
1933
1921
  * asymmetry with `matching`, which takes a decoded input, is the shape of the
1934
1922
  * two real callers rather than an oversight.
1935
1923
  */
1936
- const belongsEncoded = (store, descriptor, encoded, key) => {
1924
+ const belongsEncoded = (store, descriptor, encoded, key, operators) => {
1937
1925
  const entry = store[key];
1938
1926
  if (entry === void 0) return "unknown";
1939
1927
  if (entry.tombstone) return "no";
@@ -1941,7 +1929,10 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
1941
1929
  if (body !== void 0 && decidableOn(body).some((field) => entry.stale.has(field))) return "unknown";
1942
1930
  let judged;
1943
1931
  try {
1944
- judged = matchingEncoded(store, descriptor, encoded, { among: [key] });
1932
+ judged = matchingEncoded(store, descriptor, encoded, {
1933
+ among: [key],
1934
+ operators
1935
+ });
1945
1936
  } catch (error) {
1946
1937
  if (error instanceof QueryEvaluateError) return "unknown";
1947
1938
  throw error;
@@ -1950,8 +1941,7 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
1950
1941
  if (judged.skipped.includes(key)) return "unknown";
1951
1942
  return "no";
1952
1943
  };
1953
- //#endregion
1954
- //#region src/impact.ts
1944
+ // src/impact.ts
1955
1945
  /**
1956
1946
  * What a write did to the lists the client holds: given one change and one
1957
1947
  * loaded connection, whether the connection is still right as it stands.
@@ -2014,7 +2004,7 @@ const sameOrder = (left, right) => left.segments.length === right.segments.lengt
2014
2004
  * What `change` does to `connection`, judged against `store`, the store after
2015
2005
  * the write.
2016
2006
  */
2017
- const impactOn = (connection, store, change) => {
2007
+ const impactOn = (connection, store, change, operators) => {
2018
2008
  const { descriptor } = connection;
2019
2009
  const body = descriptor.body;
2020
2010
  if ((body?.entity.name ?? descriptor.Result.entity) !== change.entity) return kept;
@@ -2040,7 +2030,7 @@ const impactOn = (connection, store, change) => {
2040
2030
  const refilters = touches(roles.predicate);
2041
2031
  const unloaded = hasPrevious(pages) || hasNext(pages) || isGapped(pages);
2042
2032
  if (!(held && reorders) && !refilters && !(!held && (created || reorders && unloaded))) return kept;
2043
- const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key);
2033
+ const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key, operators);
2044
2034
  if (belongs === "unknown") return Impact.Invalidated({ reason: `${key} changed a field "${descriptor.name}" filters on, and the client cannot judge it` });
2045
2035
  if (!held && belongs === "no") return kept;
2046
2036
  if (held && belongs === "yes" && !reorders) return kept;
@@ -2055,7 +2045,7 @@ const impactOn = (connection, store, change) => {
2055
2045
  }), place);
2056
2046
  return sameOrder(pages, next) ? kept : Impact.Placed({ connection: next });
2057
2047
  };
2058
- return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key), {
2048
+ return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key, operators), {
2059
2049
  Before: placedAt,
2060
2050
  End: placedAt,
2061
2051
  Outside: () => held ? Impact.Placed({ connection: withoutEdge(pages, key) }) : kept,
@@ -2064,8 +2054,7 @@ const impactOn = (connection, store, change) => {
2064
2054
  }
2065
2055
  });
2066
2056
  };
2067
- //#endregion
2068
- //#region src/inspect.ts
2057
+ // src/inspect.ts
2069
2058
  const inspectEntry = (key, entry) => ({
2070
2059
  key,
2071
2060
  present: [...entry.present],
@@ -2095,8 +2084,7 @@ const inspectEntity = (model, key) => {
2095
2084
  const entry = model.entities[key];
2096
2085
  return entry === void 0 ? void 0 : inspectEntry(key, entry);
2097
2086
  };
2098
- //#endregion
2099
- //#region src/optimistic.ts
2087
+ // src/optimistic.ts
2100
2088
  /**
2101
2089
  * Optimistic layers. Pending changes are held as ordered layers over a base
2102
2090
  * store and as overlays over a connection; the visible value is recomputed, never
@@ -2311,8 +2299,7 @@ const visibleItems = (connection, connectionId, overlays, store) => {
2311
2299
  ...take("append")
2312
2300
  ];
2313
2301
  };
2314
- //#endregion
2315
- //#region src/live.ts
2302
+ // src/live.ts
2316
2303
  const emptyLiveState = {
2317
2304
  cursor: 0,
2318
2305
  boundary: {}
@@ -2432,8 +2419,7 @@ const applyConnectionEvent = (state, optimistic, event, policy = {}) => {
2432
2419
  const liveHasPrevious = (connection, state, connectionId) => hasPrevious(connection) || (state.boundary[connectionId]?.before ?? 0) > 0;
2433
2420
  /** `hasNext` accounting for edges recorded outside the loaded boundary. */
2434
2421
  const liveHasNext = (connection, state, connectionId) => hasNext(connection) || (state.boundary[connectionId]?.after ?? 0) > 0;
2435
- //#endregion
2436
- //#region src/plan.ts
2422
+ // src/plan.ts
2437
2423
  /**
2438
2424
  * The pure requirement planner.
2439
2425
  *
@@ -2526,8 +2512,7 @@ const plan = (store, requirements, options = {}) => {
2526
2512
  const nested = followed.length === 0 ? [] : plan(store, followed, options);
2527
2513
  return [...Requirement.merge([...planned, ...nested])].sort((a, b) => entityKey(a.entity, a.id) < entityKey(b.entity, b.id) ? -1 : 1);
2528
2514
  };
2529
- //#endregion
2530
- //#region src/retain.ts
2515
+ // src/retain.ts
2531
2516
  /**
2532
2517
  * The entity keys the roots reach: each root entity, the targets its retained
2533
2518
  * fields refer to, and recursively the targets a nested relation selects.
@@ -2599,8 +2584,7 @@ const keptOf = (record, keep) => {
2599
2584
  const kept = entries.filter(([key]) => keep(key));
2600
2585
  return kept.length === entries.length ? record : Object.fromEntries(kept);
2601
2586
  };
2602
- //#endregion
2603
- //#region src/persistence.ts
2587
+ // src/persistence.ts
2604
2588
  /**
2605
2589
  * Remote cache persistence: a snapshot of the entity store and nothing else.
2606
2590
  * Runtime state (connections' live cursors, optimistic layers, the mutation
@@ -2797,8 +2781,7 @@ const RemotePersistence = {
2797
2781
  return restored;
2798
2782
  })
2799
2783
  };
2800
- //#endregion
2801
- //#region src/remoteData.ts
2784
+ // src/remoteData.ts
2802
2785
  /** `RemoteData`: the state of a value the store may not hold yet. */
2803
2786
  /**
2804
2787
  * The server would not answer who is asking: their session ended or was
@@ -2954,8 +2937,7 @@ const RemoteData = {
2954
2937
  }
2955
2938
  }
2956
2939
  };
2957
- //#endregion
2958
- //#region src/model.ts
2940
+ // src/model.ts
2959
2941
  /**
2960
2942
  * The Remote submodel: the store, connections, mutations, live state, and
2961
2943
  * optimistic layers an application keeps in its Model, the Messages that
@@ -3842,8 +3824,7 @@ const writeRead = (store, requests, result, now = 0) => {
3842
3824
  }
3843
3825
  return setUnavailable(writeEntities(answered, writes, now), result.settled.map((entry) => [entityKey(entry.entity, entry.id), entry.fields]), true);
3844
3826
  };
3845
- //#endregion
3846
- //#region src/policy.ts
3827
+ // src/policy.ts
3847
3828
  const RemotePolicy = {
3848
3829
  /** Fetch only what the store lacks. */
3849
3830
  cacheFirst: { _tag: "CacheFirst" },
@@ -3872,8 +3853,7 @@ const RemotePolicy = {
3872
3853
  */
3873
3854
  refreshes: (policy) => policy._tag !== "CacheFirst"
3874
3855
  };
3875
- //#endregion
3876
- //#region src/resume.ts
3856
+ // src/resume.ts
3877
3857
  /**
3878
3858
  * What of Remote's state crosses from a server render to the browser.
3879
3859
  *
@@ -4087,8 +4067,7 @@ const resumePart = (domain, options = {}) => ({
4087
4067
  onSuccess: (capture) => Result.succeed(domain.store.set(model, restoreRemote(domain.store.get(model), capture)))
4088
4068
  })
4089
4069
  });
4090
- //#endregion
4091
- //#region src/json.ts
4070
+ // src/json.ts
4092
4071
  /**
4093
4072
  * Remote's three calls as JSON: one request, `{ operation, payload }`, and one
4094
4073
  * answer, `{ result }` or `{ error }`. `RemoteServer.answer` is the other end.
@@ -4193,8 +4172,7 @@ const http = (url, options = {}) => json(async (request) => {
4193
4172
  if (body === notJson) throw new Error(status);
4194
4173
  return body;
4195
4174
  });
4196
- //#endregion
4197
- //#region src/sse.ts
4175
+ // src/sse.ts
4198
4176
  /**
4199
4177
  * Remote live over fetch with SSE framing: the other end of
4200
4178
  * `foldkit-remote-server/fetch`'s live open. One `POST` carries the live
@@ -4314,8 +4292,7 @@ const httpWithLive = (url, options = {}) => ({
4314
4292
  ...http(url, options),
4315
4293
  FoldkitRemoteLive: liveFetch(url, options)
4316
4294
  });
4317
- //#endregion
4318
- //#region src/index.ts
4295
+ // src/index.ts
4319
4296
  /**
4320
4297
  * `foldkit-remote` — normalized application-facing server state.
4321
4298
  *
@@ -4330,7 +4307,11 @@ const explainedDependencies = (dependencies) => ({
4330
4307
  key
4331
4308
  })),
4332
4309
  inputs: dependencies.inputs,
4333
- operations: dependencies.operations
4310
+ operations: dependencies.operations,
4311
+ operators: dependencies.operators.map(({ id, version }) => ({
4312
+ id,
4313
+ version
4314
+ }))
4334
4315
  });
4335
4316
  const descriptorOf = (entity) => Entity.is(entity) ? Entity$1.from(entity) : entity;
4336
4317
  const selectionOf = (selection) => SelectionTypeId in selection ? Selection.from(selection) : selection;
@@ -4357,11 +4338,11 @@ const readContract = (source, shape, window) => {
4357
4338
  * compared with neighbours that hold those fields. What the view reads, and so
4358
4339
  * decodes, stays its Selection.
4359
4340
  */
4360
- const placeableReadContract = (contract, body) => {
4341
+ const placeableReadContract = (contract, body, operators) => {
4361
4342
  if (body === void 0) return contract;
4362
4343
  const { requirement, ref } = contract;
4363
4344
  const encoded = Schema.encodeSync(ref.Input)(ref.input);
4364
- if (Query.placement(body, encoded)._tag !== "Placeable") return contract;
4345
+ if (Query.placement(body, encoded, { operators })._tag !== "Placeable") return contract;
4365
4346
  const missing = Query.dependencies(body).fields.filter((field) => !requirement.select.fields.includes(field.key));
4366
4347
  if (missing.length === 0) return contract;
4367
4348
  return {
@@ -5122,7 +5103,10 @@ const Remote = {
5122
5103
  * in one step; the result carries the application-facing operations. The
5123
5104
  * descriptor alone is `Remote.define`, the binding alone `Remote.at`.
5124
5105
  */
5125
- 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
+ }),
5126
5110
  /**
5127
5111
  * Declares a Remote domain without binding it: its entities, queries, and
5128
5112
  * mutations, plus the submodel. For a domain reused across applications or
@@ -5484,6 +5468,7 @@ const failedReadWords = (error) => {
5484
5468
  };
5485
5469
  /** The bound domain: the descriptor, the binding, and the operations over them. */
5486
5470
  const bindDomain = (definition, store, options = {}) => {
5471
+ const operators = options.operators ?? Operators.kernel;
5487
5472
  const bound = bindRemote(definition, store);
5488
5473
  const readers = /* @__PURE__ */ new Map();
5489
5474
  const keptConnections = /* @__PURE__ */ new Set();
@@ -5516,7 +5501,7 @@ const bindDomain = (definition, store, options = {}) => {
5516
5501
  const declared = (descriptor?.Result)?.live;
5517
5502
  if (descriptor?.body === void 0) return declared;
5518
5503
  const encoded = JSON.parse(identity.slice(identity.indexOf("\0") + 1));
5519
- 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" ? {
5520
5505
  prepend: "ignore",
5521
5506
  append: "ignore"
5522
5507
  } : declared;
@@ -5565,7 +5550,7 @@ const bindDomain = (definition, store, options = {}) => {
5565
5550
  ...query.value,
5566
5551
  connection: placed,
5567
5552
  holds
5568
- }, store, change), {
5553
+ }, store, change, operators), {
5569
5554
  Kept: () => placed,
5570
5555
  Placed: ({ connection }) => connection,
5571
5556
  Invalidated: () => placed
@@ -5628,7 +5613,7 @@ const bindDomain = (definition, store, options = {}) => {
5628
5613
  for (const edge of inserted.values()) {
5629
5614
  if (held.has(edge.key)) continue;
5630
5615
  const key = entityKey(edge.ref.entity, edge.ref.id);
5631
- RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key), {
5616
+ RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key, operators), {
5632
5617
  Before: (place) => void (placed = withEdge(placed, edge, place)),
5633
5618
  End: (place) => void (placed = withEdge(placed, edge, place)),
5634
5619
  Outside: () => void outside.push(edge),
@@ -5717,7 +5702,7 @@ const bindDomain = (definition, store, options = {}) => {
5717
5702
  connection: pages,
5718
5703
  holds
5719
5704
  };
5720
- const after = Impact.$match(impactOn(held, visible, change), {
5705
+ const after = Impact.$match(impactOn(held, visible, change, operators), {
5721
5706
  Kept: () => Option.some(pages),
5722
5707
  Placed: ({ connection }) => Option.some(connection),
5723
5708
  Invalidated: () => Option.none()
@@ -5899,7 +5884,7 @@ const bindDomain = (definition, store, options = {}) => {
5899
5884
  const listed = query.Result.entity;
5900
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`);
5901
5886
  if (select.entity !== listed) throw new Error(`Remote: the selection is of "${select.entity}", but query "${query.name}" lists "${listed}"`);
5902
- 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);
5903
5888
  const relationKey = stableStringify(relation);
5904
5889
  const sizeOf = (remote) => windowSize(remote, ref);
5905
5890
  const shown = (remote, connection) => cutToWindow(shownEdges(remote, ref.identity, connection), ref.window, sizeOf(remote));
@@ -6114,7 +6099,10 @@ const bindDomain = (definition, store, options = {}) => {
6114
6099
  const among = (connection === void 0 ? [] : shownEdges(remote, over.ref.identity, connection)).map((edge) => entityKey(edge.ref.entity, edge.ref.id));
6115
6100
  let judged;
6116
6101
  try {
6117
- judged = matching(visible, by, input, { among });
6102
+ judged = matching(visible, by, input, {
6103
+ among,
6104
+ operators
6105
+ });
6118
6106
  } catch (error) {
6119
6107
  if (error instanceof QueryEvaluateError) return {
6120
6108
  items: [],
@@ -6351,7 +6339,6 @@ const pickWindow = (window) => ({
6351
6339
  ...window.after === void 0 ? {} : { after: window.after },
6352
6340
  ...window.before === void 0 ? {} : { before: window.before }
6353
6341
  });
6354
- //#endregion
6355
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 };
6356
6343
 
6357
- //# sourceMappingURL=src-fsYu0YoT.mjs.map
6344
+ //# sourceMappingURL=src-BDqn7Ocr.mjs.map