@sanity-labs/client-fake-for-test 0.6.0 → 0.7.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/dist/index.cjs CHANGED
@@ -138,7 +138,7 @@ function createPatch(documentId, executor) {
138
138
  dec: (props) => (ops.push({ kind: "dec", props }), handle),
139
139
  insert: (position, anchor, items) => (ops.push({ kind: "insert", position, anchor, items }), handle),
140
140
  ifRevisionId: (rev) => (ifRev = rev, handle),
141
- commit: () => executor.apply(documentId, ops, ifRev),
141
+ commit: (options) => executor.apply(documentId, ops, ifRev, options),
142
142
  toJSON: () => ({
143
143
  id: documentId,
144
144
  ops: [...ops],
@@ -839,6 +839,25 @@ function wrapWithGuards(client, config) {
839
839
  }
840
840
  });
841
841
  }
842
+ const OPTIONS_ARG_POSITION = {
843
+ fetch: 2,
844
+ getDocument: 1,
845
+ getDocuments: 1,
846
+ create: 1,
847
+ createOrReplace: 1,
848
+ createIfNotExists: 1,
849
+ delete: 1,
850
+ mutate: 1,
851
+ action: 1,
852
+ request: 0
853
+ };
854
+ function tagFromArgs(method, args) {
855
+ const position = OPTIONS_ARG_POSITION[method];
856
+ if (position === void 0) return;
857
+ const options = args[position];
858
+ if (!(typeof options != "object" || options === null || !("tag" in options)))
859
+ return options.tag;
860
+ }
842
861
  const RECORDED_METHODS = /* @__PURE__ */ new Set([
843
862
  "fetch",
844
863
  "getDocument",
@@ -856,6 +875,15 @@ const RECORDED_METHODS = /* @__PURE__ */ new Set([
856
875
  "unpublishVersion",
857
876
  "request"
858
877
  ]), DEFAULT_PROJECT_ID = "test", DEFAULT_DATASET = "test";
878
+ function serializeWrite(backend, run) {
879
+ const result = backend.writeChain.then(run);
880
+ return backend.writeChain = result.then(
881
+ () => {
882
+ },
883
+ () => {
884
+ }
885
+ ), result;
886
+ }
859
887
  function requireIdentity(backend, token, site) {
860
888
  if (backend.identities.has(token)) return;
861
889
  const known = [...backend.identities.keys()];
@@ -880,7 +908,8 @@ function createTestClient(options = {}) {
880
908
  stubs: /* @__PURE__ */ new Map(),
881
909
  calls: [],
882
910
  concurrentEdits: /* @__PURE__ */ new Map(),
883
- identities: new Map(Object.entries(options.identities ?? {}))
911
+ identities: new Map(Object.entries(options.identities ?? {})),
912
+ writeChain: Promise.resolve()
884
913
  }, registry = backend.registry;
885
914
  rejectAmbiguousIdentity("createTestClient()", options), options.token !== void 0 && requireIdentity(backend, options.token, "createTestClient()");
886
915
  const ensureStore = (projectId, dataset) => {
@@ -969,8 +998,14 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
969
998
  const key = registryKey(projectId, dataset);
970
999
  let s = registry.get(key);
971
1000
  return s === void 0 && (s = createTestStore(), registry.set(key, s)), s;
972
- })(), concurrentEditKey = (id) => registryKey(projectId, dataset) + " " + id, record = (transactionId, mutations) => {
973
- backend.log.push({ transactionId, projectId, dataset, mutations });
1001
+ })(), concurrentEditKey = (id) => registryKey(projectId, dataset) + " " + id, record = (transactionId, mutations, tag) => {
1002
+ backend.log.push({
1003
+ transactionId,
1004
+ projectId,
1005
+ dataset,
1006
+ mutations,
1007
+ ...tag !== void 0 ? { tag } : {}
1008
+ });
974
1009
  }, writeResult = (documents, results, transactionId, opts) => formatMutationResult(
975
1010
  documents,
976
1011
  results,
@@ -1094,7 +1129,7 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1094
1129
  doc === void 0 ? store.remove(id) : store.put(doc);
1095
1130
  throw error;
1096
1131
  }
1097
- record(transactionId, mutations);
1132
+ record(transactionId, mutations, txnOptions?.tag);
1098
1133
  const documents = touchedIds.map((id) => store.get(id)).filter((d) => d !== void 0);
1099
1134
  return formatMutationResult(
1100
1135
  documents,
@@ -1103,7 +1138,7 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1103
1138
  txnOptions?.returnDocuments ?? !1,
1104
1139
  txnOptions?.returnFirst ?? !1
1105
1140
  );
1106
- }, accessVisibleDocs = async () => {
1141
+ }, runAction = (actions) => serializeWrite(backend, async () => applyActions(store, actions)), accessVisibleDocs = async () => {
1107
1142
  const all = store.all();
1108
1143
  if (activeAccess() === void 0) return all;
1109
1144
  const out = [];
@@ -1147,7 +1182,7 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1147
1182
  const view = await visibleDocs(effective);
1148
1183
  return ids.map((id) => resolveDocument(view, id, effective) ?? null);
1149
1184
  },
