@nkzw/fate 1.3.2 → 1.4.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/docs/api/classes/FateClient.md +40 -40
- package/docs/api/functions/clientRoot.md +1 -1
- package/docs/api/functions/createClient.md +1 -1
- package/docs/api/functions/createGraphQLTransport.md +1 -1
- package/docs/api/functions/createHTTPTransport.md +1 -1
- package/docs/api/functions/createTRPCTransport.md +1 -1
- package/docs/api/functions/defer.md +1 -1
- package/docs/api/functions/getDeferredMetadata.md +1 -1
- package/docs/api/functions/getListEntries.md +1 -1
- package/docs/api/functions/getSelectionPlan.md +1 -1
- package/docs/api/functions/graphqlMutation.md +1 -1
- package/docs/api/functions/isDeferred.md +1 -1
- package/docs/api/functions/isRecord.md +1 -1
- package/docs/api/functions/isViewTag.md +1 -1
- package/docs/api/functions/liveConnectionTopic.md +1 -1
- package/docs/api/functions/liveEntityTopic.md +1 -1
- package/docs/api/functions/liveGlobalConnectionTopic.md +1 -1
- package/docs/api/functions/mutation.md +1 -1
- package/docs/api/functions/toEntityId.md +1 -1
- package/docs/api/functions/view.md +1 -1
- package/docs/api/interfaces/FateThenable.md +3 -3
- package/docs/api/interfaces/Transport.md +7 -7
- package/docs/api/server/classes/FateRequestError.md +5 -5
- package/docs/api/server/drizzle/functions/createDrizzleFate.md +1 -1
- package/docs/api/server/drizzle/functions/createDrizzleSourceAdapter.md +1 -1
- package/docs/api/server/drizzle/functions/createDrizzleSourceRegistry.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyConfig.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyInput.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleQueryExtra.md +3 -3
- package/docs/api/server/drizzle/type-aliases/DrizzleSourceAdapter.md +9 -9
- package/docs/api/server/drizzle/type-aliases/DrizzleViewConfig.md +1 -1
- package/docs/api/server/functions/bindSourceProcedures.md +1 -1
- package/docs/api/server/functions/computed.md +1 -1
- package/docs/api/server/functions/count.md +1 -1
- package/docs/api/server/functions/createFateFetchHandler.md +1 -1
- package/docs/api/server/functions/createFateServer.md +1 -1
- package/docs/api/server/functions/createHonoFateHandler.md +1 -1
- package/docs/api/server/functions/createLiveEventBus.md +1 -1
- package/docs/api/server/functions/createNestedSourcePlan.md +1 -1
- package/docs/api/server/functions/createResolver.md +1 -1
- package/docs/api/server/functions/createSourcePlan.md +1 -1
- package/docs/api/server/functions/createSourceProcedures.md +1 -1
- package/docs/api/server/functions/dataView.md +1 -1
- package/docs/api/server/functions/field.md +1 -1
- package/docs/api/server/functions/getNestedSelection.md +1 -1
- package/docs/api/server/functions/getScopedArgs.md +1 -1
- package/docs/api/server/functions/hasNestedSelection.md +1 -1
- package/docs/api/server/functions/list.md +1 -1
- package/docs/api/server/functions/refetchSourceById.md +1 -1
- package/docs/api/server/functions/resolveSourceById.md +1 -1
- package/docs/api/server/functions/resolveSourceByIds.md +1 -1
- package/docs/api/server/functions/resolveSourceConnection.md +1 -1
- package/docs/api/server/functions/resolver.md +1 -1
- package/docs/api/server/functions/toPrismaSelect.md +1 -1
- package/docs/api/server/functions/withConnection.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaFate.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaSourceAdapter.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaSourceRegistry.md +1 -1
- package/docs/api/server/prisma/functions/prismaConnectionArgs.md +1 -1
- package/docs/api/server/prisma/type-aliases/PrismaDelegate.md +4 -4
- package/docs/api/server/prisma/type-aliases/PrismaQueryExtra.md +1 -1
- package/docs/api/server/prisma/type-aliases/PrismaSourceAdapter.md +9 -9
- package/docs/api/server/prisma/type-aliases/PrismaViewConfig.md +1 -1
- package/docs/api/server/type-aliases/ComputedField.md +5 -5
- package/docs/api/server/type-aliases/ComputedSelection.md +1 -1
- package/docs/api/server/type-aliases/ConnectionItem.md +3 -3
- package/docs/api/server/type-aliases/ConnectionPagination.md +5 -5
- package/docs/api/server/type-aliases/ConnectionResult.md +3 -3
- package/docs/api/server/type-aliases/CountSelection.md +4 -4
- package/docs/api/server/type-aliases/CountWhere.md +1 -1
- package/docs/api/server/type-aliases/DataViewListOptions.md +2 -2
- package/docs/api/server/type-aliases/DataViewOrderBy.md +1 -1
- package/docs/api/server/type-aliases/DataViewOrderDirection.md +1 -1
- package/docs/api/server/type-aliases/DataViewResult.md +1 -1
- package/docs/api/server/type-aliases/Entity.md +1 -1
- package/docs/api/server/type-aliases/FateServer.md +5 -5
- package/docs/api/server/type-aliases/FateServerManifest.md +1 -1
- package/docs/api/server/type-aliases/FieldSelection.md +3 -3
- package/docs/api/server/type-aliases/LiveConnectionEventType.md +1 -1
- package/docs/api/server/type-aliases/LiveConnectionSourceEvent.md +1 -1
- package/docs/api/server/type-aliases/LiveEventBus.md +1 -1
- package/docs/api/server/type-aliases/LiveEventType.md +1 -1
- package/docs/api/server/type-aliases/LiveSourceEvent.md +1 -1
- package/docs/api/server/type-aliases/NativeFateAPI.md +4 -4
- package/docs/api/server/type-aliases/OrderDirection.md +1 -1
- package/docs/api/server/type-aliases/SourceConfig.md +6 -6
- package/docs/api/server/type-aliases/SourceDefinition.md +6 -6
- package/docs/api/server/type-aliases/SourceOrder.md +1 -1
- package/docs/api/server/type-aliases/SourceOrderField.md +3 -3
- package/docs/api/server/type-aliases/SourcePlan.md +1 -1
- package/docs/api/server/type-aliases/SourcePlanNode.md +1 -1
- package/docs/api/server/type-aliases/SourceRegistry.md +1 -1
- package/docs/api/server/type-aliases/SourceRelation.md +1 -1
- package/docs/api/server/type-aliases/SourceRelationConfig.md +1 -1
- package/docs/api/server/variables/byIdInput.md +1 -1
- package/docs/api/server/variables/connectionArgs.md +1 -1
- package/docs/api/type-aliases/ConnectionMetadata.md +1 -1
- package/docs/api/type-aliases/ConnectionRef.md +1 -1
- package/docs/api/type-aliases/Deferred.md +1 -1
- package/docs/api/type-aliases/DeferredMetadata.md +1 -1
- package/docs/api/type-aliases/DeferredSelection.md +1 -1
- package/docs/api/type-aliases/DeferredSnapshot.md +1 -1
- package/docs/api/type-aliases/Entity.md +2 -2
- package/docs/api/type-aliases/EntityId.md +1 -1
- package/docs/api/type-aliases/FateDehydratedState.md +1 -1
- package/docs/api/type-aliases/FateLiveConnectionEvent.md +1 -1
- package/docs/api/type-aliases/FateLiveEvent.md +1 -1
- package/docs/api/type-aliases/FateMutations.md +1 -1
- package/docs/api/type-aliases/FateOperation.md +1 -1
- package/docs/api/type-aliases/FateProtocolRequest.md +1 -1
- package/docs/api/type-aliases/FateProtocolResponse.md +1 -1
- package/docs/api/type-aliases/FateRecord.md +1 -1
- package/docs/api/type-aliases/FateRoots.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationDefinition.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationInput.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationMap.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationOutput.md +1 -1
- package/docs/api/type-aliases/GraphQLTransportOptions.md +11 -11
- package/docs/api/type-aliases/HydrateOptions.md +1 -1
- package/docs/api/type-aliases/HydrationLimits.md +1 -1
- package/docs/api/type-aliases/InferFateAPI.md +1 -1
- package/docs/api/type-aliases/List.md +1 -1
- package/docs/api/type-aliases/ListEntry.md +1 -1
- package/docs/api/type-aliases/ListItem.md +1 -1
- package/docs/api/type-aliases/Mask.md +1 -1
- package/docs/api/type-aliases/MutationDefinition.md +1 -1
- package/docs/api/type-aliases/MutationEntity.md +1 -1
- package/docs/api/type-aliases/MutationIdentifier.md +1 -1
- package/docs/api/type-aliases/MutationInput.md +1 -1
- package/docs/api/type-aliases/MutationResult.md +1 -1
- package/docs/api/type-aliases/NodesItem.md +1 -1
- package/docs/api/type-aliases/Pagination.md +5 -5
- package/docs/api/type-aliases/Request.md +1 -1
- package/docs/api/type-aliases/RequestMode.md +1 -1
- package/docs/api/type-aliases/RequestOptions.md +1 -1
- package/docs/api/type-aliases/RequestResult.md +1 -1
- package/docs/api/type-aliases/Selection.md +1 -1
- package/docs/api/type-aliases/Snapshot.md +1 -1
- package/docs/api/type-aliases/TypeConfig.md +4 -4
- package/docs/api/type-aliases/View.md +1 -1
- package/docs/api/type-aliases/ViewData.md +1 -1
- package/docs/api/type-aliases/ViewEntity.md +1 -1
- package/docs/api/type-aliases/ViewEntityName.md +1 -1
- package/docs/api/type-aliases/ViewRef.md +1 -1
- package/docs/api/type-aliases/ViewSelection.md +1 -1
- package/docs/api/type-aliases/ViewSnapshot.md +1 -1
- package/docs/api/type-aliases/ViewTag.md +1 -1
- package/docs/api/variables/ConnectionTag.md +1 -1
- package/docs/api/variables/DeferTag.md +1 -1
- package/docs/api/variables/DeferredTag.md +1 -1
- package/lib/cli.d.mts +1 -1
- package/lib/{executor-C8HNogYG.d.mts → executor-BRudKWDY.d.mts} +18 -65
- package/lib/{graphqlTransport-DskuXeUP.d.mts → graphqlTransport-BDR1pnUQ.d.mts} +3 -14
- package/lib/graphqlTransport.d.mts +1 -1
- package/lib/index.d.mts +6 -15
- package/lib/index.mjs +711 -623
- package/lib/{list-sI2UPhHc.d.mts → list-Bb1SeABn.d.mts} +1 -2
- package/lib/list.d.mts +1 -1
- package/lib/{record-CZyyeLa3.d.mts → record-BTUXkHQU.d.mts} +9 -18
- package/lib/server/drizzle.d.mts +45 -114
- package/lib/server/drizzle.mjs +1 -1
- package/lib/server/prisma.d.mts +52 -127
- package/lib/server/prisma.mjs +8 -2
- package/lib/server.d.mts +4 -16
- package/lib/server.mjs +2 -28
- package/lib/{transport-DhaVVq4P.d.mts → transport-Bo1Jgo9R.d.mts} +76 -103
- package/lib/vite.d.mts +0 -1
- package/lib/vite.mjs +1 -1
- package/package.json +5 -5
package/lib/index.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import { t as getListEntries } from "./list-_6fXYLtJ.mjs";
|
|
|
4
4
|
import { n as graphqlMutation, t as createGraphQLTransport } from "./graphqlTransport-DSBVS2Fq.mjs";
|
|
5
5
|
//#region src/cache.ts
|
|
6
6
|
var ViewDataCache = class {
|
|
7
|
-
constructor() {
|
|
7
|
+
constructor(isEnabled = () => true) {
|
|
8
|
+
this.isEnabled = isEnabled;
|
|
8
9
|
this.cache = /* @__PURE__ */ new Map();
|
|
9
10
|
this.rootDependencies = /* @__PURE__ */ new Map();
|
|
10
11
|
this.dependencyIndex = /* @__PURE__ */ new Map();
|
|
@@ -15,9 +16,11 @@ var ViewDataCache = class {
|
|
|
15
16
|
this.dependencyIndex.clear();
|
|
16
17
|
}
|
|
17
18
|
get(entityId, view, ref) {
|
|
19
|
+
if (!this.isEnabled()) return null;
|
|
18
20
|
return this.cache.get(entityId)?.get(view)?.get(ref) ?? null;
|
|
19
21
|
}
|
|
20
22
|
set(entityId, view, ref, thenable, dependencies) {
|
|
23
|
+
if (!this.isEnabled()) return;
|
|
21
24
|
let entityMap = this.cache.get(entityId);
|
|
22
25
|
if (!entityMap) {
|
|
23
26
|
entityMap = /* @__PURE__ */ new WeakMap();
|
|
@@ -45,6 +48,7 @@ var ViewDataCache = class {
|
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
invalidate(entityId) {
|
|
51
|
+
if (!this.isEnabled()) return;
|
|
48
52
|
this.invalidateDependents(entityId, /* @__PURE__ */ new Set());
|
|
49
53
|
}
|
|
50
54
|
invalidateDependents(entityId, visited) {
|
|
@@ -351,94 +355,7 @@ const decodeClientHydrationState = (value, limits) => {
|
|
|
351
355
|
return decoded;
|
|
352
356
|
};
|
|
353
357
|
//#endregion
|
|
354
|
-
//#region
|
|
355
|
-
function emptyMask() {
|
|
356
|
-
return {
|
|
357
|
-
all: false,
|
|
358
|
-
children: /* @__PURE__ */ new Map()
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
function cloneMask(m) {
|
|
362
|
-
const clone = {
|
|
363
|
-
all: m.all,
|
|
364
|
-
children: /* @__PURE__ */ new Map()
|
|
365
|
-
};
|
|
366
|
-
for (const [key, value] of m.children) clone.children.set(key, cloneMask(value));
|
|
367
|
-
return clone;
|
|
368
|
-
}
|
|
369
|
-
function addPath(mask, path) {
|
|
370
|
-
if (mask.all) return;
|
|
371
|
-
const parts = path.split(".");
|
|
372
|
-
let current = mask;
|
|
373
|
-
for (let i = 0; i < parts.length; i++) {
|
|
374
|
-
const seg = parts[i];
|
|
375
|
-
let child = current.children.get(seg);
|
|
376
|
-
if (!child) {
|
|
377
|
-
child = emptyMask();
|
|
378
|
-
current.children.set(seg, child);
|
|
379
|
-
}
|
|
380
|
-
current = child;
|
|
381
|
-
}
|
|
382
|
-
current.all = true;
|
|
383
|
-
current.children.clear();
|
|
384
|
-
}
|
|
385
|
-
function union(into, b) {
|
|
386
|
-
if (into.all || b.all) {
|
|
387
|
-
into.all = true;
|
|
388
|
-
into.children.clear();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
for (const [key, child] of b.children) {
|
|
392
|
-
const exist = into.children.get(key);
|
|
393
|
-
if (!exist) into.children.set(key, cloneMask(child));
|
|
394
|
-
else union(exist, child);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
function fromPaths(paths) {
|
|
398
|
-
const mask = emptyMask();
|
|
399
|
-
for (const path of paths) addPath(mask, path);
|
|
400
|
-
return mask;
|
|
401
|
-
}
|
|
402
|
-
function toPaths(mask) {
|
|
403
|
-
const paths = [];
|
|
404
|
-
const visit = (current, prefix) => {
|
|
405
|
-
if (current.all) {
|
|
406
|
-
if (prefix) paths.push(prefix);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
for (const [key, child] of current.children) visit(child, prefix ? `${prefix}.${key}` : key);
|
|
410
|
-
};
|
|
411
|
-
visit(mask, null);
|
|
412
|
-
return paths;
|
|
413
|
-
}
|
|
414
|
-
function isCovered(mask, path) {
|
|
415
|
-
if (mask.all) return true;
|
|
416
|
-
const parts = path.split(".");
|
|
417
|
-
let current = mask;
|
|
418
|
-
for (let i = 0; i < parts.length; i++) {
|
|
419
|
-
if (!current) return false;
|
|
420
|
-
if (current.all) return true;
|
|
421
|
-
current = current.children.get(parts[i]);
|
|
422
|
-
}
|
|
423
|
-
return !!current && (current.all || current.children.size === 0);
|
|
424
|
-
}
|
|
425
|
-
function diffPaths(paths, mask) {
|
|
426
|
-
const missing = /* @__PURE__ */ new Set();
|
|
427
|
-
for (const path of paths) if (!isCovered(mask, path)) missing.add(path);
|
|
428
|
-
return missing;
|
|
429
|
-
}
|
|
430
|
-
function intersects(a, b) {
|
|
431
|
-
if (a.all || b.all) return true;
|
|
432
|
-
for (const [key, child] of a.children) {
|
|
433
|
-
const otherChild = b.children.get(key);
|
|
434
|
-
if (!otherChild) continue;
|
|
435
|
-
if (child.all || otherChild.all) return true;
|
|
436
|
-
if (intersects(child, otherChild)) return true;
|
|
437
|
-
}
|
|
438
|
-
return false;
|
|
439
|
-
}
|
|
440
|
-
//#endregion
|
|
441
|
-
//#region ../../node_modules/.pnpm/@trpc+server@11.18.0_typescript@6.0.3/node_modules/@trpc/server/dist/getErrorShape-BPSzUA7W.mjs
|
|
358
|
+
//#region ../../node_modules/.pnpm/@trpc+server@11.18.0_typescript@7.0.2/node_modules/@trpc/server/dist/getErrorShape-BPSzUA7W.mjs
|
|
442
359
|
var __create = Object.create;
|
|
443
360
|
var __defProp = Object.defineProperty;
|
|
444
361
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -828,38 +745,37 @@ function wrapMutation(client, identifier) {
|
|
|
828
745
|
} : optimistic : void 0;
|
|
829
746
|
const optimisticRecordId = optimisticRecord !== void 0 ? maybeGetId(config.getId, optimisticRecord) : null;
|
|
830
747
|
const optimisticEntityId = id != null ? toEntityId(identifier.entity, id) : optimisticRecordId != null ? toEntityId(identifier.entity, optimisticRecordId) : null;
|
|
831
|
-
const snapshots = /* @__PURE__ */ new Map();
|
|
832
|
-
const listSnapshots = deleteRecord || optimisticRecord ? /* @__PURE__ */ new Map() : void 0;
|
|
833
748
|
const optimisticSelection = optimisticRecord ? collectImplicitSelectedPaths(optimisticRecord) : void 0;
|
|
834
749
|
const selection = viewSelection || optimisticSelection ? /* @__PURE__ */ new Set([...viewSelection ? [...viewSelection] : [], ...optimisticSelection ? [...optimisticSelection] : []]) : /* @__PURE__ */ new Set();
|
|
835
750
|
if (deleteRecord && id == null) throw new Error(`fate: Mutation '${identifier.key}' requires an 'id' to delete.`);
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
751
|
+
const applyOptimistic = () => {
|
|
752
|
+
if (optimisticRecord && optimisticEntityId) client.write(identifier.entity, optimisticRecord, optimisticSelection ?? emptySet$1, plan, insert);
|
|
753
|
+
if (deleteRecord && id != null) client.deleteRecord(identifier.entity, id);
|
|
754
|
+
};
|
|
755
|
+
const settle = client.store.optimisticUpdate(applyOptimistic);
|
|
839
756
|
const performMutation = async () => {
|
|
840
757
|
try {
|
|
841
758
|
const result = await client.executeMutation(identifier.key, input, selection, {
|
|
842
759
|
args,
|
|
843
760
|
plan
|
|
844
761
|
});
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
762
|
+
const shouldWriteResult = result && typeof result === "object" && (!deleteRecord || Boolean(view));
|
|
763
|
+
settle(() => {
|
|
764
|
+
if (shouldWriteResult) {
|
|
765
|
+
const select = collectImplicitSelectedPaths(result);
|
|
766
|
+
client.write(identifier.entity, result, select, plan, insert);
|
|
767
|
+
const resultId = maybeGetId(config.getId, result);
|
|
768
|
+
if (optimisticEntityId && resultId != null) client.resolveOptimisticEntity(optimisticEntityId, toEntityId(identifier.entity, resultId));
|
|
769
|
+
if (optimisticRecordId != null && resultId != null && optimisticRecordId !== resultId) client.deleteRecord(identifier.entity, optimisticRecordId);
|
|
770
|
+
}
|
|
850
771
|
if (deleteRecord && id != null) client.deleteRecord(identifier.entity, id);
|
|
851
|
-
|
|
852
|
-
if (optimisticEntityId && resultId != null) client.resolveOptimisticEntity(optimisticEntityId, toEntityId(identifier.entity, resultId));
|
|
853
|
-
if (optimisticRecordId != null && resultId != null && optimisticRecordId !== resultId) client.deleteRecord(identifier.entity, optimisticRecordId);
|
|
854
|
-
}
|
|
772
|
+
});
|
|
855
773
|
return {
|
|
856
774
|
error: void 0,
|
|
857
775
|
result
|
|
858
776
|
};
|
|
859
777
|
} catch (error) {
|
|
860
|
-
|
|
861
|
-
if (snapshots.size > 0) for (const [id, snapshot] of snapshots) client.restore(id, snapshot);
|
|
862
|
-
if (listSnapshots && listSnapshots.size > 0) for (const [name, list] of listSnapshots) client.restoreList(name, list);
|
|
778
|
+
settle();
|
|
863
779
|
if (error instanceof Error) {
|
|
864
780
|
const statusCode = getErrorStatusCode(error);
|
|
865
781
|
if ((statusCode ? categorizeHTTPErrorStatus(statusCode) : "boundary") === "boundary") throw error;
|
|
@@ -867,9 +783,7 @@ function wrapMutation(client, identifier) {
|
|
|
867
783
|
error,
|
|
868
784
|
result: void 0
|
|
869
785
|
};
|
|
870
|
-
} else throw new Error(`fate: Mutation '${identifier.key}' failed
|
|
871
|
-
} finally {
|
|
872
|
-
client.clearOptimisticUpdate(optimisticToken);
|
|
786
|
+
} else throw new Error(`fate: Mutation '${identifier.key}' failed.`, { cause: error });
|
|
873
787
|
}
|
|
874
788
|
};
|
|
875
789
|
const mutationPromise = client.trackPendingRequest(performMutation);
|
|
@@ -956,6 +870,93 @@ var OperationLifetime = class {
|
|
|
956
870
|
}
|
|
957
871
|
};
|
|
958
872
|
//#endregion
|
|
873
|
+
//#region src/mask.ts
|
|
874
|
+
function emptyMask() {
|
|
875
|
+
return {
|
|
876
|
+
all: false,
|
|
877
|
+
children: /* @__PURE__ */ new Map()
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function cloneMask(m) {
|
|
881
|
+
const clone = {
|
|
882
|
+
all: m.all,
|
|
883
|
+
children: /* @__PURE__ */ new Map()
|
|
884
|
+
};
|
|
885
|
+
for (const [key, value] of m.children) clone.children.set(key, cloneMask(value));
|
|
886
|
+
return clone;
|
|
887
|
+
}
|
|
888
|
+
function addPath(mask, path) {
|
|
889
|
+
if (mask.all) return;
|
|
890
|
+
const parts = path.split(".");
|
|
891
|
+
let current = mask;
|
|
892
|
+
for (let i = 0; i < parts.length; i++) {
|
|
893
|
+
const seg = parts[i];
|
|
894
|
+
let child = current.children.get(seg);
|
|
895
|
+
if (!child) {
|
|
896
|
+
child = emptyMask();
|
|
897
|
+
current.children.set(seg, child);
|
|
898
|
+
}
|
|
899
|
+
current = child;
|
|
900
|
+
}
|
|
901
|
+
current.all = true;
|
|
902
|
+
current.children.clear();
|
|
903
|
+
}
|
|
904
|
+
function union(into, b) {
|
|
905
|
+
if (into.all || b.all) {
|
|
906
|
+
into.all = true;
|
|
907
|
+
into.children.clear();
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
for (const [key, child] of b.children) {
|
|
911
|
+
const exist = into.children.get(key);
|
|
912
|
+
if (!exist) into.children.set(key, cloneMask(child));
|
|
913
|
+
else union(exist, child);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function fromPaths(paths) {
|
|
917
|
+
const mask = emptyMask();
|
|
918
|
+
for (const path of paths) addPath(mask, path);
|
|
919
|
+
return mask;
|
|
920
|
+
}
|
|
921
|
+
function toPaths(mask) {
|
|
922
|
+
const paths = [];
|
|
923
|
+
const visit = (current, prefix) => {
|
|
924
|
+
if (current.all) {
|
|
925
|
+
if (prefix) paths.push(prefix);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
for (const [key, child] of current.children) visit(child, prefix ? `${prefix}.${key}` : key);
|
|
929
|
+
};
|
|
930
|
+
visit(mask, null);
|
|
931
|
+
return paths;
|
|
932
|
+
}
|
|
933
|
+
function isCovered(mask, path) {
|
|
934
|
+
if (mask.all) return true;
|
|
935
|
+
const parts = path.split(".");
|
|
936
|
+
let current = mask;
|
|
937
|
+
for (let i = 0; i < parts.length; i++) {
|
|
938
|
+
if (!current) return false;
|
|
939
|
+
if (current.all) return true;
|
|
940
|
+
current = current.children.get(parts[i]);
|
|
941
|
+
}
|
|
942
|
+
return !!current && (current.all || current.children.size === 0);
|
|
943
|
+
}
|
|
944
|
+
function diffPaths(paths, mask) {
|
|
945
|
+
const missing = /* @__PURE__ */ new Set();
|
|
946
|
+
for (const path of paths) if (!isCovered(mask, path)) missing.add(path);
|
|
947
|
+
return missing;
|
|
948
|
+
}
|
|
949
|
+
function intersects(a, b) {
|
|
950
|
+
if (a.all || b.all) return true;
|
|
951
|
+
for (const [key, child] of a.children) {
|
|
952
|
+
const otherChild = b.children.get(key);
|
|
953
|
+
if (!otherChild) continue;
|
|
954
|
+
if (child.all || otherChild.all) return true;
|
|
955
|
+
if (intersects(child, otherChild)) return true;
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
//#endregion
|
|
959
960
|
//#region src/store.ts
|
|
960
961
|
const listKeySeparator = " __fate__ ";
|
|
961
962
|
const decodeListKeyPart = (part) => {
|
|
@@ -977,16 +978,6 @@ const parseListKey = (key) => {
|
|
|
977
978
|
ownerId: decodeListKeyPart(ownerId)
|
|
978
979
|
};
|
|
979
980
|
};
|
|
980
|
-
const cloneValue = (value) => {
|
|
981
|
-
if (Array.isArray(value)) return value.map(cloneValue);
|
|
982
|
-
if (isNodeRef(value)) return value;
|
|
983
|
-
if (value != null && typeof value === "object") {
|
|
984
|
-
const result = {};
|
|
985
|
-
for (const [key, record] of Object.entries(value)) result[key] = cloneValue(record);
|
|
986
|
-
return result;
|
|
987
|
-
}
|
|
988
|
-
return value;
|
|
989
|
-
};
|
|
990
981
|
const isPlainRecord = (value) => {
|
|
991
982
|
if (value == null || typeof value !== "object" || Array.isArray(value) || isNodeRef(value)) return false;
|
|
992
983
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -1021,14 +1012,17 @@ const areHydrationValuesEqual = (left, right) => {
|
|
|
1021
1012
|
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(right, key) && areHydrationValuesEqual(left[key], right[key]));
|
|
1022
1013
|
};
|
|
1023
1014
|
const areMasksEqual = (left, right) => {
|
|
1024
|
-
if (
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
return
|
|
1015
|
+
if (left === right || left?.all && right?.all) return true;
|
|
1016
|
+
if (!left || !right || left.all !== right.all || left.children.size !== right.children.size) return false;
|
|
1017
|
+
for (const [key, child] of left.children) if (!areMasksEqual(child, right.children.get(key))) return false;
|
|
1018
|
+
return true;
|
|
1028
1019
|
};
|
|
1029
1020
|
const emptyFunction = () => {};
|
|
1021
|
+
const hasReferences = (value) => isNodeRef(value) || Array.isArray(value) && value.some(isNodeRef);
|
|
1022
|
+
const areNormalizedValuesEqual = (left, right) => Object.is(left, right) || isNodeRef(left) && isNodeRef(right) && getNodeRefId(left) === getNodeRefId(right) || Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => areNormalizedValuesEqual(value, right[index]));
|
|
1030
1023
|
var Store = class {
|
|
1031
|
-
constructor() {
|
|
1024
|
+
constructor(onRebase) {
|
|
1025
|
+
this.onRebase = onRebase;
|
|
1032
1026
|
this.coverage = /* @__PURE__ */ new Map();
|
|
1033
1027
|
this.listKeysByOwnerField = /* @__PURE__ */ new Map();
|
|
1034
1028
|
this.listKeysByReferencedEntity = /* @__PURE__ */ new Map();
|
|
@@ -1038,6 +1032,142 @@ var Store = class {
|
|
|
1038
1032
|
this.records = /* @__PURE__ */ new Map();
|
|
1039
1033
|
this.subscriptions = /* @__PURE__ */ new Map();
|
|
1040
1034
|
this.listSubscriptions = /* @__PURE__ */ new Map();
|
|
1035
|
+
this.optimisticLayers = /* @__PURE__ */ new Set();
|
|
1036
|
+
this.optimisticBase = {
|
|
1037
|
+
lists: /* @__PURE__ */ new Map(),
|
|
1038
|
+
records: /* @__PURE__ */ new Map()
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
get hasOptimisticUpdates() {
|
|
1042
|
+
return this.optimisticLayers.size > 0;
|
|
1043
|
+
}
|
|
1044
|
+
get isRebasing() {
|
|
1045
|
+
return this.rebase !== void 0;
|
|
1046
|
+
}
|
|
1047
|
+
/** Apply a synchronous cache update beneath the pending optimistic layers. */
|
|
1048
|
+
update(apply) {
|
|
1049
|
+
if (this.rebase || this.optimisticLayers.size === 0) return apply();
|
|
1050
|
+
const rebase = {
|
|
1051
|
+
lists: /* @__PURE__ */ new Map(),
|
|
1052
|
+
records: /* @__PURE__ */ new Map()
|
|
1053
|
+
};
|
|
1054
|
+
this.rebase = rebase;
|
|
1055
|
+
try {
|
|
1056
|
+
for (const [id, snapshot] of this.optimisticBase.records) this.restore(id, snapshot);
|
|
1057
|
+
for (const [key, list] of this.optimisticBase.lists) this.restoreList(key, list);
|
|
1058
|
+
this.optimisticBase.records.clear();
|
|
1059
|
+
this.optimisticBase.lists.clear();
|
|
1060
|
+
return apply();
|
|
1061
|
+
} finally {
|
|
1062
|
+
try {
|
|
1063
|
+
for (const layer of this.optimisticLayers) {
|
|
1064
|
+
layer.writes.clear();
|
|
1065
|
+
this.recordingLayer = layer;
|
|
1066
|
+
layer.apply();
|
|
1067
|
+
}
|
|
1068
|
+
} finally {
|
|
1069
|
+
this.recordingLayer = void 0;
|
|
1070
|
+
const records = this.getRebaseChanges(rebase);
|
|
1071
|
+
const lists = /* @__PURE__ */ new Set();
|
|
1072
|
+
for (const [key, before] of rebase.lists) if (!areHydrationValuesEqual(before, this.lists.get(key))) {
|
|
1073
|
+
lists.add(key);
|
|
1074
|
+
const owner = parseListKey(key);
|
|
1075
|
+
if (owner) {
|
|
1076
|
+
if (!records.has(owner.ownerId)) records.set(owner.ownerId, /* @__PURE__ */ new Set([owner.field]));
|
|
1077
|
+
else records.get(owner.ownerId)?.add(owner.field);
|
|
1078
|
+
}
|
|
1079
|
+
} else if (before) this.lists.set(key, before);
|
|
1080
|
+
this.rebase = void 0;
|
|
1081
|
+
this.onRebase?.(new Set(records.keys()));
|
|
1082
|
+
for (const [id, paths] of records) this.notify(id, paths);
|
|
1083
|
+
for (const key of lists) this.notifyListSubscribers(key);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
getRebaseChanges(rebase) {
|
|
1088
|
+
const changes = /* @__PURE__ */ new Map();
|
|
1089
|
+
for (const [id, before] of rebase.records) {
|
|
1090
|
+
const after = this.records.get(id);
|
|
1091
|
+
const mask = this.coverage.get(id);
|
|
1092
|
+
if (Boolean(before.record) !== Boolean(after) || before.mask?.all !== mask?.all) {
|
|
1093
|
+
changes.set(id, void 0);
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1097
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(before.record ?? {}), ...Object.keys(after ?? {})])) if (Object.hasOwn(before.record ?? {}, key) !== Object.hasOwn(after ?? {}, key) || !areNormalizedValuesEqual(before.record?.[key], after?.[key])) paths.add(key);
|
|
1098
|
+
if (!areMasksEqual(before.mask, mask)) {
|
|
1099
|
+
for (const path of before.mask ? toPaths(before.mask) : []) if (!mask || !isCovered(mask, path)) paths.add(path);
|
|
1100
|
+
for (const path of mask ? toPaths(mask) : []) if (!before.mask || !isCovered(before.mask, path)) paths.add(path);
|
|
1101
|
+
}
|
|
1102
|
+
if (paths.size > 0) changes.set(id, paths);
|
|
1103
|
+
else if (before.record) this.records.set(id, before.record);
|
|
1104
|
+
}
|
|
1105
|
+
return changes;
|
|
1106
|
+
}
|
|
1107
|
+
/** Returns an idempotent settlement function; omit its update to roll back. */
|
|
1108
|
+
optimisticUpdate(apply) {
|
|
1109
|
+
const layer = {
|
|
1110
|
+
apply,
|
|
1111
|
+
writes: /* @__PURE__ */ new Map()
|
|
1112
|
+
};
|
|
1113
|
+
const settle = (commit) => {
|
|
1114
|
+
if (!this.optimisticLayers.has(layer) || layer.settled) return;
|
|
1115
|
+
this.update(() => {
|
|
1116
|
+
const overlays = commit ? this.getPendingOverlap(layer, layer.writes) : /* @__PURE__ */ new Map();
|
|
1117
|
+
if (overlays.size > 0) {
|
|
1118
|
+
layer.settled = true;
|
|
1119
|
+
layer.apply = () => {
|
|
1120
|
+
for (const [id, { partial, paths }] of this.getPendingOverlap(layer, overlays)) this.merge(id, partial, paths);
|
|
1121
|
+
};
|
|
1122
|
+
} else this.optimisticLayers.delete(layer);
|
|
1123
|
+
for (const pending of this.optimisticLayers) {
|
|
1124
|
+
if (!pending.settled) break;
|
|
1125
|
+
this.optimisticLayers.delete(pending);
|
|
1126
|
+
}
|
|
1127
|
+
commit?.();
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
this.optimisticLayers.add(layer);
|
|
1131
|
+
try {
|
|
1132
|
+
this.update(() => {});
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
settle();
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
return settle;
|
|
1138
|
+
}
|
|
1139
|
+
getPendingOverlap(layer, writes) {
|
|
1140
|
+
const earlier = [];
|
|
1141
|
+
for (const pending of this.optimisticLayers) {
|
|
1142
|
+
if (pending === layer) break;
|
|
1143
|
+
if (!pending.settled) earlier.push(pending);
|
|
1144
|
+
}
|
|
1145
|
+
const overlaps = /* @__PURE__ */ new Map();
|
|
1146
|
+
for (const [id, write] of writes) {
|
|
1147
|
+
const partial = Object.fromEntries(Object.entries(write.partial).filter(([key, value]) => !hasReferences(value) && earlier.some(({ writes }) => {
|
|
1148
|
+
const previous = writes.get(id)?.partial;
|
|
1149
|
+
return previous && Object.hasOwn(previous, key) && !hasReferences(previous[key]);
|
|
1150
|
+
})));
|
|
1151
|
+
if (Object.keys(partial).length) overlaps.set(id, {
|
|
1152
|
+
partial,
|
|
1153
|
+
paths: new Set([...write.paths].filter((path) => Object.hasOwn(partial, path.split(".")[0])))
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
return overlaps;
|
|
1157
|
+
}
|
|
1158
|
+
captureRecord(id) {
|
|
1159
|
+
if (!this.rebase) return;
|
|
1160
|
+
for (const target of [this.rebase, this.recordingLayer && this.optimisticBase]) if (target && !target.records.has(id)) {
|
|
1161
|
+
const mask = this.coverage.get(id);
|
|
1162
|
+
target.records.set(id, {
|
|
1163
|
+
mask: mask ? cloneMask(mask) : void 0,
|
|
1164
|
+
record: this.records.get(id)
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
captureList(key) {
|
|
1169
|
+
if (!this.rebase) return;
|
|
1170
|
+
for (const target of [this.rebase, this.recordingLayer && this.optimisticBase]) if (target && !target.lists.has(key)) target.lists.set(key, this.lists.get(key));
|
|
1041
1171
|
}
|
|
1042
1172
|
dehydrate() {
|
|
1043
1173
|
return {
|
|
@@ -1095,10 +1225,23 @@ var Store = class {
|
|
|
1095
1225
|
return this.records.get(id);
|
|
1096
1226
|
}
|
|
1097
1227
|
merge(id, partial, paths) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1228
|
+
return this.update(() => {
|
|
1229
|
+
const changedPaths = this.mergeInternal(id, partial, paths);
|
|
1230
|
+
if (changedPaths) this.notify(id, changedPaths);
|
|
1231
|
+
});
|
|
1100
1232
|
}
|
|
1101
1233
|
mergeInternal(id, partial, paths) {
|
|
1234
|
+
this.captureRecord(id);
|
|
1235
|
+
const selectedPaths = this.recordingLayer ? new Set(paths) : paths;
|
|
1236
|
+
if (this.recordingLayer) {
|
|
1237
|
+
const write = this.recordingLayer.writes.get(id) ?? {
|
|
1238
|
+
partial: {},
|
|
1239
|
+
paths: /* @__PURE__ */ new Set()
|
|
1240
|
+
};
|
|
1241
|
+
Object.assign(write.partial, partial);
|
|
1242
|
+
for (const path of selectedPaths) write.paths.add(path);
|
|
1243
|
+
this.recordingLayer.writes.set(id, write);
|
|
1244
|
+
}
|
|
1102
1245
|
const previous = this.records.get(id);
|
|
1103
1246
|
const changedPaths = /* @__PURE__ */ new Set();
|
|
1104
1247
|
let mask = this.coverage.get(id);
|
|
@@ -1106,7 +1249,7 @@ var Store = class {
|
|
|
1106
1249
|
mask = emptyMask();
|
|
1107
1250
|
this.coverage.set(id, mask);
|
|
1108
1251
|
}
|
|
1109
|
-
union(mask, fromPaths(
|
|
1252
|
+
union(mask, fromPaths(selectedPaths));
|
|
1110
1253
|
if (previous) {
|
|
1111
1254
|
let hasChanges = false;
|
|
1112
1255
|
for (const [key, value] of Object.entries(partial)) if (previous[key] !== value) {
|
|
@@ -1128,10 +1271,13 @@ var Store = class {
|
|
|
1128
1271
|
return changedPaths;
|
|
1129
1272
|
}
|
|
1130
1273
|
deleteRecord(id) {
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1274
|
+
return this.update(() => {
|
|
1275
|
+
this.captureRecord(id);
|
|
1276
|
+
const record = this.records.get(id);
|
|
1277
|
+
if (record) this.removeRecordReferenceIndexes(id, record);
|
|
1278
|
+
this.records.delete(id);
|
|
1279
|
+
this.coverage.delete(id);
|
|
1280
|
+
});
|
|
1135
1281
|
}
|
|
1136
1282
|
missingForSelection(id, paths) {
|
|
1137
1283
|
const requested = new Set(paths);
|
|
@@ -1166,6 +1312,7 @@ var Store = class {
|
|
|
1166
1312
|
};
|
|
1167
1313
|
}
|
|
1168
1314
|
notify(id, paths) {
|
|
1315
|
+
if (this.rebase) return;
|
|
1169
1316
|
const set = this.subscriptions.get(id);
|
|
1170
1317
|
if (!set) return;
|
|
1171
1318
|
const changedPaths = paths ? [...paths] : [];
|
|
@@ -1178,6 +1325,7 @@ var Store = class {
|
|
|
1178
1325
|
}
|
|
1179
1326
|
}
|
|
1180
1327
|
notifyListSubscribers(key) {
|
|
1328
|
+
if (this.rebase) return;
|
|
1181
1329
|
const set = this.listSubscriptions.get(key);
|
|
1182
1330
|
if (!set) return;
|
|
1183
1331
|
for (const fn of set) try {
|
|
@@ -1201,70 +1349,77 @@ var Store = class {
|
|
|
1201
1349
|
return entries;
|
|
1202
1350
|
}
|
|
1203
1351
|
setList(key, state) {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1352
|
+
return this.update(() => {
|
|
1353
|
+
this.captureList(key);
|
|
1354
|
+
const previous = this.lists.get(key);
|
|
1355
|
+
if (previous) this.removeListIndexes(key, previous);
|
|
1356
|
+
this.lists.set(key, state);
|
|
1357
|
+
this.addListIndexes(key, state);
|
|
1358
|
+
this.notifyListSubscribers(key);
|
|
1359
|
+
});
|
|
1209
1360
|
}
|
|
1210
1361
|
replaceListEntityId(previousId, nextId) {
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1362
|
+
return this.update(() => {
|
|
1363
|
+
const keys = [...this.listKeysByReferencedEntity.get(previousId) ?? []];
|
|
1364
|
+
for (const key of keys) {
|
|
1365
|
+
const list = this.lists.get(key);
|
|
1366
|
+
if (!list) continue;
|
|
1367
|
+
let changed = false;
|
|
1368
|
+
let ids = list.ids;
|
|
1369
|
+
let cursors = list.cursors;
|
|
1370
|
+
if (list.ids.includes(previousId)) {
|
|
1371
|
+
const nextIds = [];
|
|
1372
|
+
const nextCursors = list.cursors ? [] : void 0;
|
|
1373
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1374
|
+
list.ids.forEach((id, index) => {
|
|
1375
|
+
const resolved = id === previousId ? nextId : id;
|
|
1376
|
+
if (seenIds.has(resolved)) return;
|
|
1377
|
+
seenIds.add(resolved);
|
|
1378
|
+
nextIds.push(resolved);
|
|
1379
|
+
if (nextCursors) nextCursors.push(list.cursors?.[index]);
|
|
1380
|
+
});
|
|
1381
|
+
changed = true;
|
|
1382
|
+
ids = nextIds;
|
|
1383
|
+
cursors = nextCursors;
|
|
1384
|
+
}
|
|
1385
|
+
const dedupe = (values) => {
|
|
1386
|
+
if (!values || !values.includes(previousId)) return;
|
|
1387
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1388
|
+
const next = [];
|
|
1389
|
+
for (const value of values) {
|
|
1390
|
+
const resolved = value === previousId ? nextId : value;
|
|
1391
|
+
if (seen.has(resolved)) continue;
|
|
1392
|
+
seen.add(resolved);
|
|
1393
|
+
next.push(resolved);
|
|
1394
|
+
}
|
|
1395
|
+
changed = true;
|
|
1396
|
+
return next;
|
|
1397
|
+
};
|
|
1398
|
+
const pendingBeforeIds = dedupe(list.pendingBeforeIds) ?? list.pendingBeforeIds;
|
|
1399
|
+
const pendingAfterIds = dedupe(list.pendingAfterIds) ?? list.pendingAfterIds;
|
|
1400
|
+
const liveBeforeIds = dedupe(list.liveBeforeIds) ?? list.liveBeforeIds;
|
|
1401
|
+
const liveAfterIds = dedupe(list.liveAfterIds) ?? list.liveAfterIds;
|
|
1402
|
+
if (!changed) continue;
|
|
1403
|
+
const canonicalIds = new Set(ids);
|
|
1404
|
+
this.setList(key, {
|
|
1405
|
+
backwardPageLimit: list.backwardPageLimit,
|
|
1406
|
+
cursors,
|
|
1407
|
+
forwardPageLimit: list.forwardPageLimit,
|
|
1408
|
+
ids,
|
|
1409
|
+
liveAfterIds: liveAfterIds?.filter((id) => !canonicalIds.has(id)),
|
|
1410
|
+
liveBeforeIds: liveBeforeIds?.filter((id) => !canonicalIds.has(id)),
|
|
1411
|
+
pagination: list.pagination,
|
|
1412
|
+
pendingAfterIds: pendingAfterIds?.filter((id) => !canonicalIds.has(id)),
|
|
1413
|
+
pendingBeforeIds: pendingBeforeIds?.filter((id) => !canonicalIds.has(id))
|
|
1228
1414
|
});
|
|
1229
|
-
changed = true;
|
|
1230
|
-
ids = nextIds;
|
|
1231
|
-
cursors = nextCursors;
|
|
1232
1415
|
}
|
|
1233
|
-
|
|
1234
|
-
if (!values || !values.includes(previousId)) return;
|
|
1235
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1236
|
-
const next = [];
|
|
1237
|
-
for (const value of values) {
|
|
1238
|
-
const resolved = value === previousId ? nextId : value;
|
|
1239
|
-
if (seen.has(resolved)) continue;
|
|
1240
|
-
seen.add(resolved);
|
|
1241
|
-
next.push(resolved);
|
|
1242
|
-
}
|
|
1243
|
-
changed = true;
|
|
1244
|
-
return next;
|
|
1245
|
-
};
|
|
1246
|
-
const pendingBeforeIds = dedupe(list.pendingBeforeIds) ?? list.pendingBeforeIds;
|
|
1247
|
-
const pendingAfterIds = dedupe(list.pendingAfterIds) ?? list.pendingAfterIds;
|
|
1248
|
-
const liveBeforeIds = dedupe(list.liveBeforeIds) ?? list.liveBeforeIds;
|
|
1249
|
-
const liveAfterIds = dedupe(list.liveAfterIds) ?? list.liveAfterIds;
|
|
1250
|
-
if (!changed) continue;
|
|
1251
|
-
const canonicalIds = new Set(ids);
|
|
1252
|
-
this.setList(key, {
|
|
1253
|
-
backwardPageLimit: list.backwardPageLimit,
|
|
1254
|
-
cursors,
|
|
1255
|
-
forwardPageLimit: list.forwardPageLimit,
|
|
1256
|
-
ids,
|
|
1257
|
-
liveAfterIds: liveAfterIds?.filter((id) => !canonicalIds.has(id)),
|
|
1258
|
-
liveBeforeIds: liveBeforeIds?.filter((id) => !canonicalIds.has(id)),
|
|
1259
|
-
pagination: list.pagination,
|
|
1260
|
-
pendingAfterIds: pendingAfterIds?.filter((id) => !canonicalIds.has(id)),
|
|
1261
|
-
pendingBeforeIds: pendingBeforeIds?.filter((id) => !canonicalIds.has(id))
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1416
|
+
});
|
|
1264
1417
|
}
|
|
1265
1418
|
restoreList(key, list) {
|
|
1266
|
-
|
|
1267
|
-
|
|
1419
|
+
return this.update(() => {
|
|
1420
|
+
if (list == null) this.deleteList(key);
|
|
1421
|
+
else this.setList(key, list);
|
|
1422
|
+
});
|
|
1268
1423
|
}
|
|
1269
1424
|
collectGarbage(markedRecords, markedLists, options = {}) {
|
|
1270
1425
|
const records = /* @__PURE__ */ new Set();
|
|
@@ -1291,10 +1446,13 @@ var Store = class {
|
|
|
1291
1446
|
};
|
|
1292
1447
|
}
|
|
1293
1448
|
deleteList(key) {
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1449
|
+
return this.update(() => {
|
|
1450
|
+
this.captureList(key);
|
|
1451
|
+
const previous = this.lists.get(key);
|
|
1452
|
+
if (previous) this.removeListIndexes(key, previous);
|
|
1453
|
+
this.lists.delete(key);
|
|
1454
|
+
this.notifyListSubscribers(key);
|
|
1455
|
+
});
|
|
1298
1456
|
}
|
|
1299
1457
|
subscribeList(key, fn) {
|
|
1300
1458
|
let set = this.listSubscriptions.get(key);
|
|
@@ -1310,88 +1468,83 @@ var Store = class {
|
|
|
1310
1468
|
if (subscribers.size === 0) this.listSubscriptions.delete(key);
|
|
1311
1469
|
};
|
|
1312
1470
|
}
|
|
1313
|
-
removeReferencesTo(targetId, viewDataCache
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
const
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1471
|
+
removeReferencesTo(targetId, viewDataCache) {
|
|
1472
|
+
return this.update(() => {
|
|
1473
|
+
const listKeys = [...this.listKeysByReferencedEntity.get(targetId) ?? []];
|
|
1474
|
+
for (const key of listKeys) {
|
|
1475
|
+
const list = this.lists.get(key);
|
|
1476
|
+
if (!list) continue;
|
|
1477
|
+
const { ids } = list;
|
|
1478
|
+
const hasLiveAfter = Boolean(list.liveAfterIds?.includes(targetId));
|
|
1479
|
+
const hasLiveBefore = Boolean(list.liveBeforeIds?.includes(targetId));
|
|
1480
|
+
const hasPendingAfter = Boolean(list.pendingAfterIds?.includes(targetId));
|
|
1481
|
+
const hasPendingBefore = Boolean(list.pendingBeforeIds?.includes(targetId));
|
|
1482
|
+
if (!ids.includes(targetId) && !hasLiveAfter && !hasLiveBefore && !hasPendingAfter && !hasPendingBefore) continue;
|
|
1483
|
+
const entityIds = [];
|
|
1484
|
+
const cursors = list.cursors ? [] : void 0;
|
|
1485
|
+
for (let index = 0; index < ids.length; index++) {
|
|
1486
|
+
const id = ids[index];
|
|
1487
|
+
if (id === targetId) continue;
|
|
1488
|
+
entityIds.push(id);
|
|
1489
|
+
if (cursors) cursors.push(list.cursors?.[index]);
|
|
1490
|
+
}
|
|
1491
|
+
this.setList(key, {
|
|
1492
|
+
backwardPageLimit: list.backwardPageLimit,
|
|
1493
|
+
cursors,
|
|
1494
|
+
forwardPageLimit: list.forwardPageLimit,
|
|
1495
|
+
ids: entityIds,
|
|
1496
|
+
liveAfterIds: list.liveAfterIds?.filter((id) => id !== targetId),
|
|
1497
|
+
liveBeforeIds: list.liveBeforeIds?.filter((id) => id !== targetId),
|
|
1498
|
+
pagination: list.pagination,
|
|
1499
|
+
pendingAfterIds: list.pendingAfterIds?.filter((id) => id !== targetId),
|
|
1500
|
+
pendingBeforeIds: list.pendingBeforeIds?.filter((id) => id !== targetId)
|
|
1501
|
+
});
|
|
1332
1502
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
const next = {};
|
|
1352
|
-
const paths = /* @__PURE__ */ new Set();
|
|
1353
|
-
for (const key of fields) {
|
|
1354
|
-
const value = record[key];
|
|
1355
|
-
if (Array.isArray(value)) {
|
|
1356
|
-
const filtered = value.filter((item) => !(isNodeRef(item) && getNodeRefId(item) === targetId));
|
|
1357
|
-
if (filtered.length !== value.length) {
|
|
1503
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1504
|
+
const recordEntries = [...this.recordReferencesByTarget.get(targetId)?.entries() ?? []];
|
|
1505
|
+
for (const [id, fields] of recordEntries) {
|
|
1506
|
+
const record = this.records.get(id);
|
|
1507
|
+
if (!record) continue;
|
|
1508
|
+
let updated = false;
|
|
1509
|
+
const next = {};
|
|
1510
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1511
|
+
for (const key of fields) {
|
|
1512
|
+
const value = record[key];
|
|
1513
|
+
if (Array.isArray(value)) {
|
|
1514
|
+
const filtered = value.filter((item) => !(isNodeRef(item) && getNodeRefId(item) === targetId));
|
|
1515
|
+
if (filtered.length !== value.length) {
|
|
1516
|
+
updated = true;
|
|
1517
|
+
paths.add(key);
|
|
1518
|
+
next[key] = filtered;
|
|
1519
|
+
}
|
|
1520
|
+
} else if (isNodeRef(value) && getNodeRefId(value) === targetId) {
|
|
1358
1521
|
updated = true;
|
|
1359
1522
|
paths.add(key);
|
|
1360
|
-
next[key] =
|
|
1523
|
+
next[key] = null;
|
|
1361
1524
|
}
|
|
1362
|
-
} else if (isNodeRef(value) && getNodeRefId(value) === targetId) {
|
|
1363
|
-
updated = true;
|
|
1364
|
-
paths.add(key);
|
|
1365
|
-
next[key] = null;
|
|
1366
1525
|
}
|
|
1526
|
+
if (!updated) continue;
|
|
1527
|
+
viewDataCache.invalidate(id);
|
|
1528
|
+
this.mergeInternal(id, next, paths);
|
|
1529
|
+
ids.set(id, paths);
|
|
1367
1530
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
viewDataCache.invalidate(id);
|
|
1371
|
-
this.mergeInternal(id, next, paths);
|
|
1372
|
-
ids.set(id, paths);
|
|
1373
|
-
}
|
|
1374
|
-
for (const [id, paths] of ids) this.notify(id, paths);
|
|
1375
|
-
}
|
|
1376
|
-
snapshot(id) {
|
|
1377
|
-
const record = this.records.get(id);
|
|
1378
|
-
const mask = this.coverage.get(id);
|
|
1379
|
-
return {
|
|
1380
|
-
mask: mask ? cloneMask(mask) : void 0,
|
|
1381
|
-
record: record ? cloneValue(record) : void 0
|
|
1382
|
-
};
|
|
1531
|
+
for (const [id, paths] of ids) this.notify(id, paths);
|
|
1532
|
+
});
|
|
1383
1533
|
}
|
|
1384
1534
|
restore(id, snapshot) {
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
this.records.
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1535
|
+
return this.update(() => {
|
|
1536
|
+
this.captureRecord(id);
|
|
1537
|
+
const previous = this.records.get(id);
|
|
1538
|
+
if (previous) this.removeRecordReferenceIndexes(id, previous);
|
|
1539
|
+
if (snapshot.record === void 0) this.records.delete(id);
|
|
1540
|
+
else {
|
|
1541
|
+
this.records.set(id, snapshot.record);
|
|
1542
|
+
this.addRecordReferenceIndexes(id, snapshot.record);
|
|
1543
|
+
}
|
|
1544
|
+
if (snapshot.mask === void 0) this.coverage.delete(id);
|
|
1545
|
+
else this.coverage.set(id, snapshot.mask);
|
|
1546
|
+
this.notify(id);
|
|
1547
|
+
});
|
|
1395
1548
|
}
|
|
1396
1549
|
addListIndexes(key, list) {
|
|
1397
1550
|
const parsed = parseListKey(key);
|
|
@@ -1826,10 +1979,7 @@ var FateClient = class {
|
|
|
1826
1979
|
this.pending = /* @__PURE__ */ new Map();
|
|
1827
1980
|
this.pendingDeferred = /* @__PURE__ */ new Map();
|
|
1828
1981
|
this.pendingOptimisticMutations = /* @__PURE__ */ new Map();
|
|
1829
|
-
this.optimisticMasks = /* @__PURE__ */ new Map();
|
|
1830
|
-
this.optimisticByEntity = /* @__PURE__ */ new Map();
|
|
1831
1982
|
this.optimisticEntityResolutions = /* @__PURE__ */ new Map();
|
|
1832
|
-
this.optimisticTokenCounter = 0;
|
|
1833
1983
|
this.liveSubscriptions = /* @__PURE__ */ new Map();
|
|
1834
1984
|
this.liveConnectionInvalidations = /* @__PURE__ */ new Map();
|
|
1835
1985
|
this.stableRefs = /* @__PURE__ */ new Map();
|
|
@@ -1839,8 +1989,11 @@ var FateClient = class {
|
|
|
1839
1989
|
this.gcPending = false;
|
|
1840
1990
|
this.gcScheduled = false;
|
|
1841
1991
|
this.pendingNetworkRequests = 0;
|
|
1842
|
-
this.store = new Store()
|
|
1843
|
-
|
|
1992
|
+
this.store = new Store((ids) => {
|
|
1993
|
+
for (const id of ids) this.viewDataCache.invalidate(id);
|
|
1994
|
+
this.runPendingGarbageCollection();
|
|
1995
|
+
});
|
|
1996
|
+
this.viewDataCache = new ViewDataCache(() => !this.store.isRebasing);
|
|
1844
1997
|
this.liveConnectionInvalidationToken = 0;
|
|
1845
1998
|
this.actions = Object.create(null);
|
|
1846
1999
|
this.mutationMap = Object.create(null);
|
|
@@ -1953,11 +2106,6 @@ var FateClient = class {
|
|
|
1953
2106
|
}
|
|
1954
2107
|
lists.add(key);
|
|
1955
2108
|
}
|
|
1956
|
-
snapshotList(key, listSnapshots) {
|
|
1957
|
-
if (!listSnapshots || listSnapshots.has(key)) return;
|
|
1958
|
-
const listState = this.store.getListState(key);
|
|
1959
|
-
if (listState) listSnapshots.set(key, listState);
|
|
1960
|
-
}
|
|
1961
2109
|
applyListInsert(listState, entityId, insert) {
|
|
1962
2110
|
const pendingBeforeIds = listState.pendingBeforeIds ?? [];
|
|
1963
2111
|
const pendingAfterIds = listState.pendingAfterIds ?? [];
|
|
@@ -1986,7 +2134,7 @@ var FateClient = class {
|
|
|
1986
2134
|
pending: false
|
|
1987
2135
|
};
|
|
1988
2136
|
}
|
|
1989
|
-
insertIntoRootLists(type, entityId, insert
|
|
2137
|
+
insertIntoRootLists(type, entityId, insert) {
|
|
1990
2138
|
if (insert === "none") return;
|
|
1991
2139
|
const listNames = this.rootLists.get(type);
|
|
1992
2140
|
if (!listNames) return;
|
|
@@ -1995,7 +2143,6 @@ var FateClient = class {
|
|
|
1995
2143
|
if (!listState) continue;
|
|
1996
2144
|
const next = this.applyListInsert(listState, entityId, insert).list;
|
|
1997
2145
|
if (next === listState) continue;
|
|
1998
|
-
this.snapshotList(key, listSnapshots);
|
|
1999
2146
|
this.store.setList(key, next);
|
|
2000
2147
|
}
|
|
2001
2148
|
}
|
|
@@ -2020,23 +2167,17 @@ var FateClient = class {
|
|
|
2020
2167
|
} : argsPayload ? { args: argsPayload } : input;
|
|
2021
2168
|
return await this.trackPendingRequest(() => this.transport.mutate(key, requestInput, select));
|
|
2022
2169
|
}
|
|
2023
|
-
write(type, data, select,
|
|
2024
|
-
return this.writeEntity(type, data, select,
|
|
2025
|
-
}
|
|
2026
|
-
deleteRecord(type, id, snapshots, listSnapshots) {
|
|
2027
|
-
const entityId = toEntityId(type, id);
|
|
2028
|
-
if (snapshots && !snapshots.has(entityId)) snapshots.set(entityId, this.store.snapshot(entityId));
|
|
2029
|
-
this.viewDataCache.invalidate(entityId);
|
|
2030
|
-
this.stableRefs.delete(entityId);
|
|
2031
|
-
this.store.deleteRecord(entityId);
|
|
2032
|
-
this.store.removeReferencesTo(entityId, this.viewDataCache, snapshots, listSnapshots);
|
|
2170
|
+
write(type, data, select, plan, insert) {
|
|
2171
|
+
return this.writeEntity(type, data, select, plan, null, insert);
|
|
2033
2172
|
}
|
|
2034
|
-
|
|
2035
|
-
this.
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2173
|
+
deleteRecord(type, id) {
|
|
2174
|
+
return this.store.update(() => {
|
|
2175
|
+
const entityId = toEntityId(type, id);
|
|
2176
|
+
this.viewDataCache.invalidate(entityId);
|
|
2177
|
+
this.stableRefs.delete(entityId);
|
|
2178
|
+
this.store.deleteRecord(entityId);
|
|
2179
|
+
this.store.removeReferencesTo(entityId, this.viewDataCache);
|
|
2180
|
+
});
|
|
2040
2181
|
}
|
|
2041
2182
|
stableRefWithViewNames(type, id, viewNames) {
|
|
2042
2183
|
const entityId = toEntityId(type, id);
|
|
@@ -2221,10 +2362,8 @@ var FateClient = class {
|
|
|
2221
2362
|
unsubscribe = this.transport.subscribeById(type, id, plan.paths, args, {
|
|
2222
2363
|
onData: (record, liveSelect) => {
|
|
2223
2364
|
if (!record || typeof record !== "object") return;
|
|
2224
|
-
const pendingMask = this.getPendingOptimisticMask(entityId);
|
|
2225
2365
|
const select = new Set(liveSelect ?? plan.paths);
|
|
2226
|
-
|
|
2227
|
-
this.write(type, record, selection, void 0, plan, null, pendingMask, "none");
|
|
2366
|
+
this.write(type, record, select, plan, "none");
|
|
2228
2367
|
},
|
|
2229
2368
|
onDelete: (deletedId) => {
|
|
2230
2369
|
this.deleteRecord(type, deletedId ?? id);
|
|
@@ -2278,24 +2417,26 @@ var FateClient = class {
|
|
|
2278
2417
|
};
|
|
2279
2418
|
}
|
|
2280
2419
|
applyLiveConnectionEvent(view, connection, plan, event) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2420
|
+
return this.store.update(() => {
|
|
2421
|
+
if (event.type === "invalidate") {
|
|
2422
|
+
this.invalidateLiveConnection(view, connection);
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
if (event.type === "deleteEdge") {
|
|
2426
|
+
this.deleteConnectionEdge(connection, toEntityId(event.nodeType, event.id));
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
const node = event.edge.node;
|
|
2430
|
+
if (!node || typeof node !== "object") return;
|
|
2431
|
+
const nodeRecord = node;
|
|
2432
|
+
const nodeType = event.nodeType;
|
|
2433
|
+
if (!nodeType) {
|
|
2434
|
+
this.reportLiveError(/* @__PURE__ */ new Error(`fate: Live connection event for '${connection.procedure}' did not include a node type.`));
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
const entityId = this.write(nodeType, nodeRecord, plan.paths, plan, "none");
|
|
2438
|
+
this.insertConnectionEdge(connection.key, entityId, event.edge.cursor, event.type, event.targetCursor, view, connection);
|
|
2439
|
+
});
|
|
2299
2440
|
}
|
|
2300
2441
|
invalidateLiveConnection(view, connection) {
|
|
2301
2442
|
const token = ++this.liveConnectionInvalidationToken;
|
|
@@ -2524,11 +2665,14 @@ var FateClient = class {
|
|
|
2524
2665
|
const cursors = hasIncomingCursor || Boolean(previous?.cursors) || options.hasCursorArg ? ids.map((id) => cursorMap.get(id)) : void 0;
|
|
2525
2666
|
const previousPagination = previous?.pagination;
|
|
2526
2667
|
const newPagination = incomingPagination;
|
|
2668
|
+
const extendsExistingList = options.hasCursorArg && existingIds.length > 0;
|
|
2669
|
+
const leadingPagination = extendsExistingList && !isBackward ? previousPagination ?? newPagination : newPagination;
|
|
2670
|
+
const trailingPagination = extendsExistingList && isBackward ? previousPagination ?? newPagination : newPagination;
|
|
2527
2671
|
const pagination = previousPagination || newPagination ? {
|
|
2528
|
-
hasNext: !!(
|
|
2529
|
-
hasPrevious: !!(
|
|
2530
|
-
nextCursor:
|
|
2531
|
-
previousCursor:
|
|
2672
|
+
hasNext: !!(trailingPagination?.hasNext ?? previousPagination?.hasNext),
|
|
2673
|
+
hasPrevious: !!(leadingPagination?.hasPrevious ?? previousPagination?.hasPrevious),
|
|
2674
|
+
nextCursor: trailingPagination?.nextCursor ?? previousPagination?.nextCursor,
|
|
2675
|
+
previousCursor: leadingPagination?.previousCursor ?? previousPagination?.previousCursor
|
|
2532
2676
|
} : void 0;
|
|
2533
2677
|
return {
|
|
2534
2678
|
backwardPageLimit: !options.hasCursorArg && isBackward && options.pageLimit != null ? Math.max(previous?.backwardPageLimit ?? 0, options.pageLimit) : previous?.backwardPageLimit,
|
|
@@ -2562,60 +2706,10 @@ var FateClient = class {
|
|
|
2562
2706
|
this.optimisticEntityResolutions.set(optimisticEntityId, resolvedEntityId);
|
|
2563
2707
|
this.store.replaceListEntityId(optimisticEntityId, resolvedEntityId);
|
|
2564
2708
|
}
|
|
2565
|
-
registerOptimisticUpdate(entityId, select) {
|
|
2566
|
-
if (!entityId || select.size === 0) return null;
|
|
2567
|
-
const mask = fromPaths(select);
|
|
2568
|
-
const token = ++this.optimisticTokenCounter;
|
|
2569
|
-
this.optimisticMasks.set(token, {
|
|
2570
|
-
entityId,
|
|
2571
|
-
mask
|
|
2572
|
-
});
|
|
2573
|
-
let entries = this.optimisticByEntity.get(entityId);
|
|
2574
|
-
if (!entries) {
|
|
2575
|
-
entries = /* @__PURE__ */ new Set();
|
|
2576
|
-
this.optimisticByEntity.set(entityId, entries);
|
|
2577
|
-
}
|
|
2578
|
-
entries.add(token);
|
|
2579
|
-
return token;
|
|
2580
|
-
}
|
|
2581
|
-
clearOptimisticUpdate(token) {
|
|
2582
|
-
if (token == null) return;
|
|
2583
|
-
const entry = this.optimisticMasks.get(token);
|
|
2584
|
-
if (!entry) return;
|
|
2585
|
-
this.optimisticMasks.delete(token);
|
|
2586
|
-
const entityTokens = this.optimisticByEntity.get(entry.entityId);
|
|
2587
|
-
if (entityTokens) {
|
|
2588
|
-
entityTokens.delete(token);
|
|
2589
|
-
if (entityTokens.size === 0) this.optimisticByEntity.delete(entry.entityId);
|
|
2590
|
-
}
|
|
2591
|
-
this.runPendingGarbageCollection();
|
|
2592
|
-
}
|
|
2593
|
-
getPendingOptimisticMask(entityId, options = {}) {
|
|
2594
|
-
if (!entityId) return null;
|
|
2595
|
-
const tokens = this.optimisticByEntity.get(entityId);
|
|
2596
|
-
if (!tokens || tokens.size === 0) return null;
|
|
2597
|
-
let mask = null;
|
|
2598
|
-
for (const token of tokens) {
|
|
2599
|
-
if (options.excludeToken != null && token === options.excludeToken) continue;
|
|
2600
|
-
const entry = this.optimisticMasks.get(token);
|
|
2601
|
-
if (!entry) continue;
|
|
2602
|
-
if (!mask) mask = cloneMask(entry.mask);
|
|
2603
|
-
else union(mask, entry.mask);
|
|
2604
|
-
}
|
|
2605
|
-
return mask;
|
|
2606
|
-
}
|
|
2607
2709
|
getPendingOptimisticMutations(entityId) {
|
|
2608
2710
|
const pending = this.pendingOptimisticMutations.get(entityId);
|
|
2609
2711
|
return pending && pending.size > 0 ? [...pending] : null;
|
|
2610
2712
|
}
|
|
2611
|
-
filterSelectionForPendingOptimistics(entityId, select, options = {}) {
|
|
2612
|
-
if (!entityId || select.size === 0) return select;
|
|
2613
|
-
const pendingMask = this.getPendingOptimisticMask(entityId, options);
|
|
2614
|
-
if (!pendingMask) return select;
|
|
2615
|
-
const filtered = /* @__PURE__ */ new Set();
|
|
2616
|
-
for (const path of select) if (!isCovered(pendingMask, path)) filtered.add(path);
|
|
2617
|
-
return filtered;
|
|
2618
|
-
}
|
|
2619
2713
|
async loadConnection(view, connection, args, options = {}) {
|
|
2620
2714
|
return await this.trackPendingRequest(() => this.loadConnectionInternal(view, connection, args, options));
|
|
2621
2715
|
}
|
|
@@ -2630,21 +2724,23 @@ var FateClient = class {
|
|
|
2630
2724
|
const { argsPayload, plan } = resolveSelectionPlan(view, requestArgs);
|
|
2631
2725
|
const { items, pagination } = await this.transport.fetchList(connection.field, plan.paths, argsPayload);
|
|
2632
2726
|
if (!items) return this.store.getListState(connection.key);
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2727
|
+
this.store.update(() => {
|
|
2728
|
+
const incomingIds = [];
|
|
2729
|
+
const incomingCursors = [];
|
|
2730
|
+
for (const entry of items) {
|
|
2731
|
+
const id = this.write(connection.type, entry.node, plan.paths, plan, "none");
|
|
2732
|
+
incomingIds.push(id);
|
|
2733
|
+
incomingCursors.push(entry.cursor);
|
|
2734
|
+
}
|
|
2735
|
+
const previous = this.store.getListState(connection.key);
|
|
2736
|
+
const nextListState = this.mergeListState(previous, incomingIds, incomingCursors, pagination, {
|
|
2737
|
+
...getPaginationMergeInfo(requestArgs),
|
|
2738
|
+
replace: true
|
|
2739
|
+
});
|
|
2740
|
+
if (!filterConnectionArgs(connection.args)) this.registerRootList(connection.type, connection.key);
|
|
2741
|
+
this.store.setList(connection.key, nextListState);
|
|
2644
2742
|
});
|
|
2645
|
-
|
|
2646
|
-
this.store.setList(connection.key, nextListState);
|
|
2647
|
-
return nextListState;
|
|
2743
|
+
return this.store.getListState(connection.key);
|
|
2648
2744
|
}
|
|
2649
2745
|
const owner = parseEntityId(connection.owner);
|
|
2650
2746
|
const requestArgs = omitUndefinedValues({
|
|
@@ -2668,32 +2764,34 @@ var FateClient = class {
|
|
|
2668
2764
|
pagination: void 0
|
|
2669
2765
|
} : list;
|
|
2670
2766
|
if (!connectionPayload) return this.store.getListState(connection.key);
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
const
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2767
|
+
this.store.update(() => {
|
|
2768
|
+
const incomingIds = [];
|
|
2769
|
+
const incomingCursors = [];
|
|
2770
|
+
const nodeType = this.getListNodeType(owner.type, connection.field);
|
|
2771
|
+
for (const entry of connectionPayload.items) {
|
|
2772
|
+
const { node } = entry;
|
|
2773
|
+
const id = this.write(nodeType, node, nodeSelection, plan);
|
|
2774
|
+
incomingIds.push(id);
|
|
2775
|
+
incomingCursors.push(entry.cursor);
|
|
2776
|
+
}
|
|
2777
|
+
const previous = this.store.getListState(connection.key);
|
|
2778
|
+
const previousIds = previous?.ids ?? [];
|
|
2779
|
+
const previousSet = new Set(previousIds);
|
|
2780
|
+
const newIds = incomingIds.filter((id) => !previousSet.has(id));
|
|
2781
|
+
const nextListState = this.mergeListState(previous, incomingIds, incomingCursors, connectionPayload.pagination, {
|
|
2782
|
+
...getPaginationMergeInfo(argsPayload),
|
|
2783
|
+
direction,
|
|
2784
|
+
hasCursorArg: true,
|
|
2785
|
+
replace: true
|
|
2786
|
+
});
|
|
2787
|
+
this.store.setList(connection.key, nextListState);
|
|
2788
|
+
const current = this.store.read(connection.owner);
|
|
2789
|
+
const existingField = Array.isArray(current?.[connection.field]) ? current?.[connection.field] || [] : [];
|
|
2790
|
+
const nodeRefs = createNodeRefsForIds(newIds, void 0);
|
|
2791
|
+
const nextField = direction === "forward" ? [...existingField, ...nodeRefs] : [...nodeRefs, ...existingField];
|
|
2792
|
+
this.viewDataCache.invalidate(connection.owner);
|
|
2793
|
+
this.store.merge(connection.owner, { [connection.field]: nextField }, [connection.field]);
|
|
2689
2794
|
});
|
|
2690
|
-
this.store.setList(connection.key, nextListState);
|
|
2691
|
-
const current = this.store.read(connection.owner);
|
|
2692
|
-
const existingField = Array.isArray(current?.[connection.field]) ? current?.[connection.field] || [] : [];
|
|
2693
|
-
const nodeRefs = createNodeRefsForIds(newIds, void 0);
|
|
2694
|
-
const nextField = direction === "forward" ? [...existingField, ...nodeRefs] : [...nodeRefs, ...existingField];
|
|
2695
|
-
this.viewDataCache.invalidate(connection.owner);
|
|
2696
|
-
this.store.merge(connection.owner, { [connection.field]: nextField }, [connection.field]);
|
|
2697
2795
|
return this.store.getListState(connection.key);
|
|
2698
2796
|
}
|
|
2699
2797
|
request(request, options) {
|
|
@@ -2836,9 +2934,7 @@ var FateClient = class {
|
|
|
2836
2934
|
case "stale-while-revalidate":
|
|
2837
2935
|
execution = this.handleStoreAndNetworkRequest(handle.descriptor);
|
|
2838
2936
|
break;
|
|
2839
|
-
default:
|
|
2840
|
-
execution = this.executeRequest(handle.descriptor, mode === "network-only" ? { fetchAll: true } : void 0).then(() => this.getRequestResultFromDescriptor(handle.descriptor));
|
|
2841
|
-
break;
|
|
2937
|
+
default: execution = this.executeRequest(handle.descriptor, mode === "network-only" ? { fetchAll: true } : void 0).then(() => this.getRequestResultFromDescriptor(handle.descriptor));
|
|
2842
2938
|
}
|
|
2843
2939
|
handle.start(execution);
|
|
2844
2940
|
}
|
|
@@ -2861,7 +2957,7 @@ var FateClient = class {
|
|
|
2861
2957
|
walk(record);
|
|
2862
2958
|
}
|
|
2863
2959
|
hasActiveOptimisticUpdates() {
|
|
2864
|
-
return this.
|
|
2960
|
+
return this.store.hasOptimisticUpdates || this.pendingOptimisticMutations.size > 0;
|
|
2865
2961
|
}
|
|
2866
2962
|
hasPendingRequests() {
|
|
2867
2963
|
return this.pendingNetworkRequests > 0;
|
|
@@ -3028,7 +3124,7 @@ var FateClient = class {
|
|
|
3028
3124
|
const resolvedArgs = resolvedArgsFromPlan(plan);
|
|
3029
3125
|
await this.trackPendingRequest(async () => {
|
|
3030
3126
|
const records = await this.transport.fetchById(type, ids, select, resolvedArgs);
|
|
3031
|
-
for (const record of records) this.writeEntity(type, record, select,
|
|
3127
|
+
for (const record of records) this.writeEntity(type, record, select, plan, prefix);
|
|
3032
3128
|
});
|
|
3033
3129
|
}
|
|
3034
3130
|
async fetchQueryAndNormalize(item) {
|
|
@@ -3039,7 +3135,7 @@ var FateClient = class {
|
|
|
3039
3135
|
this.rootRequests.set(item.queryKey, null);
|
|
3040
3136
|
return;
|
|
3041
3137
|
}
|
|
3042
|
-
const entityId = this.writeEntity(item.type, record, item.plan.paths,
|
|
3138
|
+
const entityId = this.writeEntity(item.type, record, item.plan.paths, item.plan);
|
|
3043
3139
|
this.rootRequests.set(item.queryKey, entityId);
|
|
3044
3140
|
});
|
|
3045
3141
|
}
|
|
@@ -3047,133 +3143,130 @@ var FateClient = class {
|
|
|
3047
3143
|
if (!this.transport.fetchList) throw new Error(`fate: 'transport.fetchList' is not configured but request includes a list for key '${item.name}'.`);
|
|
3048
3144
|
await this.trackPendingRequest(async () => {
|
|
3049
3145
|
const { items, pagination } = await this.transport.fetchList(item.name, item.plan.paths, item.argsPayload);
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3146
|
+
this.store.update(() => {
|
|
3147
|
+
const ids = [];
|
|
3148
|
+
const cursors = [];
|
|
3149
|
+
for (const entry of items) {
|
|
3150
|
+
const id = this.writeEntity(item.type, entry.node, item.plan.paths, item.plan);
|
|
3151
|
+
ids.push(id);
|
|
3152
|
+
cursors.push(entry.cursor);
|
|
3153
|
+
}
|
|
3154
|
+
if (!filterConnectionArgs(item.argsPayload)) this.registerRootList(item.type, item.listKey);
|
|
3155
|
+
const previous = this.store.getListState(item.listKey);
|
|
3156
|
+
this.store.setList(item.listKey, this.mergeListState(previous, ids, cursors, pagination, {
|
|
3157
|
+
...getPaginationMergeInfo(item.argsPayload),
|
|
3158
|
+
replace: true
|
|
3159
|
+
}));
|
|
3160
|
+
});
|
|
3063
3161
|
});
|
|
3064
3162
|
}
|
|
3065
|
-
writeEntity(type, record, select,
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
const
|
|
3073
|
-
const
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
if (
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
if (
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3163
|
+
writeEntity(type, record, select, plan, pathPrefix = null, insert) {
|
|
3164
|
+
return this.store.update(() => {
|
|
3165
|
+
const config = this.types.get(type);
|
|
3166
|
+
if (!config) throw new Error(`fate: Found unknown entity type '${type}' in normalization.`);
|
|
3167
|
+
const id = config.getId(record);
|
|
3168
|
+
const entityId = toEntityId(type, id);
|
|
3169
|
+
const result = {};
|
|
3170
|
+
const selectionTree = groupSelectionByPrefix(select);
|
|
3171
|
+
if (config.fields) for (const [key, relationDescriptor] of Object.entries(config.fields)) {
|
|
3172
|
+
const value = record[key];
|
|
3173
|
+
const fieldPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
3174
|
+
const fieldArgs = plan?.args.get(fieldPath);
|
|
3175
|
+
if (relationDescriptor === "scalar") {
|
|
3176
|
+
if (!Object.hasOwn(record, key)) continue;
|
|
3177
|
+
result[key] = value;
|
|
3178
|
+
} else if (relationDescriptor && typeof relationDescriptor === "object" && "type" in relationDescriptor) {
|
|
3179
|
+
const childPaths = selectionTree.get(key) ?? emptySet;
|
|
3180
|
+
if (value === null) {
|
|
3181
|
+
result[key] = null;
|
|
3182
|
+
continue;
|
|
3183
|
+
}
|
|
3184
|
+
if (value && typeof value === "object" && !isNodeRef(value)) {
|
|
3185
|
+
const childType = relationDescriptor.type;
|
|
3186
|
+
const childConfig = this.types.get(childType);
|
|
3187
|
+
if (!childConfig) throw new Error(`fate: Unknown related type '${childType}' (field '${type}.${key}').`);
|
|
3188
|
+
result[key] = createNodeRef(toEntityId(childType, childConfig.getId(value)));
|
|
3189
|
+
this.writeEntity(childType, value, childPaths, plan, fieldPath);
|
|
3190
|
+
}
|
|
3191
|
+
} else if (relationDescriptor && typeof relationDescriptor === "object" && "listOf" in relationDescriptor) {
|
|
3192
|
+
const childPaths = selectionTree.get(key) ?? emptySet;
|
|
3193
|
+
if (value === null) {
|
|
3194
|
+
result[key] = null;
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
const childType = relationDescriptor.listOf;
|
|
3088
3198
|
const childConfig = this.types.get(childType);
|
|
3089
3199
|
if (!childConfig) throw new Error(`fate: Unknown related type '${childType}' (field '${type}.${key}').`);
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
if (Array.isArray(record.items)) return {
|
|
3108
|
-
items: record.items.map((node) => {
|
|
3109
|
-
if (node && typeof node === "object" && "node" in node) {
|
|
3110
|
-
const itemRecord = node;
|
|
3111
|
-
return {
|
|
3112
|
-
cursor: itemRecord.cursor,
|
|
3113
|
-
node: itemRecord.node
|
|
3114
|
-
};
|
|
3115
|
-
}
|
|
3116
|
-
return { node };
|
|
3117
|
-
}),
|
|
3118
|
-
pagination: record.pagination
|
|
3119
|
-
};
|
|
3120
|
-
}
|
|
3121
|
-
return null;
|
|
3122
|
-
})();
|
|
3123
|
-
if (connection) {
|
|
3124
|
-
const ids = [];
|
|
3125
|
-
const cursors = [];
|
|
3126
|
-
const nodeSelection = childPaths.size > 0 ? /* @__PURE__ */ new Set() : childPaths;
|
|
3127
|
-
if (childPaths.size > 0) for (const path of childPaths) {
|
|
3128
|
-
if (path.startsWith("items.node.")) {
|
|
3129
|
-
nodeSelection.add(path.slice(11));
|
|
3130
|
-
continue;
|
|
3131
|
-
}
|
|
3132
|
-
if (path.startsWith("node.")) {
|
|
3133
|
-
nodeSelection.add(path.slice(5));
|
|
3134
|
-
continue;
|
|
3200
|
+
const connection = (() => {
|
|
3201
|
+
if (Array.isArray(value)) return { items: value.map((item) => ({ node: item })) };
|
|
3202
|
+
if (value && typeof value === "object") {
|
|
3203
|
+
const record = value;
|
|
3204
|
+
if (Array.isArray(record.items)) return {
|
|
3205
|
+
items: record.items.map((node) => {
|
|
3206
|
+
if (node && typeof node === "object" && "node" in node) {
|
|
3207
|
+
const itemRecord = node;
|
|
3208
|
+
return {
|
|
3209
|
+
cursor: itemRecord.cursor,
|
|
3210
|
+
node: itemRecord.node
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
return { node };
|
|
3214
|
+
}),
|
|
3215
|
+
pagination: record.pagination
|
|
3216
|
+
};
|
|
3135
3217
|
}
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
const
|
|
3141
|
-
const
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3218
|
+
return null;
|
|
3219
|
+
})();
|
|
3220
|
+
if (connection) {
|
|
3221
|
+
const ids = [];
|
|
3222
|
+
const cursors = [];
|
|
3223
|
+
const nodeSelection = childPaths.size > 0 ? /* @__PURE__ */ new Set() : childPaths;
|
|
3224
|
+
if (childPaths.size > 0) for (const path of childPaths) {
|
|
3225
|
+
if (path.startsWith("items.node.")) {
|
|
3226
|
+
nodeSelection.add(path.slice(11));
|
|
3227
|
+
continue;
|
|
3228
|
+
}
|
|
3229
|
+
if (path.startsWith("node.")) {
|
|
3230
|
+
nodeSelection.add(path.slice(5));
|
|
3231
|
+
continue;
|
|
3232
|
+
}
|
|
3233
|
+
if (path === "items.node" || path.startsWith("items.")) continue;
|
|
3234
|
+
nodeSelection.add(path);
|
|
3146
3235
|
}
|
|
3147
|
-
|
|
3148
|
-
const
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3236
|
+
for (const entry of connection.items) {
|
|
3237
|
+
const node = entry.node;
|
|
3238
|
+
const cursor = "cursor" in entry ? entry.cursor : void 0;
|
|
3239
|
+
cursors.push(cursor);
|
|
3240
|
+
if (isNodeRef(node)) {
|
|
3241
|
+
ids.push(getNodeRefId(node));
|
|
3242
|
+
continue;
|
|
3243
|
+
}
|
|
3244
|
+
if (node && typeof node === "object") {
|
|
3245
|
+
const childId = toEntityId(childType, childConfig.getId(node));
|
|
3246
|
+
this.writeEntity(childType, node, nodeSelection, plan, fieldPath);
|
|
3247
|
+
ids.push(childId);
|
|
3248
|
+
continue;
|
|
3249
|
+
}
|
|
3152
3250
|
}
|
|
3251
|
+
const listKey = getListKey(entityId, key, fieldArgs?.hash);
|
|
3252
|
+
const previousList = this.store.getListState(listKey);
|
|
3253
|
+
const argsValue = fieldArgs?.value;
|
|
3254
|
+
const nextListState = this.mergeListState(previousList, ids, cursors, connection.pagination, getPaginationMergeInfo(argsValue));
|
|
3255
|
+
const listChanged = !areListStatesEqual(previousList, nextListState);
|
|
3256
|
+
result[key] = createNodeRefsForIds(nextListState.ids, this.store.read(entityId)?.[key], { reuseCurrentArray: !listChanged });
|
|
3257
|
+
this.store.setList(listKey, nextListState);
|
|
3153
3258
|
}
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
}
|
|
3164
|
-
for (const [key, value] of Object.entries(record)) if (!(key in (config.fields ?? {}))) {
|
|
3165
|
-
const fieldPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
3166
|
-
if (blockedMask && isCovered(blockedMask, fieldPath)) continue;
|
|
3167
|
-
result[key] = value;
|
|
3168
|
-
}
|
|
3169
|
-
if (snapshots && !snapshots.has(entityId)) snapshots.set(entityId, this.store.snapshot(entityId));
|
|
3170
|
-
this.viewDataCache.invalidate(entityId);
|
|
3171
|
-
this.store.merge(entityId, result, select);
|
|
3172
|
-
this.linkParentLists(type, entityId, result, snapshots, listSnapshots, insert ?? "after");
|
|
3173
|
-
if (!pathPrefix && insert) this.insertIntoRootLists(type, entityId, insert, listSnapshots);
|
|
3174
|
-
return entityId;
|
|
3259
|
+
} else result[key] = value;
|
|
3260
|
+
}
|
|
3261
|
+
for (const [key, value] of Object.entries(record)) if (!(key in (config.fields ?? {}))) result[key] = value;
|
|
3262
|
+
this.viewDataCache.invalidate(entityId);
|
|
3263
|
+
this.store.merge(entityId, result, select);
|
|
3264
|
+
this.linkParentLists(type, entityId, result, insert ?? "after");
|
|
3265
|
+
if (!pathPrefix && insert) this.insertIntoRootLists(type, entityId, insert);
|
|
3266
|
+
return entityId;
|
|
3267
|
+
});
|
|
3175
3268
|
}
|
|
3176
|
-
linkParentLists(type, entityId, record,
|
|
3269
|
+
linkParentLists(type, entityId, record, insert) {
|
|
3177
3270
|
if (insert === "none") return;
|
|
3178
3271
|
const parents = this.parentLists.get(type);
|
|
3179
3272
|
if (!parents) return;
|
|
@@ -3186,23 +3279,18 @@ var FateClient = class {
|
|
|
3186
3279
|
if (!existing) continue;
|
|
3187
3280
|
const current = Array.isArray(existing[parent.field]) ? existing[parent.field] : [];
|
|
3188
3281
|
if (current.some((item) => isNodeRef(item) && getNodeRefId(item) === entityId)) continue;
|
|
3189
|
-
if (snapshots && !snapshots.has(parentId)) snapshots.set(parentId, this.store.snapshot(parentId));
|
|
3190
3282
|
this.viewDataCache.invalidate(parentId);
|
|
3191
3283
|
const defaultListKey = getListKey(parentId, parent.field);
|
|
3192
3284
|
const defaultListState = this.store.getListState(defaultListKey);
|
|
3193
3285
|
let nextField = current;
|
|
3194
3286
|
if (defaultListState) {
|
|
3195
3287
|
const { list: nextDefaultListState, pending } = this.applyListInsert(defaultListState, entityId, insert);
|
|
3196
|
-
if (nextDefaultListState !== defaultListState)
|
|
3197
|
-
this.snapshotList(defaultListKey, listSnapshots);
|
|
3198
|
-
this.store.setList(defaultListKey, nextDefaultListState);
|
|
3199
|
-
}
|
|
3288
|
+
if (nextDefaultListState !== defaultListState) this.store.setList(defaultListKey, nextDefaultListState);
|
|
3200
3289
|
const nextFieldIds = pending ? getListEntries(nextDefaultListState).map(({ id }) => id) : nextDefaultListState.ids;
|
|
3201
3290
|
nextField = createNodeRefsForIds(nextFieldIds, current);
|
|
3202
3291
|
} else {
|
|
3203
3292
|
const currentIds = current.map((item) => isNodeRef(item) ? getNodeRefId(item) : null).filter((id) => id != null);
|
|
3204
3293
|
const nextDefaultListState = { ids: insert === "before" ? [entityId, ...currentIds] : [...currentIds, entityId] };
|
|
3205
|
-
this.snapshotList(defaultListKey, listSnapshots);
|
|
3206
3294
|
this.store.setList(defaultListKey, nextDefaultListState);
|
|
3207
3295
|
nextField = createNodeRefsForIds(nextDefaultListState.ids, current);
|
|
3208
3296
|
}
|
|
@@ -3210,7 +3298,6 @@ var FateClient = class {
|
|
|
3210
3298
|
for (const [listKey, listState] of registeredLists) {
|
|
3211
3299
|
const nextListState = this.applyListInsert(listState, entityId, insert).list;
|
|
3212
3300
|
if (nextListState === listState) continue;
|
|
3213
|
-
this.snapshotList(listKey, listSnapshots);
|
|
3214
3301
|
this.store.setList(listKey, nextListState);
|
|
3215
3302
|
}
|
|
3216
3303
|
this.store.merge(parentId, { [parent.field]: nextField }, [parent.field]);
|
|
@@ -3258,92 +3345,93 @@ var FateClient = class {
|
|
|
3258
3345
|
target[key] = null;
|
|
3259
3346
|
continue;
|
|
3260
3347
|
}
|
|
3261
|
-
if (Array.isArray(value))
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3348
|
+
if (Array.isArray(value)) {
|
|
3349
|
+
if (nextSelection.items && typeof nextSelection.items === "object") {
|
|
3350
|
+
const selection = nextSelection.items;
|
|
3351
|
+
const fieldArgs = plan.args.get(fieldPath);
|
|
3352
|
+
const listKey = getListKey(parentId, key, fieldArgs?.hash);
|
|
3353
|
+
const listState = this.store.getListState(listKey);
|
|
3354
|
+
const connection = { items: (listState ? getListEntries(listState) : value.map((item) => ({
|
|
3355
|
+
cursor: void 0,
|
|
3356
|
+
id: isNodeRef(item) ? getNodeRefId(item) : null
|
|
3357
|
+
}))).map((entry, index) => {
|
|
3358
|
+
const entityId = entry.id;
|
|
3359
|
+
if (!entityId) return {
|
|
3360
|
+
cursor: listState?.cursors?.[index],
|
|
3361
|
+
node: null
|
|
3362
|
+
};
|
|
3363
|
+
ids.add(entityId);
|
|
3364
|
+
const record = this.store.read(entityId);
|
|
3365
|
+
const { id, type } = parseEntityId(entityId);
|
|
3366
|
+
const node = {
|
|
3367
|
+
__typename: type,
|
|
3368
|
+
id
|
|
3369
|
+
};
|
|
3370
|
+
if (record) walk(selection.node, record, node, entityId, fieldPath);
|
|
3371
|
+
const itemResult = { node: record ? node : null };
|
|
3372
|
+
if (selection.cursor === true) itemResult.cursor = entry.cursor;
|
|
3373
|
+
return itemResult;
|
|
3374
|
+
}) };
|
|
3375
|
+
if ("pagination" in nextSelection && nextSelection.pagination) {
|
|
3376
|
+
const paginationSelection = nextSelection.pagination;
|
|
3377
|
+
const storedPagination = listState?.pagination;
|
|
3378
|
+
if (storedPagination) {
|
|
3379
|
+
const pagination = {};
|
|
3380
|
+
if (paginationSelection.nextCursor === true) {
|
|
3381
|
+
if (storedPagination.nextCursor !== void 0) pagination.nextCursor = storedPagination.nextCursor;
|
|
3382
|
+
}
|
|
3383
|
+
if (paginationSelection.previousCursor === true) {
|
|
3384
|
+
if (storedPagination.previousCursor !== void 0) pagination.previousCursor = storedPagination.previousCursor;
|
|
3385
|
+
}
|
|
3386
|
+
if (paginationSelection.hasNext === true) pagination.hasNext = storedPagination.hasNext;
|
|
3387
|
+
if (paginationSelection.hasPrevious === true) pagination.hasPrevious = storedPagination.hasPrevious;
|
|
3388
|
+
if (Object.keys(pagination).length > 0) connection.pagination = pagination;
|
|
3389
|
+
} else connection.pagination = void 0;
|
|
3390
|
+
}
|
|
3391
|
+
const { id: ownerRawId, type: parentType } = parseEntityId(parentId);
|
|
3392
|
+
if (parentType) {
|
|
3393
|
+
const childType = this.getListNodeType(parentType, key);
|
|
3394
|
+
const metadata = {
|
|
3395
|
+
args: (() => {
|
|
3396
|
+
if (!fieldArgs?.value && ownerRawId === void 0) return;
|
|
3397
|
+
const value = fieldArgs?.value ? { ...fieldArgs.value } : {};
|
|
3398
|
+
if (ownerRawId !== void 0) value.id = ownerRawId;
|
|
3399
|
+
return value;
|
|
3400
|
+
})(),
|
|
3401
|
+
field: key,
|
|
3402
|
+
hash: fieldArgs?.hash,
|
|
3403
|
+
key: listKey,
|
|
3404
|
+
live: plan.live.get(fieldPath),
|
|
3405
|
+
owner: parentId,
|
|
3406
|
+
procedure: `${parentType}.${key}`,
|
|
3407
|
+
root: false,
|
|
3408
|
+
type: childType
|
|
3409
|
+
};
|
|
3410
|
+
Object.defineProperty(connection, ConnectionTag, {
|
|
3411
|
+
configurable: false,
|
|
3412
|
+
enumerable: false,
|
|
3413
|
+
value: metadata,
|
|
3414
|
+
writable: false
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
target[key] = connection;
|
|
3418
|
+
} else target[key] = value.map((item) => {
|
|
3419
|
+
const entityId = isNodeRef(item) ? getNodeRefId(item) : null;
|
|
3420
|
+
if (!entityId) return item;
|
|
3275
3421
|
ids.add(entityId);
|
|
3276
3422
|
const record = this.store.read(entityId);
|
|
3277
3423
|
const { id, type } = parseEntityId(entityId);
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
const storedPagination = listState?.pagination;
|
|
3290
|
-
if (storedPagination) {
|
|
3291
|
-
const pagination = {};
|
|
3292
|
-
if (paginationSelection.nextCursor === true) {
|
|
3293
|
-
if (storedPagination.nextCursor !== void 0) pagination.nextCursor = storedPagination.nextCursor;
|
|
3294
|
-
}
|
|
3295
|
-
if (paginationSelection.previousCursor === true) {
|
|
3296
|
-
if (storedPagination.previousCursor !== void 0) pagination.previousCursor = storedPagination.previousCursor;
|
|
3297
|
-
}
|
|
3298
|
-
if (paginationSelection.hasNext === true) pagination.hasNext = storedPagination.hasNext;
|
|
3299
|
-
if (paginationSelection.hasPrevious === true) pagination.hasPrevious = storedPagination.hasPrevious;
|
|
3300
|
-
if (Object.keys(pagination).length > 0) connection.pagination = pagination;
|
|
3301
|
-
} else connection.pagination = void 0;
|
|
3302
|
-
}
|
|
3303
|
-
const { id: ownerRawId, type: parentType } = parseEntityId(parentId);
|
|
3304
|
-
if (parentType) {
|
|
3305
|
-
const childType = this.getListNodeType(parentType, key);
|
|
3306
|
-
const metadata = {
|
|
3307
|
-
args: (() => {
|
|
3308
|
-
if (!fieldArgs?.value && ownerRawId === void 0) return;
|
|
3309
|
-
const value = fieldArgs?.value ? { ...fieldArgs.value } : {};
|
|
3310
|
-
if (ownerRawId !== void 0) value.id = ownerRawId;
|
|
3311
|
-
return value;
|
|
3312
|
-
})(),
|
|
3313
|
-
field: key,
|
|
3314
|
-
hash: fieldArgs?.hash,
|
|
3315
|
-
key: listKey,
|
|
3316
|
-
live: plan.live.get(fieldPath),
|
|
3317
|
-
owner: parentId,
|
|
3318
|
-
procedure: `${parentType}.${key}`,
|
|
3319
|
-
root: false,
|
|
3320
|
-
type: childType
|
|
3321
|
-
};
|
|
3322
|
-
Object.defineProperty(connection, ConnectionTag, {
|
|
3323
|
-
configurable: false,
|
|
3324
|
-
enumerable: false,
|
|
3325
|
-
value: metadata,
|
|
3326
|
-
writable: false
|
|
3327
|
-
});
|
|
3328
|
-
}
|
|
3329
|
-
target[key] = connection;
|
|
3330
|
-
} else target[key] = value.map((item) => {
|
|
3331
|
-
const entityId = isNodeRef(item) ? getNodeRefId(item) : null;
|
|
3332
|
-
if (!entityId) return item;
|
|
3333
|
-
ids.add(entityId);
|
|
3334
|
-
const record = this.store.read(entityId);
|
|
3335
|
-
const { id, type } = parseEntityId(entityId);
|
|
3336
|
-
if (record) {
|
|
3337
|
-
const node = {
|
|
3338
|
-
__typename: type,
|
|
3339
|
-
id
|
|
3340
|
-
};
|
|
3341
|
-
walk(nextSelection, record, node, entityId, fieldPath);
|
|
3342
|
-
return node;
|
|
3343
|
-
}
|
|
3344
|
-
return null;
|
|
3345
|
-
});
|
|
3346
|
-
else if (isNodeRef(value)) {
|
|
3424
|
+
if (record) {
|
|
3425
|
+
const node = {
|
|
3426
|
+
__typename: type,
|
|
3427
|
+
id
|
|
3428
|
+
};
|
|
3429
|
+
walk(nextSelection, record, node, entityId, fieldPath);
|
|
3430
|
+
return node;
|
|
3431
|
+
}
|
|
3432
|
+
return null;
|
|
3433
|
+
});
|
|
3434
|
+
} else if (isNodeRef(value)) {
|
|
3347
3435
|
const entityId = getNodeRefId(value);
|
|
3348
3436
|
ids.add(entityId);
|
|
3349
3437
|
const relatedRecord = this.store.read(entityId);
|