@sanity-labs/client-fake-for-test 0.7.1 → 0.8.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/dist/index.cjs CHANGED
@@ -73,57 +73,6 @@ function makeRequestImpl(getAccess, projectId, dataset) {
73
73
  );
74
74
  };
75
75
  }
76
- function createTestStore(initial) {
77
- const docs = /* @__PURE__ */ new Map(), promote2 = (doc) => {
78
- if (typeof doc._id != "string" || doc._id.length === 0)
79
- throw fakeError(
80
- `Cannot seed/store a document without a non-empty string \`_id\` (got ${JSON.stringify(doc._id)}). This fake never auto-generates ids \u2014 give every document an explicit _id. Document: ${JSON.stringify(doc)}`
81
- );
82
- if (typeof doc._type != "string" || doc._type.length === 0)
83
- throw fakeError(
84
- `Document "${doc._id}" is missing a non-empty string \`_type\` (got ${JSON.stringify(doc._type)}). Every Sanity document needs a _type.`
85
- );
86
- const now = (/* @__PURE__ */ new Date()).toISOString();
87
- return {
88
- ...doc,
89
- _id: doc._id,
90
- _type: doc._type,
91
- _rev: doc._rev ?? cryptoRandomKey(),
92
- _createdAt: doc._createdAt ?? now,
93
- _updatedAt: doc._updatedAt ?? now
94
- };
95
- }, seed = (documents) => {
96
- docs.clear();
97
- for (const d of documents) {
98
- const promoted = promote2(d);
99
- docs.set(promoted._id, promoted);
100
- }
101
- };
102
- return initial && seed(initial), {
103
- seed,
104
- add: (documents) => {
105
- for (const d of documents) {
106
- const promoted = promote2(d);
107
- docs.set(promoted._id, promoted);
108
- }
109
- },
110
- reset: () => docs.clear(),
111
- all: () => [...docs.values()],
112
- get: (id) => docs.get(id),
113
- put: (doc) => {
114
- docs.set(doc._id, doc);
115
- },
116
- remove: (id) => {
117
- const doc = docs.get(id);
118
- return doc && docs.delete(id), doc;
119
- },
120
- snapshot: () => [...docs.values()]
121
- };
122
- }
123
- function cryptoRandomKey(length = 12) {
124
- const bytes = new Uint8Array(length);
125
- return globalThis.crypto.getRandomValues(bytes), [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, length);
126
- }
127
76
  function describeType(value) {
128
77
  return value === null ? "null" : Array.isArray(value) ? "an array" : `a ${typeof value}`;
129
78
  }
@@ -326,13 +275,140 @@ function insertIntoArray(doc, position, anchor, items) {
326
275
  const idx = resolveSelector(arr, last.selector);
327
276
  position === "replace" ? arr.splice(idx, 1, ...items) : position === "before" ? arr.splice(idx, 0, ...items) : arr.splice(idx + 1, 0, ...items);
328
277
  }
