@nkzw/fate 0.1.0 → 0.1.1

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/lib/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as ViewSelection, B as RequestOptions, C as TypeConfig, D as ViewEntity, E as ViewData, F as isViewTag, H as Transport, I as FateMutations, L as mutation, M as ViewTag, N as __FateEntityBrand, O as ViewEntityName, P as __FateSelectionBrand, R as FateClient, S as Snapshot, T as View, U as createTRPCTransport, V as createClient, W as getSelectionPlan, _ as Pagination, a as Entity, b as RootDefinition, c as FateThenable, d as MutationDefinition, f as MutationEntity, g as NodesItem, h as MutationResult, i as ConnectionTag, j as ViewSnapshot, k as ViewRef, l as ListItem, m as MutationInput, n as ConnectionMetadata, o as EntityId, p as MutationIdentifier, r as ConnectionRef, s as FateRoots, t as AnyRecord, u as Mask, v as Request, w as TypeName, x as Selection, y as RequestResult, z as RequestMode } from "./types-CNKGKRtz.mjs";
1
+ import { A as ViewSelection, B as RequestOptions, C as TypeConfig, D as ViewEntity, E as ViewData, F as isViewTag, H as Transport, I as FateMutations, L as mutation, M as ViewTag, N as __FateEntityBrand, O as ViewEntityName, P as __FateSelectionBrand, R as FateClient, S as Snapshot, T as View, U as createTRPCTransport, V as createClient, W as getSelectionPlan, _ as Pagination, a as Entity, b as RootDefinition, c as FateThenable, d as MutationDefinition, f as MutationEntity, g as NodesItem, h as MutationResult, i as ConnectionTag, j as ViewSnapshot, k as ViewRef, l as ListItem, m as MutationInput, n as ConnectionMetadata, o as EntityId, p as MutationIdentifier, r as ConnectionRef, s as FateRoots, t as AnyRecord, u as Mask, v as Request, w as TypeName, x as Selection, y as RequestResult, z as RequestMode } from "./types-BiDLhb07.mjs";
2
2
 
3
3
  //#region src/root.d.ts
4
4
 
package/lib/index.mjs CHANGED
@@ -689,39 +689,45 @@ function wrapMutation(client, identifier) {
689
689
  if (id$1 == null) throw new Error(`fate: Mutation '${identifier.key}' requires an 'id' to delete.`);
690
690
  client.deleteRecord(identifier.entity, id$1, snapshots, listSnapshots);
691
691
  }