1150
- create: async (doc, opts) => {
1185
+ create: (doc, opts) => serializeWrite(backend, async () => {
1151
1186
  if (checkRevision(doc._id, opts?.ifRevisionId), store.get(doc._id) !== void 0)
1152
1187
  throw fakeError(
1153
1188
  `create() failed: a document with _id "${doc._id}" already exists in dataset "${projectId}:${dataset}". Use createOrReplace() to overwrite it, or createIfNotExists() to leave the existing one untouched.`
@@ -1155,19 +1190,19 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1155
1190
  const promoted = promote2(doc);
1156
1191
  await gate(promoted, "create"), await guardGate("create", null, promoted);
1157
1192
  const transactionId = opts?.transactionId ?? cryptoRandomKey();
1158
- return opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "create", doc }])), writeResult(
1193
+ return opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "create", doc }], opts?.tag)), writeResult(
1159
1194
  [promoted],
1160
1195
  [{ id: promoted._id, operation: "create" }],
1161
1196
  transactionId,
1162
1197
  opts
1163
1198
  );
1164
- },
1165
- createOrReplace: async (doc, opts) => {
1199
+ }),
1200
+ createOrReplace: (doc, opts) => serializeWrite(backend, async () => {
1166
1201
  checkRevision(doc._id, opts?.ifRevisionId);
1167
1202
  const promoted = promote2(doc), existing = store.get(doc._id);
1168
1203
  await gate(existing ?? promoted, existing !== void 0 ? "update" : "create"), await guardGate(existing !== void 0 ? "update" : "create", existing ?? null, promoted);
1169
1204
  const transactionId = opts?.transactionId ?? cryptoRandomKey();
1170
- opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "createOrReplace", doc }]));
1205
+ opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "createOrReplace", doc }], opts?.tag));
1171
1206
  const operation = existing !== void 0 ? "update" : "create";
1172
1207
  return writeResult(
1173
1208
  [promoted],
@@ -1175,8 +1210,8 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1175
1210
  transactionId,
1176
1211
  opts
1177
1212
  );
