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.
- package/README.md +6 -0
- package/dist/{index-Bx_lCC85.d.mts → index-BEvVAL76.d.mts} +25 -61
- package/dist/index-BEvVAL76.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-BDqn7Ocr.mjs} +72 -85
- package/dist/src-BDqn7Ocr.mjs.map +1 -0
- package/package.json +2 -2
- 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, 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
|
-
|
|
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
|
*
|
|
@@ -612,8 +608,7 @@ const Mutation = {
|
|
|
612
608
|
Refusal: config.Refusal ?? Schema.Never
|
|
613
609
|
})
|
|
614
610
|
};
|
|
615
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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)
|
|
1763
|
-
* edge, if the list holds it, is left out:
|
|
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
|
-
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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, {
|
|
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, {
|
|
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-
|
|
6344
|
+
//# sourceMappingURL=src-BDqn7Ocr.mjs.map
|