692
- try {
693
- const result = await client.executeMutation(identifier.key, input, selection, {
694
- args,
695
- plan
696
- });
697
- if (result && typeof result === "object" && (!deleteRecord || Boolean(view$1))) {
698
- const select = collectImplicitSelectedPaths(result);
699
- const pendingMask = optimisticEntityId ? client.getPendingOptimisticMask(optimisticEntityId, { excludeToken: optimisticToken }) : null;
700
- const filteredSelection = optimisticEntityId ? client.filterSelectionForPendingOptimistics(optimisticEntityId, select, { excludeToken: optimisticToken }) : select;
701
- client.write(identifier.entity, result, filteredSelection, void 0, plan, null, pendingMask, insert);
702
- if (deleteRecord && id$1 != null) client.deleteRecord(identifier.entity, id$1);
703
- const resultId = maybeGetId(config.getId, result);
704
- if (optimisticRecordId != null && resultId != null && optimisticRecordId !== resultId) client.deleteRecord(identifier.entity, optimisticRecordId);
705
- }
706
- return {
707
- error: void 0,
708
- result
709
- };
710
- } catch (error) {
711
- client.clearOptimisticUpdate(optimisticToken);
712
- if (snapshots.size > 0) for (const [id$2, snapshot] of snapshots) client.restore(id$2, snapshot);
713
- if (listSnapshots && listSnapshots.size > 0) for (const [name, list] of listSnapshots) client.restoreList(name, list);
714
- if (error instanceof Error) {
715
- const { data } = error;
716
- if ((data ? categorizeTRPCError(getHTTPStatusCodeFromError(data)) : "boundary") === "boundary") throw error;
692
+ const performMutation = async () => {
693
+ try {
694
+ const result = await client.executeMutation(identifier.key, input, selection, {
695
+ args,
696
+ plan
697
+ });
698
+ if (result && typeof result === "object" && (!deleteRecord || Boolean(view$1))) {
699
+ const select = collectImplicitSelectedPaths(result);
700
+ const pendingMask = optimisticEntityId ? client.getPendingOptimisticMask(optimisticEntityId, { excludeToken: optimisticToken }) : null;
701
+ const filteredSelection = optimisticEntityId ? client.filterSelectionForPendingOptimistics(optimisticEntityId, select, { excludeToken: optimisticToken }) : select;
702
+ client.write(identifier.entity, result, filteredSelection, void 0, plan, null, pendingMask, insert);
703
+ if (deleteRecord && id$1 != null) client.deleteRecord(identifier.entity, id$1);
704
+ const resultId = maybeGetId(config.getId, result);
705
+ if (optimisticEntityId && resultId != null) client.resolveOptimisticEntity(optimisticEntityId, toEntityId(identifier.entity, resultId));
706
+ if (optimisticRecordId != null && resultId != null && optimisticRecordId !== resultId) client.deleteRecord(identifier.entity, optimisticRecordId);
707
+ }
717
708
  return {
718
- error,
719
- result: void 0
709
+ error: void 0,
710
+ result
720
711
  };
721
- } else throw new Error(`fate: Mutation '${identifier.key}' failed.`);
722
- } finally {
723
- client.clearOptimisticUpdate(optimisticToken);
724
- }
712
+ } catch (error) {
713
+ client.clearOptimisticUpdate(optimisticToken);
714
+ if (snapshots.size > 0) for (const [id$2, snapshot] of snapshots) client.restore(id$2, snapshot);
715
+ if (listSnapshots && listSnapshots.size > 0) for (const [name, list] of listSnapshots) client.restoreList(name, list);
716
+ if (error instanceof Error) {
717
+ const { data } = error;
718
+ if ((data ? categorizeTRPCError(getHTTPStatusCodeFromError(data)) : "boundary") === "boundary") throw error;
719
+ return {
720
+ error,
721
+ result: void 0
722
+ };
723
+ } else throw new Error(`fate: Mutation '${identifier.key}' failed.`);
724
+ } finally {
725
+ client.clearOptimisticUpdate(optimisticToken);
726
+ }
727
+ };
728
+ const mutationPromise = performMutation();
729
+ if (optimisticEntityId) client.registerPendingOptimisticMutation(optimisticEntityId, mutationPromise);
730
+ return mutationPromise;
725
731
  };
726
732
  }