1178
- },
1179
- createIfNotExists: async (doc, opts) => {
1213
+ }),
1214
+ createIfNotExists: (doc, opts) => serializeWrite(backend, async () => {
1180
1215
  checkRevision(doc._id, opts?.ifRevisionId);
1181
1216
  const existing = store.get(doc._id), transactionId = opts?.transactionId ?? cryptoRandomKey();
1182
1217
  if (existing !== void 0)
@@ -1187,41 +1222,55 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1187
1222
  opts
1188
1223
  );
1189
1224
  const promoted = promote2(doc);
1190
- return await gate(promoted, "create"), await guardGate("create", null, promoted), opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "createIfNotExists", doc }])), writeResult(
1225
+ return await gate(promoted, "create"), await guardGate("create", null, promoted), opts?.dryRun !== !0 && (store.put(promoted), record(transactionId, [{ kind: "createIfNotExists", doc }], opts?.tag)), writeResult(
1191
1226
  [promoted],
1192
1227
  [{ id: promoted._id, operation: "create" }],
1193
1228
  transactionId,
1194
1229
  opts
1195
1230
  );
1196
- },
1197
- delete: async (id, opts) => {
1231
+ }),
1232
+ delete: (id, opts) => serializeWrite(backend, async () => {
1198
1233
  checkRevision(id, opts?.ifRevisionId);
1199
1234
  const existing = store.get(id);
1200
1235
  existing !== void 0 && await gate(existing, "update"), existing !== void 0 && await guardGate("delete", existing, null);
1201
1236
  const transactionId = opts?.transactionId ?? cryptoRandomKey();
1202
1237
  let removed = existing;
1203
- return opts?.dryRun !== !0 && (removed = store.remove(id), removed !== void 0 && record(transactionId, [{ kind: "delete", id }])), opts?.returnDocuments === void 0 && opts?.returnFirst === void 0 ? removed !== void 0 ? { _id: id } : null : formatMutationResult(
1238
+ return opts?.dryRun !== !0 && (removed = store.remove(id), removed !== void 0 && record(transactionId, [{ kind: "delete", id }], opts?.tag)), opts?.returnDocuments === void 0 && opts?.returnFirst === void 0 ? removed !== void 0 ? { _id: id } : null : formatMutationResult(
1204
1239
  removed !== void 0 ? [removed] : [],
1205
1240
  removed !== void 0 ? [{ id, operation: "delete" }] : [],
1206
1241
  transactionId,
1207
1242
  opts.returnDocuments ?? !0,
1208
1243
  opts.returnFirst ?? !0
1209
1244
  );
1210
- },
1245
+ }),
1211
1246
  patch: (documentId) => createPatch(documentId, {
1212
- apply: async (docId, ops, ifRev) => {
1247
+ apply: (docId, ops, ifRev, options) => serializeWrite(backend, async () => {
1213
1248
  const doc = await applyPatch(docId, ops, ifRev);
1214
- return record(cryptoRandomKey(), [
1215
- { kind: "patch", documentId: docId, ops, ...ifRev !== void 0 ? { ifRev } : {} }
1216
- ]), doc;
1217
- }
1249
+ return record(
1250
+ cryptoRandomKey(),
1251
+ [
1252
+ {
1253
+ kind: "patch",
1254
+ documentId: docId,
1255
+ ops,
1256
+ ...ifRev !== void 0 ? { ifRev } : {}
1257
+ }
1258
+ ],
1259
+ options?.tag
1260
+ ), doc;
1261
+ })
1262
+ }),
1263
+ transaction: () => createTransaction({
1264
+ apply: (mutations, txnOptions) => serializeWrite(backend, () => applyTransaction(mutations, txnOptions))
1218
1265
  }),
