foldkit-remote 0.19.0 → 0.21.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/README.md +19 -8
- package/dist/{index-Bx_lCC85.d.mts → index-YyucgTYm.d.mts} +59 -77
- package/dist/index-YyucgTYm.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/port.d.mts +1 -3
- package/dist/port.d.mts.map +1 -1
- package/dist/port.mjs +2 -3
- package/dist/{src-fsYu0YoT.mjs → src-lVP_7bf4.mjs} +156 -131
- package/dist/src-lVP_7bf4.mjs.map +1 -0
- package/package.json +4 -4
- package/dist/index-Bx_lCC85.d.mts.map +0 -1
- package/dist/src-fsYu0YoT.mjs.map +0 -1
|
@@ -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,
|
|
4
|
+
import { Entity, Expr, Operators, Query, QueryEvaluateError, ReadFilter, SchemaShape, SelectionTypeId, Write, compareRows, dependenciesOf, evaluateEach } 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
410
|
-
//#region src/mutation.ts
|
|
406
|
+
// src/mutation.ts
|
|
411
407
|
/**
|
|
412
408
|
* Mutation status and idempotent reconciliation.
|
|
413
409
|
*
|
|
@@ -560,16 +556,17 @@ const patchOfWrite = (bound) => ({
|
|
|
560
556
|
/**
|
|
561
557
|
* What a declared write shows before the server answers: an update's or an
|
|
562
558
|
* insert's row as a patch (an update's only for the keys named, when some
|
|
563
|
-
* are), and an update's increments
|
|
564
|
-
*
|
|
559
|
+
* are), and an update's increments and computed fields, worked out over the
|
|
560
|
+
* row the store holds when it is read. A delete shows nothing, since no
|
|
561
|
+
* operation removes a row from every list it is in; its answer does.
|
|
565
562
|
*/
|
|
566
563
|
const optimisticOfWrite = (write, input, keys) => Match.value(write).pipe(Match.tagsExhaustive({
|
|
567
564
|
Update: () => {
|
|
568
565
|
const bound = Write.bind(write, input, keys);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
...
|
|
572
|
-
|
|
566
|
+
return [{
|
|
567
|
+
...patchOfWrite(bound),
|
|
568
|
+
...Object.keys(bound.increments).length === 0 ? {} : { adds: bound.increments },
|
|
569
|
+
...Object.keys(bound.assignments).length === 0 ? {} : { computes: bound.assignments }
|
|
573
570
|
}];
|
|
574
571
|
},
|
|
575
572
|
Insert: () => {
|
|
@@ -612,8 +609,7 @@ const Mutation = {
|
|
|
612
609
|
Refusal: config.Refusal ?? Schema.Never
|
|
613
610
|
})
|
|
614
611
|
};
|
|
615
|
-
|
|
616
|
-
//#region src/query.ts
|
|
612
|
+
// src/query.ts
|
|
617
613
|
/**
|
|
618
614
|
* Queries and connections. A connection's identity is its descriptor plus the
|
|
619
615
|
* canonical encoded filter/sort input — **never** the pagination window, so
|
|
@@ -755,8 +751,7 @@ const Query$1 = {
|
|
|
755
751
|
}
|
|
756
752
|
})
|
|
757
753
|
};
|
|
758
|
-
|
|
759
|
-
//#region src/wire.ts
|
|
754
|
+
// src/wire.ts
|
|
760
755
|
/**
|
|
761
756
|
* The Remote wire: Effect RPC semantics over `effect/rpc`. Remote owns
|
|
762
757
|
* the message shapes; Effect owns the transport. `Make`ing reads batch, mutations
|
|
@@ -1027,8 +1022,7 @@ const QueryRpc = Rpc.make("FoldkitRemoteQuery", {
|
|
|
1027
1022
|
error: Schema.Union([RemoteQueryError, RemoteUnauthenticated])
|
|
1028
1023
|
});
|
|
1029
1024
|
const RemoteRpc = RpcGroup.make(Read, Mutate, QueryRpc, Live);
|
|
1030
|
-
|
|
1031
|
-
//#region src/coalesce.ts
|
|
1025
|
+
// src/coalesce.ts
|
|
1032
1026
|
/**
|
|
1033
1027
|
* Read coalescing: every requirement a client asks for goes through one
|
|
1034
1028
|
* `RequestResolver`, so requirements issued together become one `ReadBatch`
|
|
@@ -1152,8 +1146,7 @@ const coalesceReads = (read, options = {}) => Effect.gen(function* () {
|
|
|
1152
1146
|
};
|
|
1153
1147
|
}));
|
|
1154
1148
|
});
|
|
1155
|
-
|
|
1156
|
-
//#region src/client.ts
|
|
1149
|
+
// src/client.ts
|
|
1157
1150
|
/**
|
|
1158
1151
|
* The transport seam: the `RemoteClient` Effect service, the RPC client it is
|
|
1159
1152
|
* built from, the wire-to-client reconstructions, and the mutation call.
|
|
@@ -1286,8 +1279,7 @@ const mutateRemote = Effect.fn("Remote.mutate")(function* (mutation, input, requ
|
|
|
1286
1279
|
deleted: result.deleted ?? []
|
|
1287
1280
|
};
|
|
1288
1281
|
});
|
|
1289
|
-
|
|
1290
|
-
//#region src/connection.ts
|
|
1282
|
+
// src/connection.ts
|
|
1291
1283
|
/**
|
|
1292
1284
|
* The pure connection model: an ordered normalized structure of edges with
|
|
1293
1285
|
* explicit known boundaries. Pages, live events, and optimistic inserts are all
|
|
@@ -1401,7 +1393,10 @@ const dedupeConnection = (segments) => {
|
|
|
1401
1393
|
/** Adds a page to the connection, joining contiguous or overlapping segments. */
|
|
1402
1394
|
const merge = (current, page) => {
|
|
1403
1395
|
const incoming = normalize(page);
|
|
1404
|
-
if (incoming.edges.length === 0) return current
|
|
1396
|
+
if (incoming.edges.length === 0) return incoming.start._tag === "Terminal" && incoming.end._tag === "Terminal" && current.segments.length === 0 ? {
|
|
1397
|
+
...current,
|
|
1398
|
+
segments: [incoming]
|
|
1399
|
+
} : current;
|
|
1405
1400
|
const segments = [...current.segments.map(normalize), incoming];
|
|
1406
1401
|
let joined = true;
|
|
1407
1402
|
while (joined) {
|
|
@@ -1450,8 +1445,7 @@ const hasNext = (connection) => {
|
|
|
1450
1445
|
};
|
|
1451
1446
|
/** A connection with more than one segment has an explicit unknown gap. */
|
|
1452
1447
|
const isGapped = (connection) => connection.segments.length > 1;
|
|
1453
|
-
|
|
1454
|
-
//#region src/selection.ts
|
|
1448
|
+
// src/selection.ts
|
|
1455
1449
|
/**
|
|
1456
1450
|
* Selections: the fields a Surface picks of an entity (nested through
|
|
1457
1451
|
* relations, paged through connections), the requirement graph they imply,
|
|
@@ -1633,8 +1627,7 @@ const assembleRelation = (store, value, relation) => {
|
|
|
1633
1627
|
refreshing
|
|
1634
1628
|
};
|
|
1635
1629
|
};
|
|
1636
|
-
|
|
1637
|
-
//#region src/entity.ts
|
|
1630
|
+
// src/entity.ts
|
|
1638
1631
|
/**
|
|
1639
1632
|
* Entities: the descriptor an application declares, refs, ref pages, and
|
|
1640
1633
|
* patches, with the codecs that carry refs on the wire.
|
|
@@ -1722,8 +1715,7 @@ const Entity$1 = {
|
|
|
1722
1715
|
values: patch
|
|
1723
1716
|
})
|
|
1724
1717
|
};
|
|
1725
|
-
|
|
1726
|
-
//#region src/placement.ts
|
|
1718
|
+
// src/placement.ts
|
|
1727
1719
|
/**
|
|
1728
1720
|
* Where one row falls in a loaded list, by the list's own declared order:
|
|
1729
1721
|
* the decidable half of placing a row instead of fetching the list again.
|
|
@@ -1740,16 +1732,14 @@ const Entity$1 = {
|
|
|
1740
1732
|
*/
|
|
1741
1733
|
const RowPlace = Data.taggedEnum();
|
|
1742
1734
|
/**
|
|
1743
|
-
* The values a row holds of the fields an order reads,
|
|
1744
|
-
* one. An `id` no Selection stored is its key's, when the id is stored as
|
|
1735
|
+
* The values a row holds of the fields an order reads, a call's arguments
|
|
1736
|
+
* included, or none when it lacks one. An `id` no Selection stored is its key's, when the id is stored as
|
|
1745
1737
|
* text as a key holds it, so the id tie-break every order ends on does not
|
|
1746
1738
|
* make such a row unplaceable; a number id is never compared as text.
|
|
1747
1739
|
*/
|
|
1748
1740
|
const keysOf = (store, key, id, idIsText, terms) => {
|
|
1749
1741
|
const values = Object.create(null);
|
|
1750
|
-
for (const
|
|
1751
|
-
if (term.expr._tag !== "Field") return Option.none();
|
|
1752
|
-
const field = term.expr.key;
|
|
1742
|
+
for (const { key: field } of dependenciesOf(...terms).fields) {
|
|
1753
1743
|
const stored = readField(store, key, field);
|
|
1754
1744
|
const value = field === "id" && Option.isNone(stored) && idIsText ? id : stored;
|
|
1755
1745
|
if (Option.isNone(value)) return Option.none();
|
|
@@ -1759,12 +1749,12 @@ const keysOf = (store, key, id, idIsText, terms) => {
|
|
|
1759
1749
|
};
|
|
1760
1750
|
/**
|
|
1761
1751
|
* Where the row stored under `key` falls in `connection`, by `body`'s order
|
|
1762
|
-
* for `input` (encoded, as a connection's identity carries it)
|
|
1763
|
-
* edge, if the list holds it, is left out:
|
|
1764
|
-
* where it goes now.
|
|
1752
|
+
* for `input` (encoded, as a connection's identity carries it), a call in it
|
|
1753
|
+
* run by `operators`. The row's own edge, if the list holds it, is left out:
|
|
1754
|
+
* placing a row that moved asks where it goes now.
|
|
1765
1755
|
*/
|
|
1766
|
-
const placeIn = (store, connection, body, input, key) => {
|
|
1767
|
-
const placement = Query.placement(body, input);
|
|
1756
|
+
const placeIn = (store, connection, body, input, key, operators) => {
|
|
1757
|
+
const placement = Query.placement(body, input, { operators });
|
|
1768
1758
|
if (placement._tag === "NotPlaceable") return RowPlace.Unknown({ reason: placement.reason });
|
|
1769
1759
|
const terms = Query.orderFor(body, input);
|
|
1770
1760
|
const prefix = `${body.entity.name}:`;
|
|
@@ -1776,7 +1766,10 @@ const placeIn = (store, connection, body, input, key) => {
|
|
|
1776
1766
|
/** Negative when the row sorts before the edge; none when the edge cannot be compared. */
|
|
1777
1767
|
const against = (edge) => Option.flatMap(keysOf(store, entityKey(edge.ref.entity, edge.ref.id), Option.some(edge.ref.id), idIsText, terms), (values) => {
|
|
1778
1768
|
try {
|
|
1779
|
-
return Option.some(compareRows(terms, row.value, values, body.entity.name
|
|
1769
|
+
return Option.some(compareRows(terms, row.value, values, body.entity.name, {
|
|
1770
|
+
input,
|
|
1771
|
+
operators
|
|
1772
|
+
}));
|
|
1780
1773
|
} catch {
|
|
1781
1774
|
return Option.none();
|
|
1782
1775
|
}
|
|
@@ -1832,8 +1825,7 @@ const withEdge = (connection, added, place) => ({
|
|
|
1832
1825
|
};
|
|
1833
1826
|
})
|
|
1834
1827
|
});
|
|
1835
|
-
|
|
1836
|
-
//#region src/matching.ts
|
|
1828
|
+
// src/matching.ts
|
|
1837
1829
|
/**
|
|
1838
1830
|
* Running a query body against the rows the client already holds.
|
|
1839
1831
|
*
|
|
@@ -1919,9 +1911,11 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
|
|
|
1919
1911
|
__key: key
|
|
1920
1912
|
});
|
|
1921
1913
|
}
|
|
1914
|
+
const judged = evaluateEach(body, encoded, rows, { operators: options.operators });
|
|
1915
|
+
const keyOf = (row) => row.__key;
|
|
1922
1916
|
return {
|
|
1923
|
-
matched:
|
|
1924
|
-
skipped
|
|
1917
|
+
matched: judged.matched.map(keyOf),
|
|
1918
|
+
skipped: [...skipped, ...judged.refused.map(keyOf)]
|
|
1925
1919
|
};
|
|
1926
1920
|
};
|
|
1927
1921
|
/**
|
|
@@ -1933,7 +1927,7 @@ const matchingEncoded = (store, descriptor, encoded, options = {}) => {
|
|
|
1933
1927
|
* asymmetry with `matching`, which takes a decoded input, is the shape of the
|
|
1934
1928
|
* two real callers rather than an oversight.
|
|
1935
1929
|
*/
|
|
1936
|
-
const belongsEncoded = (store, descriptor, encoded, key) => {
|
|
1930
|
+
const belongsEncoded = (store, descriptor, encoded, key, operators) => {
|
|
1937
1931
|
const entry = store[key];
|
|
1938
1932
|
if (entry === void 0) return "unknown";
|
|
1939
1933
|
if (entry.tombstone) return "no";
|
|
@@ -1941,7 +1935,10 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
|
|
|
1941
1935
|
if (body !== void 0 && decidableOn(body).some((field) => entry.stale.has(field))) return "unknown";
|
|
1942
1936
|
let judged;
|
|
1943
1937
|
try {
|
|
1944
|
-
judged = matchingEncoded(store, descriptor, encoded, {
|
|
1938
|
+
judged = matchingEncoded(store, descriptor, encoded, {
|
|
1939
|
+
among: [key],
|
|
1940
|
+
operators
|
|
1941
|
+
});
|
|
1945
1942
|
} catch (error) {
|
|
1946
1943
|
if (error instanceof QueryEvaluateError) return "unknown";
|
|
1947
1944
|
throw error;
|
|
@@ -1950,8 +1947,7 @@ const belongsEncoded = (store, descriptor, encoded, key) => {
|
|
|
1950
1947
|
if (judged.skipped.includes(key)) return "unknown";
|
|
1951
1948
|
return "no";
|
|
1952
1949
|
};
|
|
1953
|
-
|
|
1954
|
-
//#region src/impact.ts
|
|
1950
|
+
// src/impact.ts
|
|
1955
1951
|
/**
|
|
1956
1952
|
* What a write did to the lists the client holds: given one change and one
|
|
1957
1953
|
* loaded connection, whether the connection is still right as it stands.
|
|
@@ -2014,7 +2010,7 @@ const sameOrder = (left, right) => left.segments.length === right.segments.lengt
|
|
|
2014
2010
|
* What `change` does to `connection`, judged against `store`, the store after
|
|
2015
2011
|
* the write.
|
|
2016
2012
|
*/
|
|
2017
|
-
const impactOn = (connection, store, change) => {
|
|
2013
|
+
const impactOn = (connection, store, change, operators) => {
|
|
2018
2014
|
const { descriptor } = connection;
|
|
2019
2015
|
const body = descriptor.body;
|
|
2020
2016
|
if ((body?.entity.name ?? descriptor.Result.entity) !== change.entity) return kept;
|
|
@@ -2040,7 +2036,7 @@ const impactOn = (connection, store, change) => {
|
|
|
2040
2036
|
const refilters = touches(roles.predicate);
|
|
2041
2037
|
const unloaded = hasPrevious(pages) || hasNext(pages) || isGapped(pages);
|
|
2042
2038
|
if (!(held && reorders) && !refilters && !(!held && (created || reorders && unloaded))) return kept;
|
|
2043
|
-
const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key);
|
|
2039
|
+
const belongs = held && !refilters ? "yes" : belongsEncoded(store, descriptor, connection.encoded, key, operators);
|
|
2044
2040
|
if (belongs === "unknown") return Impact.Invalidated({ reason: `${key} changed a field "${descriptor.name}" filters on, and the client cannot judge it` });
|
|
2045
2041
|
if (!held && belongs === "no") return kept;
|
|
2046
2042
|
if (held && belongs === "yes" && !reorders) return kept;
|
|
@@ -2055,7 +2051,7 @@ const impactOn = (connection, store, change) => {
|
|
|
2055
2051
|
}), place);
|
|
2056
2052
|
return sameOrder(pages, next) ? kept : Impact.Placed({ connection: next });
|
|
2057
2053
|
};
|
|
2058
|
-
return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key), {
|
|
2054
|
+
return RowPlace.$match(placeIn(store, pages, body, connection.encoded, key, operators), {
|
|
2059
2055
|
Before: placedAt,
|
|
2060
2056
|
End: placedAt,
|
|
2061
2057
|
Outside: () => held ? Impact.Placed({ connection: withoutEdge(pages, key) }) : kept,
|
|
@@ -2064,8 +2060,7 @@ const impactOn = (connection, store, change) => {
|
|
|
2064
2060
|
}
|
|
2065
2061
|
});
|
|
2066
2062
|
};
|
|
2067
|
-
|
|
2068
|
-
//#region src/inspect.ts
|
|
2063
|
+
// src/inspect.ts
|
|
2069
2064
|
const inspectEntry = (key, entry) => ({
|
|
2070
2065
|
key,
|
|
2071
2066
|
present: [...entry.present],
|
|
@@ -2095,8 +2090,7 @@ const inspectEntity = (model, key) => {
|
|
|
2095
2090
|
const entry = model.entities[key];
|
|
2096
2091
|
return entry === void 0 ? void 0 : inspectEntry(key, entry);
|
|
2097
2092
|
};
|
|
2098
|
-
|
|
2099
|
-
//#region src/optimistic.ts
|
|
2093
|
+
// src/optimistic.ts
|
|
2100
2094
|
/**
|
|
2101
2095
|
* Optimistic layers. Pending changes are held as ordered layers over a base
|
|
2102
2096
|
* store and as overlays over a connection; the visible value is recomputed, never
|
|
@@ -2202,7 +2196,7 @@ const removeOverlay = (optimistic, id) => {
|
|
|
2202
2196
|
* entity only a request holds (a temporary id) is not the server's to age, and
|
|
2203
2197
|
* is dated `Infinity`, so freshness never plans or times it.
|
|
2204
2198
|
*/
|
|
2205
|
-
const visibleStore = (base, optimistic) => writeEntities(base, resolvedPatches(base, optimistic).map((patch) => {
|
|
2199
|
+
const visibleStore = (base, optimistic, operators = Operators.kernel) => writeEntities(base, resolvedPatches(base, optimistic, operators).map((patch) => {
|
|
2206
2200
|
const key = entityKey(patch.entity, patch.id);
|
|
2207
2201
|
const under = base[key];
|
|
2208
2202
|
return {
|
|
@@ -2212,32 +2206,56 @@ const visibleStore = (base, optimistic) => writeEntities(base, resolvedPatches(b
|
|
|
2212
2206
|
};
|
|
2213
2207
|
}));
|
|
2214
2208
|
/**
|
|
2215
|
-
* Every pending patch in order, each amount added
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2209
|
+
* Every pending patch in order, each amount added and each computed field
|
|
2210
|
+
* worked out over the row under it (the store's, with earlier layers over
|
|
2211
|
+
* it) by `Write.apply`, with the client's table (the kernel's when not
|
|
2212
|
+
* given). A prediction, so only over
|
|
2213
|
+
* what the client holds: a field it has not read, an amount over anything
|
|
2214
|
+
* but a number, or a computation by an operator its table lacks keeps what
|
|
2215
|
+
* it shows until the server answers.
|
|
2219
2216
|
*/
|
|
2220
|
-
const resolvedPatches = (base, optimistic) => {
|
|
2217
|
+
const resolvedPatches = (base, optimistic, operators = Operators.kernel) => {
|
|
2221
2218
|
const shown = /* @__PURE__ */ new Map();
|
|
2222
|
-
|
|
2219
|
+
const unsure = /* @__PURE__ */ new Map();
|
|
2220
|
+
return optimistic.layers.flatMap((layer) => layer.patches.map(({ adds, computes, ...patch }) => {
|
|
2223
2221
|
const key = entityKey(patch.entity, patch.id);
|
|
2224
2222
|
const earlier = shown.get(key) ?? {};
|
|
2223
|
+
const unknown = new Set([...unsure.get(key) ?? []].filter((field) => !Object.hasOwn(patch.values, field)));
|
|
2225
2224
|
const values = { ...patch.values };
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2225
|
+
const row = Object.fromEntries(Object.entries({
|
|
2226
|
+
...base[key]?.values,
|
|
2227
|
+
...earlier
|
|
2228
|
+
}).filter(([field]) => !unknown.has(field)));
|
|
2229
|
+
const moved = {
|
|
2230
|
+
values: {},
|
|
2231
|
+
increments: adds ?? {},
|
|
2232
|
+
assignments: computes ?? {}
|
|
2233
|
+
};
|
|
2234
|
+
const predicted = predicting(() => Write.apply(row, moved, { operators }));
|
|
2235
|
+
for (const field of [...Object.keys(moved.increments), ...Object.keys(moved.assignments)]) if (predicted !== void 0 && !predicted.unknown.includes(field)) {
|
|
2236
|
+
values[field] = predicted.row[field];
|
|
2237
|
+
unknown.delete(field);
|
|
2238
|
+
} else unknown.add(field);
|
|
2231
2239
|
shown.set(key, {
|
|
2232
2240
|
...earlier,
|
|
2233
2241
|
...values
|
|
2234
2242
|
});
|
|
2243
|
+
unsure.set(key, unknown);
|
|
2235
2244
|
return {
|
|
2236
2245
|
...patch,
|
|
2237
2246
|
values
|
|
2238
2247
|
};
|
|
2239
2248
|
}));
|
|
2240
2249
|
};
|
|
2250
|
+
/** A prediction, or none where an operator refuses the row it is given: the server will answer. */
|
|
2251
|
+
const predicting = (predict) => {
|
|
2252
|
+
try {
|
|
2253
|
+
return predict();
|
|
2254
|
+
} catch (error) {
|
|
2255
|
+
if (error instanceof QueryEvaluateError) return void 0;
|
|
2256
|
+
throw error;
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2241
2259
|
/**
|
|
2242
2260
|
* A fresh page is newer than any settled overlay it covers: an edge the page
|
|
2243
2261
|
* carries no longer needs an insert overlay, and a `remove` overlay hiding it
|
|
@@ -2311,8 +2329,7 @@ const visibleItems = (connection, connectionId, overlays, store) => {
|
|
|
2311
2329
|
...take("append")
|
|
2312
2330
|
];
|
|
2313
2331
|
};
|
|
2314
|
-
|
|
2315
|
-
//#region src/live.ts
|
|
2332
|
+
// src/live.ts
|
|
2316
2333
|
const emptyLiveState = {
|
|
2317
2334
|
cursor: 0,
|
|
2318
2335
|
boundary: {}
|
|
@@ -2432,8 +2449,7 @@ const applyConnectionEvent = (state, optimistic, event, policy = {}) => {
|
|
|
2432
2449
|
const liveHasPrevious = (connection, state, connectionId) => hasPrevious(connection) || (state.boundary[connectionId]?.before ?? 0) > 0;
|
|
2433
2450
|
/** `hasNext` accounting for edges recorded outside the loaded boundary. */
|
|
2434
2451
|
const liveHasNext = (connection, state, connectionId) => hasNext(connection) || (state.boundary[connectionId]?.after ?? 0) > 0;
|
|
2435
|
-
|
|
2436
|
-
//#region src/plan.ts
|
|
2452
|
+
// src/plan.ts
|
|
2437
2453
|
/**
|
|
2438
2454
|
* The pure requirement planner.
|
|
2439
2455
|
*
|
|
@@ -2526,8 +2542,7 @@ const plan = (store, requirements, options = {}) => {
|
|
|
2526
2542
|
const nested = followed.length === 0 ? [] : plan(store, followed, options);
|
|
2527
2543
|
return [...Requirement.merge([...planned, ...nested])].sort((a, b) => entityKey(a.entity, a.id) < entityKey(b.entity, b.id) ? -1 : 1);
|
|
2528
2544
|
};
|
|
2529
|
-
|
|
2530
|
-
//#region src/retain.ts
|
|
2545
|
+
// src/retain.ts
|
|
2531
2546
|
/**
|
|
2532
2547
|
* The entity keys the roots reach: each root entity, the targets its retained
|
|
2533
2548
|
* fields refer to, and recursively the targets a nested relation selects.
|
|
@@ -2599,8 +2614,7 @@ const keptOf = (record, keep) => {
|
|
|
2599
2614
|
const kept = entries.filter(([key]) => keep(key));
|
|
2600
2615
|
return kept.length === entries.length ? record : Object.fromEntries(kept);
|
|
2601
2616
|
};
|
|
2602
|
-
|
|
2603
|
-
//#region src/persistence.ts
|
|
2617
|
+
// src/persistence.ts
|
|
2604
2618
|
/**
|
|
2605
2619
|
* Remote cache persistence: a snapshot of the entity store and nothing else.
|
|
2606
2620
|
* Runtime state (connections' live cursors, optimistic layers, the mutation
|
|
@@ -2797,8 +2811,7 @@ const RemotePersistence = {
|
|
|
2797
2811
|
return restored;
|
|
2798
2812
|
})
|
|
2799
2813
|
};
|
|
2800
|
-
|
|
2801
|
-
//#region src/remoteData.ts
|
|
2814
|
+
// src/remoteData.ts
|
|
2802
2815
|
/** `RemoteData`: the state of a value the store may not hold yet. */
|
|
2803
2816
|
/**
|
|
2804
2817
|
* The server would not answer who is asking: their session ended or was
|
|
@@ -2954,8 +2967,7 @@ const RemoteData = {
|
|
|
2954
2967
|
}
|
|
2955
2968
|
}
|
|
2956
2969
|
};
|
|
2957
|
-
|
|
2958
|
-
//#region src/model.ts
|
|
2970
|
+
// src/model.ts
|
|
2959
2971
|
/**
|
|
2960
2972
|
* The Remote submodel: the store, connections, mutations, live state, and
|
|
2961
2973
|
* optimistic layers an application keeps in its Model, the Messages that
|
|
@@ -3842,8 +3854,7 @@ const writeRead = (store, requests, result, now = 0) => {
|
|
|
3842
3854
|
}
|
|
3843
3855
|
return setUnavailable(writeEntities(answered, writes, now), result.settled.map((entry) => [entityKey(entry.entity, entry.id), entry.fields]), true);
|
|
3844
3856
|
};
|
|
3845
|
-
|
|
3846
|
-
//#region src/policy.ts
|
|
3857
|
+
// src/policy.ts
|
|
3847
3858
|
const RemotePolicy = {
|
|
3848
3859
|
/** Fetch only what the store lacks. */
|
|
3849
3860
|
cacheFirst: { _tag: "CacheFirst" },
|
|
@@ -3872,8 +3883,7 @@ const RemotePolicy = {
|
|
|
3872
3883
|
*/
|
|
3873
3884
|
refreshes: (policy) => policy._tag !== "CacheFirst"
|
|
3874
3885
|
};
|
|
3875
|
-
|
|
3876
|
-
//#region src/resume.ts
|
|
3886
|
+
// src/resume.ts
|
|
3877
3887
|
/**
|
|
3878
3888
|
* What of Remote's state crosses from a server render to the browser.
|
|
3879
3889
|
*
|
|
@@ -4087,8 +4097,7 @@ const resumePart = (domain, options = {}) => ({
|
|
|
4087
4097
|
onSuccess: (capture) => Result.succeed(domain.store.set(model, restoreRemote(domain.store.get(model), capture)))
|
|
4088
4098
|
})
|
|
4089
4099
|
});
|
|
4090
|
-
|
|
4091
|
-
//#region src/json.ts
|
|
4100
|
+
// src/json.ts
|
|
4092
4101
|
/**
|
|
4093
4102
|
* Remote's three calls as JSON: one request, `{ operation, payload }`, and one
|
|
4094
4103
|
* answer, `{ result }` or `{ error }`. `RemoteServer.answer` is the other end.
|
|
@@ -4193,8 +4202,7 @@ const http = (url, options = {}) => json(async (request) => {
|
|
|
4193
4202
|
if (body === notJson) throw new Error(status);
|
|
4194
4203
|
return body;
|
|
4195
4204
|
});
|
|
4196
|
-
|
|
4197
|
-
//#region src/sse.ts
|
|
4205
|
+
// src/sse.ts
|
|
4198
4206
|
/**
|
|
4199
4207
|
* Remote live over fetch with SSE framing: the other end of
|
|
4200
4208
|
* `foldkit-remote-server/fetch`'s live open. One `POST` carries the live
|
|
@@ -4314,8 +4322,7 @@ const httpWithLive = (url, options = {}) => ({
|
|
|
4314
4322
|
...http(url, options),
|
|
4315
4323
|
FoldkitRemoteLive: liveFetch(url, options)
|
|
4316
4324
|
});
|
|
4317
|
-
|
|
4318
|
-
//#region src/index.ts
|
|
4325
|
+
// src/index.ts
|
|
4319
4326
|
/**
|
|
4320
4327
|
* `foldkit-remote` — normalized application-facing server state.
|
|
4321
4328
|
*
|
|
@@ -4330,7 +4337,11 @@ const explainedDependencies = (dependencies) => ({
|
|
|
4330
4337
|
key
|
|
4331
4338
|
})),
|
|
4332
4339
|
inputs: dependencies.inputs,
|
|
4333
|
-
operations: dependencies.operations
|
|
4340
|
+
operations: dependencies.operations,
|
|
4341
|
+
operators: dependencies.operators.map(({ id, version }) => ({
|
|
4342
|
+
id,
|
|
4343
|
+
version
|
|
4344
|
+
}))
|
|
4334
4345
|
});
|
|
4335
4346
|
const descriptorOf = (entity) => Entity.is(entity) ? Entity$1.from(entity) : entity;
|
|
4336
4347
|
const selectionOf = (selection) => SelectionTypeId in selection ? Selection.from(selection) : selection;
|
|
@@ -4357,11 +4368,11 @@ const readContract = (source, shape, window) => {
|
|
|
4357
4368
|
* compared with neighbours that hold those fields. What the view reads, and so
|
|
4358
4369
|
* decodes, stays its Selection.
|
|
4359
4370
|
*/
|
|
4360
|
-
const placeableReadContract = (contract, body) => {
|
|
4371
|
+
const placeableReadContract = (contract, body, operators) => {
|
|
4361
4372
|
if (body === void 0) return contract;
|
|
4362
4373
|
const { requirement, ref } = contract;
|
|
4363
4374
|
const encoded = Schema.encodeSync(ref.Input)(ref.input);
|
|
4364
|
-
if (Query.placement(body, encoded)._tag !== "Placeable") return contract;
|
|
4375
|
+
if (Query.placement(body, encoded, { operators })._tag !== "Placeable") return contract;
|
|
4365
4376
|
const missing = Query.dependencies(body).fields.filter((field) => !requirement.select.fields.includes(field.key));
|
|
4366
4377
|
if (missing.length === 0) return contract;
|
|
4367
4378
|
return {
|
|
@@ -4375,8 +4386,8 @@ const placeableReadContract = (contract, body) => {
|
|
|
4375
4386
|
}
|
|
4376
4387
|
};
|
|
4377
4388
|
};
|
|
4378
|
-
const metaOf = (remote, asked) => {
|
|
4379
|
-
const visible = visibleStoreOf(remote.entities, remote.optimistic);
|
|
4389
|
+
const metaOf = (remote, asked, operators) => {
|
|
4390
|
+
const visible = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
4380
4391
|
let updatedAt;
|
|
4381
4392
|
let stale = false;
|
|
4382
4393
|
let loading = false;
|
|
@@ -4426,7 +4437,7 @@ const metaOf = (remote, asked) => {
|
|
|
4426
4437
|
*/
|
|
4427
4438
|
const storeOf = (bound, model) => {
|
|
4428
4439
|
const remote = bound.store.get(model);
|
|
4429
|
-
return visibleStoreOf(remote.entities, remote.optimistic);
|
|
4440
|
+
return visibleStoreOf(remote.entities, remote.optimistic, bound.operators);
|
|
4430
4441
|
};
|
|
4431
4442
|
/**
|
|
4432
4443
|
* The Model as it would be with nothing optimistic pending. Every read reaches
|
|
@@ -4445,15 +4456,20 @@ const confirmed = (bound, projection) => ({
|
|
|
4445
4456
|
read: (root) => projection.read(withoutOptimistic(bound, root))
|
|
4446
4457
|
});
|
|
4447
4458
|
const visibleStores = /* @__PURE__ */ new WeakMap();
|
|
4448
|
-
const visibleStoreOf = (entities, optimistic) => {
|
|
4449
|
-
let
|
|
4459
|
+
const visibleStoreOf = (entities, optimistic, operators) => {
|
|
4460
|
+
let byLayers = visibleStores.get(operators);
|
|
4461
|
+
if (byLayers === void 0) {
|
|
4462
|
+
byLayers = /* @__PURE__ */ new WeakMap();
|
|
4463
|
+
visibleStores.set(operators, byLayers);
|
|
4464
|
+
}
|
|
4465
|
+
let byStore = byLayers.get(optimistic.layers);
|
|
4450
4466
|
if (byStore === void 0) {
|
|
4451
4467
|
byStore = /* @__PURE__ */ new WeakMap();
|
|
4452
|
-
|
|
4468
|
+
byLayers.set(optimistic.layers, byStore);
|
|
4453
4469
|
}
|
|
4454
4470
|
let visible = byStore.get(entities);
|
|
4455
4471
|
if (visible === void 0) {
|
|
4456
|
-
visible = visibleStore(entities, optimistic);
|
|
4472
|
+
visible = visibleStore(entities, optimistic, operators);
|
|
4457
4473
|
byStore.set(entities, visible);
|
|
4458
4474
|
}
|
|
4459
4475
|
return visible;
|
|
@@ -4562,9 +4578,10 @@ const defineRemote = (config) => {
|
|
|
4562
4578
|
};
|
|
4563
4579
|
};
|
|
4564
4580
|
/** Binds a Remote domain to its store's location in the application Model. */
|
|
4565
|
-
const bindRemote = (definition, store) => ({
|
|
4581
|
+
const bindRemote = (definition, store, operators) => ({
|
|
4566
4582
|
definition,
|
|
4567
4583
|
store,
|
|
4584
|
+
operators,
|
|
4568
4585
|
contract: {
|
|
4569
4586
|
kind: "remote",
|
|
4570
4587
|
name: store.dependency.join(".") || "remote",
|
|
@@ -4670,7 +4687,7 @@ const missingRows = (known, window, size) => {
|
|
|
4670
4687
|
before: to.cursor
|
|
4671
4688
|
};
|
|
4672
4689
|
};
|
|
4673
|
-
const planAsked = (remote, asked, options) => {
|
|
4690
|
+
const planAsked = (remote, asked, options, operators) => {
|
|
4674
4691
|
const queries = [];
|
|
4675
4692
|
const items = [];
|
|
4676
4693
|
const connections = Requirement.mergeConnections(asked.connections);
|
|
@@ -4688,7 +4705,7 @@ const planAsked = (remote, asked, options) => {
|
|
|
4688
4705
|
const edges = visibleItems(known, connection.identity, remote.optimistic.overlays, remote.entities);
|
|
4689
4706
|
items.push(...itemsOf(edges.map((edge) => edge.ref), connection.select));
|
|
4690
4707
|
}
|
|
4691
|
-
const visible = visibleStoreOf(remote.entities, remote.optimistic);
|
|
4708
|
+
const visible = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
4692
4709
|
const read = [...asked.requirements, ...items];
|
|
4693
4710
|
const planned = plan(visible, read, options);
|
|
4694
4711
|
return {
|
|
@@ -4891,7 +4908,7 @@ const observeEntry = (bound, askedOf, toMessage, options) => {
|
|
|
4891
4908
|
let byAsked = planned.get(remote);
|
|
4892
4909
|
const known = byAsked?.get(askedKey);
|
|
4893
4910
|
if (known !== void 0 && at < known.until) return known.dependencies;
|
|
4894
|
-
const plan = planAsked(remote, asked, RemotePolicy.toPlan(policy, at));
|
|
4911
|
+
const plan = planAsked(remote, asked, RemotePolicy.toPlan(policy, at), bound.operators);
|
|
4895
4912
|
const dependencies = {
|
|
4896
4913
|
refresh: refreshedAt(remote.refresh, plan.requirements, plan.queries.map((query) => query.identity)),
|
|
4897
4914
|
requirements: plan.requirements,
|
|
@@ -5122,7 +5139,10 @@ const Remote = {
|
|
|
5122
5139
|
* in one step; the result carries the application-facing operations. The
|
|
5123
5140
|
* descriptor alone is `Remote.define`, the binding alone `Remote.at`.
|
|
5124
5141
|
*/
|
|
5125
|
-
make: (config) => bindDomain(defineRemote(config), config.model, {
|
|
5142
|
+
make: (config) => bindDomain(defineRemote(config), config.model, {
|
|
5143
|
+
verifyPlacement: config.verifyPlacement,
|
|
5144
|
+
operators: config.operators
|
|
5145
|
+
}),
|
|
5126
5146
|
/**
|
|
5127
5147
|
* Declares a Remote domain without binding it: its entities, queries, and
|
|
5128
5148
|
* mutations, plus the submodel. For a domain reused across applications or
|
|
@@ -5132,9 +5152,11 @@ const Remote = {
|
|
|
5132
5152
|
/**
|
|
5133
5153
|
* Binds a Remote domain to its store's location in the application Model. The
|
|
5134
5154
|
* registered entity names are carried on the returned value, so `Remote.select`
|
|
5135
|
-
* rejects a selection for an entity this domain never declared.
|
|
5155
|
+
* rejects a selection for an entity this domain never declared. `operators`
|
|
5156
|
+
* is the client's table, which a pending computed assignment is predicted by
|
|
5157
|
+
* (`Operators.kernel` when not given), as `Remote.make`'s is.
|
|
5136
5158
|
*/
|
|
5137
|
-
at: bindRemote,
|
|
5159
|
+
at: (definition, store, options = {}) => bindRemote(definition, store, options.operators ?? Operators.kernel),
|
|
5138
5160
|
/**
|
|
5139
5161
|
* The resume part for this domain, for `foldkit-ssr`'s `SSR.plan({ parts })`:
|
|
5140
5162
|
* a server render sends what the plan's active Surfaces read from the store,
|
|
@@ -5219,18 +5241,18 @@ const Remote = {
|
|
|
5219
5241
|
* connection marked stale; `loading` is any of them in flight. Optimistic
|
|
5220
5242
|
* previews do not date: showing only one reads `updatedAt: undefined`.
|
|
5221
5243
|
*/
|
|
5222
|
-
meta: (bound, model, projection) => metaOf(bound.store.get(model), askedOf(projection)),
|
|
5244
|
+
meta: (bound, model, projection) => metaOf(bound.store.get(model), askedOf(projection), bound.operators),
|
|
5223
5245
|
/**
|
|
5224
5246
|
* The pure plan for a projection against a Model: the requirements its
|
|
5225
5247
|
* remote store does not satisfy, under `options` (freshness, force). A
|
|
5226
5248
|
* Surface's projection is `surface.projection(params)`.
|
|
5227
5249
|
*/
|
|
5228
|
-
plan: (bound, model, projection, options) => planAsked(bound.store.get(model), askedOf(projection), options ?? {}).requirements,
|
|
5250
|
+
plan: (bound, model, projection, options) => planAsked(bound.store.get(model), askedOf(projection), options ?? {}, bound.operators).requirements,
|
|
5229
5251
|
/**
|
|
5230
5252
|
* The queries a projection needs run before its connections read: those the
|
|
5231
5253
|
* Model does not hold, or holds stale (every one under `force`).
|
|
5232
5254
|
*/
|
|
5233
|
-
planQueries: (bound, model, projection, options) => planAsked(bound.store.get(model), askedOf(projection), options ?? {}).queries.flatMap((query) => query.ref === void 0 ? [] : [query.ref]),
|
|
5255
|
+
planQueries: (bound, model, projection, options) => planAsked(bound.store.get(model), askedOf(projection), options ?? {}, bound.operators).queries.flatMap((query) => query.ref === void 0 ? [] : [query.ref]),
|
|
5234
5256
|
/**
|
|
5235
5257
|
* The store reads see: the base store under the pending optimistic layers.
|
|
5236
5258
|
* One store is shared by every read and plan of a Model whose remote state
|
|
@@ -5292,7 +5314,7 @@ const Remote = {
|
|
|
5292
5314
|
const known = remote.connections[connection.identity];
|
|
5293
5315
|
return known === void 0 ? [] : itemsOf(visibleItems(known, connection.identity, remote.optimistic.overlays, remote.entities).map((edge) => edge.ref), connection.select);
|
|
5294
5316
|
});
|
|
5295
|
-
const requirements = plan(visibleStoreOf(remote.entities, remote.optimistic), [...asked.requirements, ...items], { force: true });
|
|
5317
|
+
const requirements = plan(visibleStoreOf(remote.entities, remote.optimistic, bound.operators), [...asked.requirements, ...items], { force: true });
|
|
5296
5318
|
const invalidated = connections.filter((connection) => remote.connections[connection.identity] !== void 0 || connection.identity in remote.failures.connections).map((connection) => connection.identity);
|
|
5297
5319
|
const marked = [...requirements.length === 0 ? [] : [{
|
|
5298
5320
|
_tag: "RefreshStarted",
|
|
@@ -5484,7 +5506,8 @@ const failedReadWords = (error) => {
|
|
|
5484
5506
|
};
|
|
5485
5507
|
/** The bound domain: the descriptor, the binding, and the operations over them. */
|
|
5486
5508
|
const bindDomain = (definition, store, options = {}) => {
|
|
5487
|
-
const
|
|
5509
|
+
const operators = options.operators ?? Operators.kernel;
|
|
5510
|
+
const bound = bindRemote(definition, store, operators);
|
|
5488
5511
|
const readers = /* @__PURE__ */ new Map();
|
|
5489
5512
|
const keptConnections = /* @__PURE__ */ new Set();
|
|
5490
5513
|
/**
|
|
@@ -5516,7 +5539,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5516
5539
|
const declared = (descriptor?.Result)?.live;
|
|
5517
5540
|
if (descriptor?.body === void 0) return declared;
|
|
5518
5541
|
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" ? {
|
|
5542
|
+
return belongsEncoded(storeOf(bound, model), descriptor, encoded, entityKey(event.edge.ref.entity, event.edge.ref.id), operators) === "no" ? {
|
|
5520
5543
|
prepend: "ignore",
|
|
5521
5544
|
append: "ignore"
|
|
5522
5545
|
} : declared;
|
|
@@ -5565,7 +5588,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5565
5588
|
...query.value,
|
|
5566
5589
|
connection: placed,
|
|
5567
5590
|
holds
|
|
5568
|
-
}, store, change), {
|
|
5591
|
+
}, store, change, operators), {
|
|
5569
5592
|
Kept: () => placed,
|
|
5570
5593
|
Placed: ({ connection }) => connection,
|
|
5571
5594
|
Invalidated: () => placed
|
|
@@ -5585,7 +5608,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5585
5608
|
pages,
|
|
5586
5609
|
layers,
|
|
5587
5610
|
remote.entities
|
|
5588
|
-
], `placed:${identity}`, () => placedHeld(identity, pages, changesOf({ entities: resolvedPatches(remote.entities, remote.optimistic) }, remote.entities), visibleStoreOf(remote.entities, remote.optimistic)));
|
|
5611
|
+
], `placed:${identity}`, () => placedHeld(identity, pages, changesOf({ entities: resolvedPatches(remote.entities, remote.optimistic, operators) }, remote.entities), visibleStoreOf(remote.entities, remote.optimistic, operators)));
|
|
5589
5612
|
};
|
|
5590
5613
|
/**
|
|
5591
5614
|
* The edges a loaded list shows: its pages with pending edits placed, and
|
|
@@ -5605,7 +5628,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5605
5628
|
};
|
|
5606
5629
|
const insertsPlaced = (remote, identity, pages) => {
|
|
5607
5630
|
const { overlays } = remote.optimistic;
|
|
5608
|
-
const store = visibleStoreOf(remote.entities, remote.optimistic);
|
|
5631
|
+
const store = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
5609
5632
|
return memoRead([
|
|
5610
5633
|
pages,
|
|
5611
5634
|
overlays,
|
|
@@ -5628,7 +5651,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5628
5651
|
for (const edge of inserted.values()) {
|
|
5629
5652
|
if (held.has(edge.key)) continue;
|
|
5630
5653
|
const key = entityKey(edge.ref.entity, edge.ref.id);
|
|
5631
|
-
RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key), {
|
|
5654
|
+
RowPlace.$match(placeIn(store, placed, body, query.value.encoded, key, operators), {
|
|
5632
5655
|
Before: (place) => void (placed = withEdge(placed, edge, place)),
|
|
5633
5656
|
End: (place) => void (placed = withEdge(placed, edge, place)),
|
|
5634
5657
|
Outside: () => void outside.push(edge),
|
|
@@ -5698,7 +5721,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5698
5721
|
keys.add(change.edge.key);
|
|
5699
5722
|
named.set(change.connection, keys);
|
|
5700
5723
|
}
|
|
5701
|
-
const visible = visibleStoreOf(remote.entities, remote.optimistic);
|
|
5724
|
+
const visible = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
5702
5725
|
const placed = {};
|
|
5703
5726
|
const invalidated = [];
|
|
5704
5727
|
for (const identity of Object.keys(remote.connections)) {
|
|
@@ -5717,7 +5740,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5717
5740
|
connection: pages,
|
|
5718
5741
|
holds
|
|
5719
5742
|
};
|
|
5720
|
-
const after = Impact.$match(impactOn(held, visible, change), {
|
|
5743
|
+
const after = Impact.$match(impactOn(held, visible, change, operators), {
|
|
5721
5744
|
Kept: () => Option.some(pages),
|
|
5722
5745
|
Placed: ({ connection }) => Option.some(connection),
|
|
5723
5746
|
Invalidated: () => Option.none()
|
|
@@ -5785,11 +5808,11 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5785
5808
|
const client = yield* RemoteClient;
|
|
5786
5809
|
const planOptions = RemotePolicy.toPlan(policy, now());
|
|
5787
5810
|
let current = model;
|
|
5788
|
-
for (const query of planAsked(store.get(current), askedOf(projection), planOptions).queries) {
|
|
5811
|
+
for (const query of planAsked(store.get(current), askedOf(projection), planOptions, operators).queries) {
|
|
5789
5812
|
const page = yield* queryRequestOf(query).pipe(Effect.flatMap((request) => client.query(request)));
|
|
5790
5813
|
current = hear(current, pageMessage(query.identity, page, true, query.window, query.select, now()));
|
|
5791
5814
|
}
|
|
5792
|
-
const requirements = planAsked(store.get(current), askedOf(projection), planOptions).requirements;
|
|
5815
|
+
const requirements = planAsked(store.get(current), askedOf(projection), planOptions, operators).requirements;
|
|
5793
5816
|
if (requirements.length === 0) return current;
|
|
5794
5817
|
const at = now();
|
|
5795
5818
|
const result = yield* client.read({
|
|
@@ -5810,7 +5833,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5810
5833
|
entries.forEach(assertOwned);
|
|
5811
5834
|
const planOptions = RemotePolicy.toPlan(RemotePolicy.cacheFirst, now());
|
|
5812
5835
|
const plans = (current, projections) => {
|
|
5813
|
-
const planned = planAsked(store.get(current), askedUnion(projections), planOptions);
|
|
5836
|
+
const planned = planAsked(store.get(current), askedUnion(projections), planOptions, operators);
|
|
5814
5837
|
return planned.queries.length > 0 || planned.requirements.length > 0;
|
|
5815
5838
|
};
|
|
5816
5839
|
let current = model;
|
|
@@ -5899,7 +5922,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5899
5922
|
const listed = query.Result.entity;
|
|
5900
5923
|
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
5924
|
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);
|
|
5925
|
+
const { ref, relation, requirement } = placeableReadContract(readContract(query.ref(input), select, window), query.body, operators);
|
|
5903
5926
|
const relationKey = stableStringify(relation);
|
|
5904
5927
|
const sizeOf = (remote) => windowSize(remote, ref);
|
|
5905
5928
|
const shown = (remote, connection) => cutToWindow(shownEdges(remote, ref.identity, connection), ref.window, sizeOf(remote));
|
|
@@ -5922,7 +5945,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
5922
5945
|
}
|
|
5923
5946
|
};
|
|
5924
5947
|
const readPage = (remote, connection) => {
|
|
5925
|
-
const visible = visibleStoreOf(remote.entities, remote.optimistic);
|
|
5948
|
+
const visible = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
5926
5949
|
return memoRead([
|
|
5927
5950
|
visible,
|
|
5928
5951
|
connection,
|
|
@@ -6110,11 +6133,14 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
6110
6133
|
if (filters !== void 0 && filters !== over.selection.entity) throw new Error(`Remote: query "${by.name}" is over "${filters}", but the list is of "${over.selection.entity}", so it cannot filter it`);
|
|
6111
6134
|
const remote = store.get(model);
|
|
6112
6135
|
const connection = remote.connections[over.ref.identity];
|
|
6113
|
-
const visible = visibleStoreOf(remote.entities, remote.optimistic);
|
|
6136
|
+
const visible = visibleStoreOf(remote.entities, remote.optimistic, operators);
|
|
6114
6137
|
const among = (connection === void 0 ? [] : shownEdges(remote, over.ref.identity, connection)).map((edge) => entityKey(edge.ref.entity, edge.ref.id));
|
|
6115
6138
|
let judged;
|
|
6116
6139
|
try {
|
|
6117
|
-
judged = matching(visible, by, input, {
|
|
6140
|
+
judged = matching(visible, by, input, {
|
|
6141
|
+
among,
|
|
6142
|
+
operators
|
|
6143
|
+
});
|
|
6118
6144
|
} catch (error) {
|
|
6119
6145
|
if (error instanceof QueryEvaluateError) return {
|
|
6120
6146
|
items: [],
|
|
@@ -6351,7 +6377,6 @@ const pickWindow = (window) => ({
|
|
|
6351
6377
|
...window.after === void 0 ? {} : { after: window.after },
|
|
6352
6378
|
...window.before === void 0 ? {} : { before: window.before }
|
|
6353
6379
|
});
|
|
6354
|
-
//#endregion
|
|
6355
6380
|
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
6381
|
|
|
6357
|
-
//# sourceMappingURL=src-
|
|
6382
|
+
//# sourceMappingURL=src-lVP_7bf4.mjs.map
|