727
733
  function categorizeTRPCError(statusCode) {
@@ -1049,8 +1055,10 @@ var FateClient = class {
1049
1055
  this.parentLists = /* @__PURE__ */ new Map();
1050
1056
  this.rootLists = /* @__PURE__ */ new Map();
1051
1057
  this.pending = /* @__PURE__ */ new Map();
1058
+ this.pendingOptimisticMutations = /* @__PURE__ */ new Map();
1052
1059
  this.optimisticMasks = /* @__PURE__ */ new Map();
1053
1060
  this.optimisticByEntity = /* @__PURE__ */ new Map();
1061
+ this.optimisticEntityResolutions = /* @__PURE__ */ new Map();
1054
1062
  this.optimisticTokenCounter = 0;
1055
1063
  this.requests = /* @__PURE__ */ new Map();
1056
1064
  this.rootRequests = /* @__PURE__ */ new Map();
@@ -1177,6 +1185,11 @@ var FateClient = class {
1177
1185
  }
1178
1186
  if (type == null) throw new Error(`fate: Invalid view reference. Expected '__typename' to be provided as part of the reference, received '${JSON.stringify(ref)}'.`);
1179
1187
  const entityId = toEntityId(type, id$1);
1188
+ const resolvedEntityId = this.optimisticEntityResolutions.get(entityId) ?? null;
1189
+ if (resolvedEntityId && resolvedEntityId !== entityId) {
1190
+ const { id: resolvedId, type: resolvedType } = parseEntityId(resolvedEntityId);
1191
+ return this.readView(view$1, createRef(resolvedType, resolvedId, view$1));
1192
+ }
1180
1193
  const viewNames = getViewNames(view$1);
1181
1194
  const refViews = ref[ViewsTag];
1182
1195
  if (!refViews || ![...viewNames].every((name) => refViews.has(name))) {
@@ -1204,6 +1217,14 @@ var FateClient = class {
1204
1217
  }
1205
1218
  if (missing.size > 0) {
1206
1219
  const key = this.pendingKey(entityId, missing);
1220
+ const pendingOptimistic = this.getPendingOptimisticMutations(entityId);
1221
+ if (pendingOptimistic) {
1222
+ const pending = this.pending.get(key);
1223
+ if (pending) return pending;
1224
+ const promise$1 = Promise.all(pendingOptimistic).then(() => this.readView(view$1, ref)).finally(() => this.pending.delete(key));
1225
+ this.pending.set(key, promise$1);
1226
+ return promise$1;
1227
+ }
1207
1228
  if (this.stalledRequests.has(key)) return resolveSnapshot();
1208
1229
  const pendingPromise = this.pending.get(key) || null;
1209
1230
  if (pendingPromise) return pendingPromise;
@@ -1257,6 +1278,24 @@ var FateClient = class {
1257
1278
  } : void 0
1258
1279
  };
1259
1280
  }
1281
+ registerPendingOptimisticMutation(entityId, promise) {
1282
+ let entries = this.pendingOptimisticMutations.get(entityId);
1283
+ if (!entries) {
1284
+ entries = /* @__PURE__ */ new Set();
1285
+ this.pendingOptimisticMutations.set(entityId, entries);
1286
+ }
1287
+ const trackedPromise = promise.catch(() => void 0);
1288
+ entries.add(trackedPromise);
1289
+ trackedPromise.finally(() => {
1290
+ const current = this.pendingOptimisticMutations.get(entityId);
1291
+ if (!current) return;
1292
+ current.delete(trackedPromise);
1293
+ if (current.size === 0) this.pendingOptimisticMutations.delete(entityId);
1294
+ });
1295
+ }
1296
+ resolveOptimisticEntity(optimisticEntityId, resolvedEntityId) {
1297
+ this.optimisticEntityResolutions.set(optimisticEntityId, resolvedEntityId);
1298
+ }
1260
1299
  registerOptimisticUpdate(entityId, select) {
1261
1300
  if (!entityId || select.size === 0) return null;
1262
1301
  const mask = fromPaths(select);
@@ -1298,6 +1337,10 @@ var FateClient = class {
1298
1337
  }
1299
1338
  return mask;
1300
1339
  }
1340
+ getPendingOptimisticMutations(entityId) {
1341
+ const pending = this.pendingOptimisticMutations.get(entityId);
1342
+ return pending && pending.size > 0 ? [...pending] : null;
1343
+ }
1301
1344
  filterSelectionForPendingOptimistics(entityId, select, options = {}) {
1302
1345
  if (!entityId || select.size === 0) return select;
1303
1346
  const pendingMask = this.getPendingOptimisticMask(entityId, options);
package/lib/server.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as AnyRecord } from "./types-CNKGKRtz.mjs";
1
+ import { t as AnyRecord } from "./types-BiDLhb07.mjs";
2
2
  import { z } from "zod";
3
3
  import { TRPCProcedureBuilder } from "@trpc/server";
4
4
 
@@ -181,8 +181,10 @@ declare class FateClient<Roots extends FateRoots, Mutations extends FateMutation
181
181
  private readonly parentLists;
182
182
  private readonly rootLists;
183
183
  private readonly pending;
184
+ private readonly pendingOptimisticMutations;
184
185
  private readonly optimisticMasks;
185
186
  private readonly optimisticByEntity;
187
+ private readonly optimisticEntityResolutions;
186
188
  private optimisticTokenCounter;
187
189
  private readonly requests;
188
190
  private readonly rootRequests;
@@ -215,11 +217,14 @@ declare class FateClient<Roots extends FateRoots, Mutations extends FateMutation
215
217
  }>;
216
218
  readView<T$1 extends Entity, S extends Selection<T$1>, V extends View<T$1, S>>(view: V, ref: ViewRef<T$1['__typename']>): FateThenable<ViewSnapshot<T$1, S>>;
217
219
  private mergeListState;
220
+ registerPendingOptimisticMutation(entityId: EntityId, promise: Promise<unknown>): void;
221
+ resolveOptimisticEntity(optimisticEntityId: EntityId, resolvedEntityId: EntityId): void;
218
222
  registerOptimisticUpdate(entityId: EntityId | null, select: ReadonlySet<string>): number | null;
219
223
  clearOptimisticUpdate(token: number | null): void;
220
224
  getPendingOptimisticMask(entityId: EntityId | null, options?: {
221
225
  excludeToken?: number | null;
222
226
  }): FieldMask | null;
227
+ private getPendingOptimisticMutations;
223
228
  filterSelectionForPendingOptimistics(entityId: EntityId | null, select: Set<string>, options?: {
224
229
  excludeToken?: number | null;
225
230
  }): Set<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nkzw/fate",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "fate is a modern data client for React.",
5
5
  "homepage": "https://github.com/nkzw-tech/fate",
6
6
  "repository": {