1219
- transaction: () => createTransaction({ apply: applyTransaction }),
1220
- mutate: async (operations, options) => applyTransaction(toTxnMutations(operations), options),
1221
- action: async (action) => applyActions(store, action),
1266
+ mutate: (operations, options) => serializeWrite(backend, () => applyTransaction(toTxnMutations(operations), options)),
1267
+ // Synchronous writes still take the lock: an action landing while a
1268
+ // guarded patch is parked in its gate would otherwise be clobbered
1269
+ // when that patch resumes over its pre-action snapshot.
1270
+ action: (action) => runAction(action),
1222
1271
  releases: {
1223
1272
  create: async ({ releaseId, metadata }) => {
1224
- const result = applyActions(store, {
1273
+ const result = await runAction({
1225
1274
  actionType: "sanity.action.release.create",
1226
1275
  releaseId,
1227
1276
  ...metadata !== void 0 ? { metadata } : {}
@@ -1232,30 +1281,30 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1232
1281
  metadata: doc?.metadata ?? { releaseType: "undecided" }
1233
1282
  };
1234
1283
  },
1235
- edit: async ({ releaseId, patch }) => applyActions(store, { actionType: "sanity.action.release.edit", releaseId, patch }),
1284
+ edit: ({ releaseId, patch }) => runAction({ actionType: "sanity.action.release.edit", releaseId, patch }),
1236
1285
  get: async ({ releaseId }) => store.get(`_.releases.${releaseId}`),
1237
1286
  fetchDocuments: async ({ releaseId }) => {
1238
1287
  const prefix = `versions.${releaseId}.`;
1239
1288
  return store.all().filter((d) => d._id.startsWith(prefix));
1240
1289
  },
1241
- schedule: async ({ releaseId, publishAt }) => applyActions(store, {
1290
+ schedule: ({ releaseId, publishAt }) => runAction({
1242
1291
  actionType: "sanity.action.release.schedule",
1243
1292
  releaseId,
1244
1293
  publishAt
1245
1294
  }),
1246
- unschedule: async ({ releaseId }) => applyActions(store, { actionType: "sanity.action.release.unschedule", releaseId }),
1247
- publish: async ({ releaseId }) => applyActions(store, { actionType: "sanity.action.release.publish", releaseId }),
1248
- archive: async ({ releaseId }) => applyActions(store, { actionType: "sanity.action.release.archive", releaseId }),
1249
- unarchive: async ({ releaseId }) => applyActions(store, { actionType: "sanity.action.release.unarchive", releaseId }),
1250
- delete: async ({ releaseId }) => applyActions(store, { actionType: "sanity.action.release.delete", releaseId })
1295
+ unschedule: ({ releaseId }) => runAction({ actionType: "sanity.action.release.unschedule", releaseId }),
1296
+ publish: ({ releaseId }) => runAction({ actionType: "sanity.action.release.publish", releaseId }),
1297
+ archive: ({ releaseId }) => runAction({ actionType: "sanity.action.release.archive", releaseId }),
1298
+ unarchive: ({ releaseId }) => runAction({ actionType: "sanity.action.release.unarchive", releaseId }),
1299
+ delete: ({ releaseId }) => runAction({ actionType: "sanity.action.release.delete", releaseId })
1251
1300
  },
1252
- createVersion: async ({ releaseId, publishedId, document }) => applyActions(store, {
1301
+ createVersion: ({ releaseId, publishedId, document }) => runAction({
1253
1302
  actionType: "sanity.action.document.version.create",
1254
1303
  releaseId,
1255
1304
  publishedId,
1256
1305
  document
1257
1306
  }),
1258
- unpublishVersion: async ({ releaseId, publishedId }) => applyActions(store, {
1307
+ unpublishVersion: ({ releaseId, publishedId }) => runAction({
1259
1308
  actionType: "sanity.action.document.version.unpublish",
1260
1309
  versionId: `versions.${releaseId}.${publishedId}`,
1261
1310
  publishedId
@@ -1307,8 +1356,8 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1307
1356
  return wrapWithGuards(client, {
1308
1357
  getStub: (name) => backend.stubs.get(name),
1309
1358
  onCall: (method, args) => {
1310
- const rec = { method, args, projectId, dataset };
1311
- return backend.calls.push(rec), (outcome) => {
1359
+ const rec = { method, args, projectId, dataset }, tag = tagFromArgs(method, args);
1360
+ return tag !== void 0 && (rec.tag = tag), backend.calls.push(rec), (outcome) => {
1312
1361
  "error" in outcome ? rec.error = outcome.error : rec.result = outcome.result;
1313
1362
  };
1314
1363
  },