329
- const RELEASE_DOC_PREFIX$1 = "_.releases.", VERSIONS_PREFIX$1 = "versions.", releaseDocId = (releaseId) => `${RELEASE_DOC_PREFIX$1}${releaseId}`, versionDocId = (releaseId, publishedId) => `${VERSIONS_PREFIX$1}${releaseId}.${publishedId}`;
278
+ const DRAFTS_PREFIX = "drafts.", VERSIONS_PREFIX$1 = "versions.", RELEASE_DOC_PREFIX$1 = "_.releases.";
279
+ function publishedIdOf(id) {
280
+ if (id.startsWith(DRAFTS_PREFIX)) return id.slice(DRAFTS_PREFIX.length);
281
+ if (id.startsWith(VERSIONS_PREFIX$1)) {
282
+ const rest = id.slice(VERSIONS_PREFIX$1.length), dot = rest.indexOf(".");
283
+ return dot === -1 ? rest : rest.slice(dot + 1);
284
+ }
285
+ return id;
286
+ }
287
+ function releaseNameOf(id) {
288
+ if (!id.startsWith(VERSIONS_PREFIX$1)) return;
289
+ const rest = id.slice(VERSIONS_PREFIX$1.length), dot = rest.indexOf(".");
290
+ if (dot !== -1)
291
+ return rest.slice(0, dot);
292
+ }
293
+ const isDraftId = (id) => id.startsWith(DRAFTS_PREFIX), isVersionId = (id) => id.startsWith(VERSIONS_PREFIX$1), isSystemId = (id) => id.startsWith("_."), isReleaseDocId = (id) => id.startsWith(RELEASE_DOC_PREFIX$1);
294
+ function applyPerspective(docs, perspective) {
295
+ if (perspective === "raw") return [...docs];
296
+ if (perspective === "published")
297
+ return docs.filter((d) => !isDraftId(d._id) && !isVersionId(d._id) && !isSystemId(d._id));
298
+ if (perspective === "drafts")
299
+ return mergeStack(docs, [], { includeDrafts: !0, includeReleaseDocs: !1 });
300
+ const stack = [];
301
+ let includeDrafts = !1;
302
+ for (const entry of perspective)
303
+ entry === "drafts" ? includeDrafts = !0 : stack.push(entry);
304
+ return mergeStack(docs, stack, { includeDrafts, includeReleaseDocs: !0 });
305
+ }
306
+ function mergeStack(docs, releaseStack, options) {
307
+ const groups = /* @__PURE__ */ new Map(), systemReleases = [];
308
+ for (const doc of docs) {
309
+ if (isReleaseDocId(doc._id)) {
310
+ options.includeReleaseDocs && systemReleases.push(doc);
311
+ continue;
312
+ }
313
+ if (isSystemId(doc._id)) continue;
314
+ const pubId = publishedIdOf(doc._id);
315
+ let group = groups.get(pubId);
316
+ if (group === void 0 && (group = { versions: /* @__PURE__ */ new Map() }, groups.set(pubId, group)), isDraftId(doc._id))
317
+ group.draft = doc;
318
+ else if (isVersionId(doc._id)) {
319
+ const releaseName = releaseNameOf(doc._id);
320
+ releaseName !== void 0 && group.versions.set(releaseName, doc);
321
+ } else
322
+ group.published = doc;
323
+ }
324
+ const out = [];
325
+ for (const [pubId, group] of groups) {
326
+ let chosen;
327
+ for (const releaseName of releaseStack) {
328
+ const v = group.versions.get(releaseName);
329
+ if (v !== void 0) {
330
+ if (isUnpublishStub(v)) {
331
+ chosen = void 0;
332
+ break;
333
+ }
334
+ chosen = v;
335
+ break;
336
+ }
337
+ }
338
+ chosen === void 0 && options.includeDrafts && group.draft !== void 0 && (chosen = group.draft), chosen === void 0 && group.published !== void 0 && (releaseStack.some((name) => {
339
+ const v = group.versions.get(name);
340
+ return v !== void 0 && isUnpublishStub(v);
341
+ }) || (chosen = group.published)), chosen !== void 0 && out.push(projectToPublishedId(chosen, pubId));
342
+ }
343
+ return [...out, ...systemReleases];
344
+ }
345
+ function isUnpublishStub(doc) {
346
+ return doc._system?.delete === !0;
347
+ }
348
+ function projectToPublishedId(doc, pubId) {
349
+ return doc._id === pubId ? doc : { ...doc, _id: pubId, _originalId: doc._id };
350
+ }
351
+ function resolveDocument(docs, id, perspective) {
352
+ return perspective === "raw" ? docs.find((d) => d._id === id) : applyPerspective(docs, perspective).find((d) => d._id === id);
353
+ }
354
+ function createTestStore(initial) {
355
+ const docs = /* @__PURE__ */ new Map(), promote2 = (doc) => {
356
+ if (typeof doc._id != "string" || doc._id.length === 0)
357
+ throw fakeError(
358
+ `Cannot seed/store a document without a non-empty string \`_id\` (got ${JSON.stringify(doc._id)}). This fake never auto-generates ids \u2014 give every document an explicit _id. Document: ${JSON.stringify(doc)}`
359
+ );
360
+ if (typeof doc._type != "string" || doc._type.length === 0)
361
+ throw fakeError(
362
+ `Document "${doc._id}" is missing a non-empty string \`_type\` (got ${JSON.stringify(doc._type)}). Every Sanity document needs a _type.`
363
+ );
364
+ const now = (/* @__PURE__ */ new Date()).toISOString();
365
+ return {
366
+ ...doc,
367
+ _id: doc._id,
368
+ _type: doc._type,
369
+ _rev: doc._rev ?? cryptoRandomKey(),
370
+ _createdAt: doc._createdAt ?? now,
371
+ _updatedAt: doc._updatedAt ?? now
372
+ };
373
+ }, seed = (documents) => {
374
+ docs.clear();
375
+ for (const d of documents) {
376
+ const promoted = promote2(d);
377
+ docs.set(promoted._id, promoted);
378
+ }
379
+ };
380
+ return initial && seed(initial), {
381
+ seed,
382
+ add: (documents) => {
383
+ for (const d of documents) {
384
+ const promoted = promote2(d);
385
+ docs.set(promoted._id, promoted);
386
+ }
387
+ },
388
+ reset: () => docs.clear(),
389
+ all: () => [...docs.values()],
390
+ get: (id) => docs.get(id),
391
+ put: (doc) => {
392
+ docs.set(doc._id, doc);
393
+ },
394
+ remove: (id) => {
395
+ const doc = docs.get(id);
396
+ return doc && docs.delete(id), doc;
397
+ },
398
+ snapshot: () => [...docs.values()]
399
+ };
400
+ }
401
+ function cryptoRandomKey(length = 12) {
402
+ const bytes = new Uint8Array(length);
403
+ return globalThis.crypto.getRandomValues(bytes), [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, length);
404
+ }
405
+ const RELEASE_DOC_PREFIX = "_.releases.", VERSIONS_PREFIX = "versions.", releaseDocId = (releaseId) => `${RELEASE_DOC_PREFIX}${releaseId}`, versionDocId = (releaseId, publishedId) => `${VERSIONS_PREFIX}${releaseId}.${publishedId}`;
330
406
  function parseVersionId(versionId) {
331
- if (!versionId.startsWith(VERSIONS_PREFIX$1))
407
+ if (!versionId.startsWith(VERSIONS_PREFIX))
332
408
  throw fakeError(
333
409
  `"${versionId}" is not a version document id. Version ids look like "versions.<releaseId>.<publishedId>" (e.g. "versions.summer-drop.product-1").`
334
410
  );
335
- const rest = versionId.slice(VERSIONS_PREFIX$1.length), dot = rest.indexOf(".");
411
+ const rest = versionId.slice(VERSIONS_PREFIX.length), dot = rest.indexOf(".");
336
412
  if (dot === -1)
337
413
  throw fakeError(
338
414
  `"${versionId}" is not a version document id. Version ids look like "versions.<releaseId>.<publishedId>" (e.g. "versions.summer-drop.product-1").`
@@ -378,7 +454,7 @@ function requireActive(release) {
378
454
  `Release "${release.name}" is "${release.state}", but only "active" releases accept version writes (create / replace / discard / unpublish). Unschedule or unarchive it back to "active" first, or target a different release.`
379
455
  );
380
456
  }
381
- function applyAction(store, action) {
457
+ async function applyAction(store, action, hooks) {
382
458
  switch (action.actionType) {
383
459
  case "sanity.action.release.create": {
384
460
  if (maybeRelease(store, action.releaseId) !== void 0)
@@ -436,7 +512,7 @@ function applyAction(store, action) {
436
512
  throw fakeError(
437
513
  `Cannot publish release "${action.releaseId}": it is "${release.state}", and only "active" or "scheduled" releases can be published.`
438
514
  );
439
- const prefix = `${VERSIONS_PREFIX$1}${action.releaseId}.`, sources = store.all().filter((d) => d._id.startsWith(prefix));
515
+ const prefix = `${VERSIONS_PREFIX}${action.releaseId}.`, sources = store.all().filter((d) => d._id.startsWith(prefix));
440
516
  for (const v of sources) {
441
517
  const pubId = v._id.slice(prefix.length);
442
518
  if (v._system?.delete === !0)
@@ -476,7 +552,7 @@ function applyAction(store, action) {
476
552
  throw fakeError(
477
553
  `Cannot delete release "${action.releaseId}": it is "${release.state}", and only "archived" or "published" releases can be deleted. Archive it first (sanity.action.release.archive) or publish it.`
478
554
  );
479
- const prefix = `${VERSIONS_PREFIX$1}${action.releaseId}.`;
555
+ const prefix = `${VERSIONS_PREFIX}${action.releaseId}.`;
480
556
  for (const v of store.all())
481
557
  v._id.startsWith(prefix) && store.remove(v._id);
482
558
  return store.remove(release._id), { transactionId: cryptoRandomKey() };
@@ -520,9 +596,46 @@ function applyAction(store, action) {
520
596
  };
521
597
  return store.put(promote(doc)), { transactionId: cryptoRandomKey() };
522
598
  }
599
+ case "sanity.action.document.publish": {
600
+ requireDraftOf(action);
601
+ const draft = store.get(action.draftId);
602
+ if (draft === void 0)
603
+ throw fakeError(
604
+ `Cannot publish "${action.publishedId}": draft "${action.draftId}" not found. document.publish promotes an existing draft onto the published id \u2014 create the draft first (e.g. client.createOrReplace({ _id: "${action.draftId}", ... })).`
605
+ );
606
+ const published = store.get(action.publishedId);
607
+ requireRevisionMatch(action.draftId, draft._rev, action.ifDraftRevisionId), requireRevisionMatch(action.publishedId, published?._rev, action.ifPublishedRevisionId);
608
+ const promoted = promote({ ...draft, _id: action.publishedId });
609
+ return published !== void 0 && (promoted._createdAt = published._createdAt), await hooks?.gate?.(promoted, published === void 0 ? "create" : "update"), await hooks?.guard?.("publish", published ?? null, promoted), store.put(promoted), store.remove(action.draftId), { transactionId: cryptoRandomKey() };
610
+ }
611
+ case "sanity.action.document.unpublish": {
612
+ requireDraftOf(action);
613
+ const published = store.get(action.publishedId);
614
+ if (published === void 0)
615
+ throw fakeError(
616
+ `Cannot unpublish "${action.publishedId}": no published document with that _id exists. document.unpublish retracts a live published document into "${action.draftId}".`
617
+ );
618
+ if (await hooks?.gate?.(published, "update"), await hooks?.guard?.("unpublish", published, null), store.get(action.draftId) === void 0) {
619
+ const draft = promote({ ...published, _id: action.draftId });
620
+ draft._createdAt = published._createdAt, store.put(draft);
621
+ }
622
+ return store.remove(action.publishedId), { transactionId: cryptoRandomKey() };
623
+ }
523
624
  }
524
625
  }
525
- function applyActions(store, actions) {
626
+ function requireDraftOf(action) {
627
+ if (!(publishedIdOf(action.draftId) === action.publishedId && action.draftId !== action.publishedId))
628
+ throw fakeError(
629
+ `${action.actionType}: draftId "${action.draftId}" is not the draft of publishedId "${action.publishedId}" \u2014 expected draftId "drafts.${action.publishedId}".`
630
+ );
631
+ }
632
+ function requireRevisionMatch(documentId, actualRev, expectedRev) {
633
+ if (!(expectedRev === void 0 || actualRev === expectedRev))
634
+ throw fakeError(
635
+ `Revision precondition failed for "${documentId}": expected _rev "${expectedRev}" but the document is at ${actualRev === void 0 ? "no revision (missing)" : `"${actualRev}"`}.`
636
+ );
637
+ }
638
+ async function applyActions(store, actions, hooks) {
526
639
  const list = Array.isArray(actions) ? actions : [actions], snapshot = /* @__PURE__ */ new Map(), remember = (id) => {
527
640
  snapshot.has(id) || snapshot.set(id, store.get(id));
528
641
  };
@@ -537,11 +650,11 @@ function applyActions(store, actions) {
537
650
  case "sanity.action.release.archive":
538
651
  case "sanity.action.release.unarchive":
539
652
  case "sanity.action.release.delete":
540
- remember(`${RELEASE_DOC_PREFIX$1}${a.releaseId}`);
653
+ remember(`${RELEASE_DOC_PREFIX}${a.releaseId}`);
541
654
  break;
542
655
  case "sanity.action.release.publish": {
543
- remember(`${RELEASE_DOC_PREFIX$1}${a.releaseId}`);
544
- const prefix = `${VERSIONS_PREFIX$1}${a.releaseId}.`;
656
+ remember(`${RELEASE_DOC_PREFIX}${a.releaseId}`);
657
+ const prefix = `${VERSIONS_PREFIX}${a.releaseId}.`;
545
658
  for (const d of store.all())
546
659
  d._id.startsWith(prefix) && (remember(d._id), remember(d._id.slice(prefix.length)));
547
660
  break;
@@ -558,8 +671,12 @@ function applyActions(store, actions) {
558
671
  case "sanity.action.document.version.unpublish":
559
672
  remember(a.versionId);
560
673
  break;
674
+ case "sanity.action.document.publish":
675
+ case "sanity.action.document.unpublish":
676
+ remember(a.draftId), remember(a.publishedId);
677
+ break;
561
678
  }
562
- last = applyAction(store, a);
679
+ last = await applyAction(store, a, hooks);
563
680
  }
564
681
  return last;
565
682
  } catch (err) {
@@ -568,82 +685,6 @@ function applyActions(store, actions) {
568
685
  throw err;
569
686
  }
570
687
  }
571
- const DRAFTS_PREFIX = "drafts.", VERSIONS_PREFIX = "versions.", RELEASE_DOC_PREFIX = "_.releases.";
572
- function publishedIdOf(id) {
573
- if (id.startsWith(DRAFTS_PREFIX)) return id.slice(DRAFTS_PREFIX.length);
574
- if (id.startsWith(VERSIONS_PREFIX)) {
575
- const rest = id.slice(VERSIONS_PREFIX.length), dot = rest.indexOf(".");
576
- return dot === -1 ? rest : rest.slice(dot + 1);
577
- }
578
- return id;
579
- }
580
- function releaseNameOf(id) {
581
- if (!id.startsWith(VERSIONS_PREFIX)) return;
582
- const rest = id.slice(VERSIONS_PREFIX.length), dot = rest.indexOf(".");
583
- if (dot !== -1)
584
- return rest.slice(0, dot);
585
- }
586
- const isDraftId = (id) => id.startsWith(DRAFTS_PREFIX), isVersionId = (id) => id.startsWith(VERSIONS_PREFIX), isSystemId = (id) => id.startsWith("_."), isReleaseDocId = (id) => id.startsWith(RELEASE_DOC_PREFIX);
587
- function applyPerspective(docs, perspective) {
588
- if (perspective === "raw") return [...docs];
589
- if (perspective === "published")
590
- return docs.filter((d) => !isDraftId(d._id) && !isVersionId(d._id) && !isSystemId(d._id));
591
- if (perspective === "drafts")
592
- return mergeStack(docs, [], { includeDrafts: !0, includeReleaseDocs: !1 });
593
- const stack = [];
594
- let includeDrafts = !1;
595
- for (const entry of perspective)
596
- entry === "drafts" ? includeDrafts = !0 : stack.push(entry);
597
- return mergeStack(docs, stack, { includeDrafts, includeReleaseDocs: !0 });
598
- }
599
- function mergeStack(docs, releaseStack, options) {
600
- const groups = /* @__PURE__ */ new Map(), systemReleases = [];
601
- for (const doc of docs) {
602
- if (isReleaseDocId(doc._id)) {
603
- options.includeReleaseDocs && systemReleases.push(doc);
604
- continue;
605
- }
606
- if (isSystemId(doc._id)) continue;
607
- const pubId = publishedIdOf(doc._id);
608
- let group = groups.get(pubId);
609
- if (group === void 0 && (group = { versions: /* @__PURE__ */ new Map() }, groups.set(pubId, group)), isDraftId(doc._id))
610
- group.draft = doc;
611
- else if (isVersionId(doc._id)) {
612
- const releaseName = releaseNameOf(doc._id);
613
- releaseName !== void 0 && group.versions.set(releaseName, doc);
614
- } else
615
- group.published = doc;
616
- }
617
- const out = [];
618
- for (const [pubId, group] of groups) {
619
- let chosen;
620
- for (const releaseName of releaseStack) {
621
- const v = group.versions.get(releaseName);
622
- if (v !== void 0) {
623
- if (isUnpublishStub(v)) {
624
- chosen = void 0;
625
- break;
626
- }
627
- chosen = v;
628
- break;
629
- }
630
- }
631
- chosen === void 0 && options.includeDrafts && group.draft !== void 0 && (chosen = group.draft), chosen === void 0 && group.published !== void 0 && (releaseStack.some((name) => {
632
- const v = group.versions.get(name);
633
- return v !== void 0 && isUnpublishStub(v);
634
- }) || (chosen = group.published)), chosen !== void 0 && out.push(projectToPublishedId(chosen, pubId));
635
- }
636
- return [...out, ...systemReleases];
637
- }
638
- function isUnpublishStub(doc) {
639
- return doc._system?.delete === !0;
640
- }
641
- function projectToPublishedId(doc, pubId) {
642
- return doc._id === pubId ? doc : { ...doc, _id: pubId, _originalId: doc._id };
643
- }
644
- function resolveDocument(docs, id, perspective) {
645
- return perspective === "raw" ? docs.find((d) => d._id === id) : applyPerspective(docs, perspective).find((d) => d._id === id);
646
- }
647
688
  function createTransaction(executor) {
648
689
  const mutations = [], handle = {
649
690
  create: (doc) => (mutations.push({ kind: "create", doc }), handle),
@@ -1138,7 +1179,7 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
1138
1179
  txnOptions?.returnDocuments ?? !1,
1139
1180
  txnOptions?.returnFirst ?? !1
1140
1181
  );
1141
- }, runAction = (actions) => serializeWrite(backend, async () => applyActions(store, actions)), accessVisibleDocs = async () => {
1182
+ }, runAction = (actions) => serializeWrite(backend, async () => applyActions(store, actions, { gate, guard: guardGate })), accessVisibleDocs = async () => {
1142
1183
  const all = store.all();
1143
1184
  if (activeAccess() === void 0) return all;
1144
1185
  const out = [];