@sanity/workflow-engine 0.27.0 → 0.29.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
@@ -55,6 +55,53 @@ function findCurrentActivityEntry(host, activityName) {
55
55
  return findOpenStageEntry(host)?.activities.find(a => a.name === activityName);
56
56
  }
57
57
 
58
+ const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
59
+
60
+ function terminalState(instance) {
61
+ return instance.abortedAt !== void 0 ? "aborted" : instance.completedAt !== void 0 ? "completed" : "in-flight";
62
+ }
63
+
64
+ function isUnprimed(instance) {
65
+ return instance.stages.length === 0 && terminalState(instance) === "in-flight";
66
+ }
67
+
68
+ function parseDefinitionSnapshotValue(instance) {
69
+ try {
70
+ return normalizeLegacyActivityRequirements(JSON.parse(instance.definitionSnapshot));
71
+ } catch (err) {
72
+ invariants.rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
73
+ }
74
+ }
75
+
76
+ function normalizeLegacyActivityRequirements(value) {
77
+ for (const stage of arrayMember(value, "stages")) for (const activity of arrayMember(stage, "activities")) normalizeLegacyRequirementMap(activity);
78
+ return value;
79
+ }
80
+
81
+ function arrayMember(value, key) {
82
+ if (typeof value != "object" || value === null) return [];
83
+ const member = value[key];
84
+ return Array.isArray(member) ? member : [];
85
+ }
86
+
87
+ function normalizeLegacyRequirementMap(value) {
88
+ if (typeof value != "object" || value === null) return;
89
+ const activity = value, requirements = activity.requirements;
90
+ typeof requirements != "object" || requirements === null || Array.isArray(requirements) || (activity.requirements = Object.entries(requirements).map(([name, query]) => ({
91
+ type: "groq",
92
+ name: name,
93
+ query: query
94
+ })));
95
+ }
96
+
97
+ function parseDefinitionSnapshot(instance) {
98
+ return parseDefinitionSnapshotValue(instance);
99
+ }
100
+
101
+ function parentRef(instance) {
102
+ return instance.ancestors.at(-1);
103
+ }
104
+
58
105
  function effectiveEditable(baseline, override) {
59
106
  if (baseline === void 0) return;
60
107
  if (override === void 0) return baseline;
@@ -131,7 +178,7 @@ function resolveEditTarget(args) {
131
178
  }
132
179
 
133
180
  function fieldWindowOpen(instance, site) {
134
- const terminal = invariants.terminalState(instance);
181
+ const terminal = terminalState(instance);
135
182
  if (terminal !== "in-flight") return {
136
183
  open: !1,
137
184
  detail: `instance ${terminal}`
@@ -198,7 +245,7 @@ function editDisabledReason(args) {
198
245
  }
199
246
 
200
247
  function instanceTerminalReason(instance) {
201
- const terminal = invariants.terminalState(instance);
248
+ const terminal = terminalState(instance);
202
249
  if (terminal === "aborted" && instance.abortedAt !== void 0) return {
203
250
  kind: "instance-aborted",
204
251
  abortedAt: instance.abortedAt
@@ -328,7 +375,7 @@ function instanceStartedData(args) {
328
375
  function instanceStartedDataFor(args) {
329
376
  return instanceStartedData({
330
377
  definition: {
331
- ...invariants.parseDefinitionSnapshot(args.instance),
378
+ ...parseDefinitionSnapshot(args.instance),
332
379
  ...args.instance.pinnedContentHash !== void 0 ? {
333
380
  contentHash: args.instance.pinnedContentHash
334
381
  } : {}
@@ -356,7 +403,7 @@ function stageTransitionedData(args) {
356
403
  }
357
404
 
358
405
  function openStage$1(instance) {
359
- const definition = invariants.parseDefinitionSnapshot(instance);
406
+ const definition = parseDefinitionSnapshot(instance);
360
407
  return {
361
408
  definition: definition,
362
409
  stage: definition.stages.find(s => s.name === instance.currentStage)
@@ -402,6 +449,313 @@ function fieldEditedData(args) {
402
449
  };
403
450
  }
404
451
 
452
+ const DATA_MODEL_VERSION = 7, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
453
+
454
+ class ReaderModelAcknowledgementError extends invariants.WorkflowError {
455
+ code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
456
+ expectedMinReaderModel;
457
+ engineMinReaderModel=DATA_MODEL_MIN_READER;
458
+ engineModelVersion=DATA_MODEL_VERSION;
459
+ documentationUrl=READER_MODEL_ROLLOUT_URL;
460
+ constructor(expectedMinReaderModel, context = "Deployment") {
461
+ const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
462
+ super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}.\nDo not change the acknowledgement yet: accepting ${DATA_MODEL_MIN_READER} authorizes this engine to write documents that older readers will refuse.\nUpgrade every Studio, CLI, MCP server, Function, and other runtime that reads engine-owned documents; verify that rollout in every environment sharing the workflow resource; then change the literal in deployment configuration and deploy the writer.\nRollout guide: ${READER_MODEL_ROLLOUT_URL}`),
463
+ this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
464
+ }
465
+ }
466
+
467
+ function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
468
+ if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
469
+ }
470
+
471
+ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
472
+ id: "governed-model-stamps",
473
+ introducedInModel: 1,
474
+ minReaderModel: 0,
475
+ documentTypes: Object.freeze([ "definition", "instance" ]),
476
+ compatibility: "additive",
477
+ applicability: "unconditional",
478
+ summary: "Definition and instance documents carry model provenance and reader-floor stamps."
479
+ }), Object.freeze({
480
+ id: "subject-field-kind",
481
+ introducedInModel: 2,
482
+ minReaderModel: 0,
483
+ documentTypes: Object.freeze([ "definition", "instance" ]),
484
+ compatibility: "additive",
485
+ applicability: "detectable",
486
+ summary: "A workflow-level subject field identifies the document a workflow is about."
487
+ }), Object.freeze({
488
+ id: "typed-scalar-choice-lists",
489
+ introducedInModel: 2,
490
+ minReaderModel: 2,
491
+ documentTypes: Object.freeze([ "definition", "instance" ]),
492
+ compatibility: "reader-floor",
493
+ applicability: "detectable",
494
+ summary: "Scalar fields may constrain writes to a persisted typed choice list."
495
+ }), Object.freeze({
496
+ id: "action-semantics",
497
+ introducedInModel: 2,
498
+ minReaderModel: 0,
499
+ documentTypes: Object.freeze([ "definition" ]),
500
+ compatibility: "additive",
501
+ applicability: "detectable",
502
+ summary: "Ordinary actions may carry advisory workflow semantics."
503
+ }), Object.freeze({
504
+ id: "inclusive-scalar-bounds",
505
+ introducedInModel: 2,
506
+ minReaderModel: 2,
507
+ documentTypes: Object.freeze([ "definition", "instance" ]),
508
+ compatibility: "reader-floor",
509
+ applicability: "detectable",
510
+ summary: "String, text, and number values may carry persisted inclusive bounds."
511
+ }), Object.freeze({
512
+ id: "progress-field-kind",
513
+ introducedInModel: 3,
514
+ minReaderModel: 0,
515
+ documentTypes: Object.freeze([ "definition", "instance" ]),
516
+ compatibility: "additive",
517
+ applicability: "detectable",
518
+ summary: "A progress field kind carries application-defined 0–100 completion."
519
+ }), Object.freeze({
520
+ id: "effect-claim-tokens",
521
+ introducedInModel: 3,
522
+ minReaderModel: 0,
523
+ documentTypes: Object.freeze([ "instance" ]),
524
+ compatibility: "additive",
525
+ applicability: "detectable",
526
+ summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
527
+ }), Object.freeze({
528
+ id: "classified-principal-ids",
529
+ introducedInModel: 4,
530
+ minReaderModel: 4,
531
+ documentTypes: Object.freeze([ "instance" ]),
532
+ compatibility: "reader-floor",
533
+ applicability: "unconditional",
534
+ summary: "Principal ids are namespace-classified: actor and assignee writes carry the account-global user id only, and readers resolve legacy project-scoped ids through the prefix classifier at the instance read funnel."
535
+ }), Object.freeze({
536
+ id: "readiness-requirements",
537
+ introducedInModel: 4,
538
+ minReaderModel: 4,
539
+ documentTypes: Object.freeze([ "definition" ]),
540
+ compatibility: "reader-floor",
541
+ applicability: "detectable",
542
+ summary: "Start and activity readiness use named polymorphic requirement arrays."
543
+ }), Object.freeze({
544
+ id: "due-date-field-kinds",
545
+ introducedInModel: 5,
546
+ minReaderModel: 0,
547
+ documentTypes: Object.freeze([ "definition", "instance" ]),
548
+ compatibility: "additive",
549
+ applicability: "detectable",
550
+ summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
551
+ }), Object.freeze({
552
+ id: "node-semantics",
553
+ introducedInModel: 6,
554
+ minReaderModel: 0,
555
+ documentTypes: Object.freeze([ "definition" ]),
556
+ compatibility: "additive",
557
+ applicability: "detectable",
558
+ summary: "Workflow, stage, activity, and action nodes may carry signal or custom advisory semantics."
559
+ }), Object.freeze({
560
+ id: "field-patch-ops",
561
+ introducedInModel: 6,
562
+ minReaderModel: 0,
563
+ documentTypes: Object.freeze([ "definition", "instance" ]),
564
+ compatibility: "additive",
565
+ applicability: "detectable",
566
+ summary: "Field ops may increment, decrement, or initialize a missing field value."
567
+ }), Object.freeze({
568
+ id: "attributes-condition-var",
569
+ introducedInModel: 7,
570
+ minReaderModel: 0,
571
+ documentTypes: Object.freeze([ "definition" ]),
572
+ compatibility: "additive",
573
+ applicability: "unconditional",
574
+ summary: "Caller-bound $attributes condition variable binds the acting token's org-level User Attributes (advisory; absent when unavailable)."
575
+ }) ]);
576
+
577
+ function recordOf(value) {
578
+ return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
579
+ }
580
+
581
+ function recordsAt(record, key) {
582
+ const value = record[key];
583
+ return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
584
+ }
585
+
586
+ function nestedFieldEntries(entries) {
587
+ return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
588
+ }
589
+
590
+ function parsedDefinitionSnapshot(root) {
591
+ if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
592
+ _id: typeof root._id == "string" ? root._id : "<unknown instance>",
593
+ definitionSnapshot: root.definitionSnapshot
594
+ }));
595
+ }
596
+
597
+ function persistedDefinitionTree(document) {
598
+ const root = recordOf(document);
599
+ if (root === void 0) return;
600
+ const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], {stages: stages, activities: activities, actions: actions} = definitionDescendants(roots);
601
+ return {
602
+ roots: roots,
603
+ stages: stages,
604
+ activities: activities,
605
+ actions: actions
606
+ };
607
+ }
608
+
609
+ function persistedFieldEntries(document) {
610
+ const tree = persistedDefinitionTree(document);
611
+ if (tree === void 0) return [];
612
+ const {roots: roots, stages: stages, activities: activities, actions: actions} = tree, effects = actions.flatMap(action => recordsAt(action, "effects"));
613
+ return nestedFieldEntries([ ...roots.flatMap(candidate => recordsAt(candidate, "fields")), ...stages.flatMap(stage => recordsAt(stage, "fields")), ...activities.flatMap(activity => recordsAt(activity, "fields")), ...actions.flatMap(action => recordsAt(action, "params")), ...effects.flatMap(effect => recordsAt(effect, "outputs")) ]);
614
+ }
615
+
616
+ function definitionDescendants(roots) {
617
+ const stages = roots.flatMap(root => recordsAt(root, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions"));
618
+ return {
619
+ stages: stages,
620
+ activities: activities,
621
+ actions: actions
622
+ };
623
+ }
624
+
625
+ function hasChoiceList(document) {
626
+ return persistedFieldEntries(document).some(entry => {
627
+ const options = recordOf(entry.options);
628
+ return options !== void 0 && Array.isArray(options.list);
629
+ });
630
+ }
631
+
632
+ function hasFieldKind(document, kind) {
633
+ return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
634
+ }
635
+
636
+ function definitionNodes(document) {
637
+ const root = recordOf(document);
638
+ if (root !== void 0) return {
639
+ root: root,
640
+ ...definitionDescendants([ root ])
641
+ };
642
+ }
643
+
644
+ function hasActionSemantics(document) {
645
+ return definitionNodes(document)?.actions.some(hasSemantics) ?? !1;
646
+ }
647
+
648
+ function hasNodeSemantics(document) {
649
+ const nodes = definitionNodes(document);
650
+ return nodes === void 0 ? !1 : [ nodes.root, ...nodes.stages, ...nodes.activities ].some(hasSemantics) ? !0 : nodes.actions.some(action => hasSemantics(action) && action.semantics.some(isNodeSemanticValue));
651
+ }
652
+
653
+ function isNodeSemanticValue(semantic) {
654
+ return typeof semantic == "string" && (semantic.startsWith("signal.") || semantic.startsWith("custom."));
655
+ }
656
+
657
+ function hasSemantics(node) {
658
+ return Array.isArray(node.semantics);
659
+ }
660
+
661
+ function hasPersistedOpType(document, types) {
662
+ const tree = persistedDefinitionTree(document);
663
+ return tree === void 0 ? !1 : tree.actions.flatMap(action => recordsAt(action, "ops")).some(op => typeof op.type == "string" && types.includes(op.type)) ? !0 : tree.roots.some(root => recordsAt(root, "history").some(entry => entry._type === "opApplied" && typeof entry.opType == "string" && types.includes(entry.opType)));
664
+ }
665
+
666
+ function hasScalarValidation(document) {
667
+ return persistedFieldEntries(document).some(entry => {
668
+ const validation = recordOf(entry.validation);
669
+ return typeof validation?.min == "number" || typeof validation?.max == "number";
670
+ });
671
+ }
672
+
673
+ function hasClaimTokens(document) {
674
+ const root = recordOf(document);
675
+ return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
676
+ const claim = recordOf(entry.claim);
677
+ return claim !== void 0 && typeof claim.claimToken == "string";
678
+ });
679
+ }
680
+
681
+ function hasReadinessRequirements(document) {
682
+ const root = recordOf(document);
683
+ return root === void 0 ? !1 : Array.isArray(recordOf(root.start)?.requirements) ? !0 : recordsAt(root, "stages").some(stage => recordsAt(stage, "activities").some(activity => Array.isArray(activity.requirements)));
684
+ }
685
+
686
+ const featureDetectors = {
687
+ "governed-model-stamps": () => !0,
688
+ "subject-field-kind": document => hasFieldKind(document, "subject"),
689
+ "typed-scalar-choice-lists": hasChoiceList,
690
+ "action-semantics": hasActionSemantics,
691
+ "inclusive-scalar-bounds": hasScalarValidation,
692
+ "progress-field-kind": document => hasFieldKind(document, "progress"),
693
+ "effect-claim-tokens": hasClaimTokens,
694
+ "classified-principal-ids": () => !0,
695
+ "readiness-requirements": hasReadinessRequirements,
696
+ "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime"),
697
+ "node-semantics": hasNodeSemantics,
698
+ "field-patch-ops": document => hasPersistedOpType(document, [ "field.inc", "field.dec", "field.setIfMissing" ]),
699
+ "attributes-condition-var": () => !0
700
+ };
701
+
702
+ function requiredModelFeatures(documentType, document) {
703
+ return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
704
+ }
705
+
706
+ function requiredReaderModel(documentType, document) {
707
+ return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
708
+ }
709
+
710
+ function modelStampFor(args) {
711
+ return {
712
+ modelVersion: DATA_MODEL_VERSION,
713
+ minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
714
+ };
715
+ }
716
+
717
+ function fieldTreeShape(value) {
718
+ if (Array.isArray(value)) return value.map(fieldTreeShape);
719
+ if (value === null) return "null";
720
+ if (typeof value == "object") {
721
+ const record = value;
722
+ return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
723
+ }
724
+ return typeof value;
725
+ }
726
+
727
+ function modelVersionOf(doc) {
728
+ const stamp = doc.modelVersion;
729
+ return typeof stamp == "number" ? stamp : 0;
730
+ }
731
+
732
+ function minReaderModelOf(doc) {
733
+ const floor = doc.minReaderModel;
734
+ return typeof floor == "number" ? floor : modelVersionOf(doc);
735
+ }
736
+
737
+ class ModelVersionAheadError extends invariants.WorkflowError {
738
+ documentId;
739
+ documentModelVersion;
740
+ requiredReaderModel;
741
+ engineModelVersion;
742
+ constructor(args) {
743
+ super("model-version-ahead", `Document "${args.documentId}" was written by engine data model ${args.documentModelVersion} and requires a reader at model ${args.requiredReaderModel} or newer; this engine reads up to model ${DATA_MODEL_VERSION}. Upgrade @sanity/workflow-engine to a version that understands it.`),
744
+ this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
745
+ this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
746
+ }
747
+ }
748
+
749
+ function assertReadableModel(doc) {
750
+ const documentReaderModel = minReaderModelOf(doc);
751
+ if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
752
+ documentId: doc._id,
753
+ documentModelVersion: modelVersionOf(doc),
754
+ requiredReaderModel: documentReaderModel
755
+ });
756
+ return doc;
757
+ }
758
+
405
759
  function effectSites(def) {
406
760
  const sites = [];
407
761
  for (const stage of def.stages ?? []) for (const activity of stage.activities ?? []) for (const action of activity.actions ?? []) for (const effect of action.effects ?? []) sites.push({
@@ -876,12 +1230,8 @@ function renderWorkflowRead(read, ctx) {
876
1230
  text: groqConditionDescribe.guillemets(title)
877
1231
  });
878
1232
  }
879
- if (read.variable === "can" && typeof read.path[0] == "string") return groqConditionDescribe.phrase("read.permission", {
880
- params: {
881
- permission: read.path[0]
882
- },
883
- text: `your ${read.path[0]} permission`
884
- });
1233
+ const keyed = keyedCallerRead(read);
1234
+ if (keyed !== void 0) return keyed;
885
1235
  if (read.variable === "actor" && read.path.length === 1 && read.path[0] === "id") return groqConditionDescribe.phrase("read.actor-id", {
886
1236
  params: {},
887
1237
  text: "your id"
@@ -903,6 +1253,24 @@ function renderWorkflowRead(read, ctx) {
903
1253
  });
904
1254
  }
905
1255
 
1256
+ function keyedCallerRead(read) {
1257
+ const key = read.path[0];
1258
+ if (typeof key == "string") {
1259
+ if (read.variable === "can") return groqConditionDescribe.phrase("read.permission", {
1260
+ params: {
1261
+ permission: key
1262
+ },
1263
+ text: `your ${key} permission`
1264
+ });
1265
+ if (read.variable === "attributes") return groqConditionDescribe.phrase("read.attribute", {
1266
+ params: {
1267
+ attribute: key
1268
+ },
1269
+ text: `your ${groqConditionDescribe.guillemets(key)} attribute`
1270
+ });
1271
+ }
1272
+ }
1273
+
906
1274
  function workflowRequirement(requirement, ctx) {
907
1275
  const {target: target} = requirement, clause = clauseVarRequirement(requirement);
908
1276
  if (clause !== void 0) return clause;
@@ -1803,12 +2171,16 @@ function derefBase(ref, snapshot) {
1803
2171
  };
1804
2172
  }
1805
2173
 
2174
+ function isRecord(value) {
2175
+ return typeof value == "object" && value !== null && !Array.isArray(value);
2176
+ }
2177
+
1806
2178
  function buildParams(args) {
1807
2179
  const {instance: instance, now: now, snapshot: snapshot, extra: extra} = args, currentActivities2 = findOpenStageEntry(instance)?.activities ?? [];
1808
2180
  return {
1809
2181
  self: invariants.selfGdr(instance),
1810
2182
  fields: renderedFields(instance.fields ?? [], snapshot),
1811
- parent: invariants.parentRef(instance)?.id ?? null,
2183
+ parent: parentRef(instance)?.id ?? null,
1812
2184
  ancestors: instance.ancestors.map(a => a.id),
1813
2185
  stage: instance.currentStage,
1814
2186
  now: now,
@@ -2273,6 +2645,12 @@ function isRevisionConflict(error) {
2273
2645
  return statusCode === 409 ? !0 : typeof message == "string" && message.includes("ifRevisionId check failed");
2274
2646
  }
2275
2647
 
2648
+ function isCreateIdCollision(error) {
2649
+ if (typeof error != "object" || error === null) return !1;
2650
+ const {message: message, responseBody: responseBody} = error;
2651
+ return typeof message == "string" && message.includes("already exists") && (message.includes("Document by ID") || message.includes("create() failed")) ? !0 : typeof responseBody == "string" && responseBody.includes("documentAlreadyExistsError");
2652
+ }
2653
+
2276
2654
  class ConcurrentEditFieldError extends invariants.WorkflowError {
2277
2655
  instanceId;
2278
2656
  target;
@@ -2325,7 +2703,7 @@ class CascadeLimitError extends invariants.WorkflowError {
2325
2703
  }
2326
2704
  }
2327
2705
 
2328
- const FIELD_OP_TYPES = [ "field.set", "field.unset", "field.append", "field.updateWhere", "field.removeWhere" ];
2706
+ const FIELD_OP_TYPES = [ "field.set", "field.setIfMissing", "field.unset", "field.append", "field.inc", "field.dec", "field.updateWhere", "field.removeWhere" ];
2329
2707
 
2330
2708
  function isFieldOp(summary) {
2331
2709
  return FIELD_OP_TYPES.includes(summary.opType);
@@ -2426,7 +2804,7 @@ async function runOps(args) {
2426
2804
  refSurface: refSurface,
2427
2805
  opsFromDefinition: opsFromDefinition
2428
2806
  });
2429
- summaries.push(summary), mutation.history.push(opAppliedEntry({
2807
+ summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
2430
2808
  origin: origin,
2431
2809
  summary: summary,
2432
2810
  stage: stage,
@@ -2437,6 +2815,10 @@ async function runOps(args) {
2437
2815
  return summaries;
2438
2816
  }
2439
2817
 
2818
+ function shouldRecordOpApplied(summary) {
2819
+ return summary.opType !== "field.setIfMissing" || summary.resolved !== void 0;
2820
+ }
2821
+
2440
2822
  function opAppliedEntry(args) {
2441
2823
  const {origin: origin, summary: summary, stage: stage, actor: actor, now: now} = args;
2442
2824
  return {
@@ -2508,12 +2890,19 @@ async function applyOp(op, ctx) {
2508
2890
  case "field.set":
2509
2891
  return applyFieldSet(op, ctx);
2510
2892
 
2893
+ case "field.setIfMissing":
2894
+ return applyFieldSetIfMissing(op, ctx);
2895
+
2511
2896
  case "field.unset":
2512
2897
  return applyFieldUnset(op, ctx);
2513
2898
 
2514
2899
  case "field.append":
2515
2900
  return applyFieldAppend(op, ctx);
2516
2901
 
2902
+ case "field.inc":
2903
+ case "field.dec":
2904
+ return applyFieldArithmetic(op, ctx);
2905
+
2517
2906
  case "field.updateWhere":
2518
2907
  return applyFieldUpdateWhere(op, ctx);
2519
2908
 
@@ -2552,6 +2941,78 @@ function applyFieldSet(op, ctx) {
2552
2941
  };
2553
2942
  }
2554
2943
 
2944
+ function applyFieldSetIfMissing(op, ctx) {
2945
+ const entry = locateEntry(ctx, op.target);
2946
+ return invariants.isAlwaysArrayFieldKind(entry._type) && rejectFieldOpTarget({
2947
+ entry: entry,
2948
+ op: op,
2949
+ issue: "is always array-valued — setIfMissing applies to nullable entries only; an empty array entry already holds []"
2950
+ }), entry.value !== null && entry.value !== void 0 ? {
2951
+ opType: op.type,
2952
+ target: op.target
2953
+ } : {
2954
+ ...applyFieldSet({
2955
+ ...op,
2956
+ type: "field.set"
2957
+ }, ctx),
2958
+ opType: op.type
2959
+ };
2960
+ }
2961
+
2962
+ function applyFieldArithmetic(op, ctx) {
2963
+ const entry = locateEntry(ctx, op.target);
2964
+ entry._type !== "number" && rejectFieldOpTarget({
2965
+ entry: entry,
2966
+ op: op,
2967
+ issue: `is a ${entry._type} entry — arithmetic ops target \`number\` entries only`
2968
+ }), typeof entry.value != "number" && rejectFieldOpTarget({
2969
+ entry: entry,
2970
+ op: op,
2971
+ issue: "has no numeric value — initialize it before applying arithmetic"
2972
+ });
2973
+ const resolvedDelta = op.value === void 0 ? 1 : resolveOpValue({
2974
+ src: op.value,
2975
+ ctx: ctx,
2976
+ target: {
2977
+ kind: "number"
2978
+ }
2979
+ });
2980
+ (typeof resolvedDelta != "number" || !Number.isFinite(resolvedDelta)) && rejectFieldOpTarget({
2981
+ entry: entry,
2982
+ op: op,
2983
+ issue: "value must resolve to a finite number"
2984
+ });
2985
+ const nextValue = entry.value + (op.type === "field.inc" ? resolvedDelta : -resolvedDelta);
2986
+ Number.isFinite(nextValue) || rejectFieldOpTarget({
2987
+ entry: entry,
2988
+ op: op,
2989
+ issue: "result must be a finite number"
2990
+ });
2991
+ const value = invariants.validateFieldValue({
2992
+ entryType: entry._type,
2993
+ entryName: entry.name,
2994
+ value: nextValue,
2995
+ ...entryShape(entry)
2996
+ });
2997
+ return setEntryValue(entry, value), {
2998
+ opType: op.type,
2999
+ target: op.target,
3000
+ resolved: {
3001
+ value: value
3002
+ }
3003
+ };
3004
+ }
3005
+
3006
+ function rejectFieldOpTarget(args) {
3007
+ const {entry: entry, op: op, issue: issue} = args;
3008
+ throw new invariants.FieldValueShapeError({
3009
+ entryType: entry._type,
3010
+ entryName: entry.name,
3011
+ mode: "value",
3012
+ issues: [ `${op.type} target ${op.target.scope}:"${op.target.field}" ${issue}` ]
3013
+ });
3014
+ }
3015
+
2555
3016
  function entryShape(entry) {
2556
3017
  return entry._type === "object" ? {
2557
3018
  fields: entry.fields
@@ -2587,15 +3048,10 @@ function appendItemSlot(entry) {
2587
3048
  };
2588
3049
  }
2589
3050
 
2590
- const EMPTY_BY_KIND = {
2591
- "doc.refs": [],
2592
- array: [],
2593
- assignees: []
2594
- };
2595
-
2596
3051
  function applyFieldUnset(op, ctx) {
2597
3052
  const entry = locateEntry(ctx, op.target);
2598
- return setEntryValue(entry, EMPTY_BY_KIND[entry._type] ?? null), {
3053
+ return setEntryValue(entry, invariants.isAlwaysArrayFieldKind(entry._type) ? [] : null),
3054
+ {
2599
3055
  opType: op.type,
2600
3056
  target: op.target
2601
3057
  };
@@ -2634,7 +3090,7 @@ function applyFieldAppend(op, ctx) {
2634
3090
  }
2635
3091
 
2636
3092
  function withRowKey(item) {
2637
- return typeof item == "object" && item !== null && !Array.isArray(item) && !("_key" in item) ? {
3093
+ return isRecord(item) && !("_key" in item) ? {
2638
3094
  _key: randomKey(),
2639
3095
  ...item
2640
3096
  } : item;
@@ -3333,6 +3789,14 @@ function latestDeployedDefinitions(rows) {
3333
3789
  return [ ...byName.values() ];
3334
3790
  }
3335
3791
 
3792
+ function findStageNode(args) {
3793
+ return args.definition?.stages.find(entry => entry.name === args.stageName);
3794
+ }
3795
+
3796
+ function findActivityNode(args) {
3797
+ return findStageNode(args)?.activities?.find(entry => entry.name === args.activityName);
3798
+ }
3799
+
3336
3800
  function liveChildrenField(instance) {
3337
3801
  const live = liveSubworkflows(instance).length;
3338
3802
  return live > 0 ? {
@@ -3421,8 +3885,29 @@ function noTransitionFiresCause(input) {
3421
3885
  };
3422
3886
  }
3423
3887
 
3888
+ function stuckFromDocumentState(input) {
3889
+ return failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input);
3890
+ }
3891
+
3892
+ function documentStuckCause(args) {
3893
+ const stage = findOpenStageEntry(args.instance);
3894
+ if (stage !== void 0) return stuckFromDocumentState({
3895
+ instance: args.instance,
3896
+ activities: stage.activities.map(entry => ({
3897
+ status: entry.status,
3898
+ activity: findActivityNode({
3899
+ activityName: entry.name,
3900
+ definition: args.definition,
3901
+ stageName: stage.name
3902
+ }) ?? {
3903
+ name: entry.name
3904
+ }
3905
+ }))
3906
+ });
3907
+ }
3908
+
3424
3909
  function diagnoseInstance(input) {
3425
- const {instance: instance} = input, terminal = invariants.terminalState(instance);
3910
+ const {instance: instance} = input, terminal = terminalState(instance);
3426
3911
  if (terminal === "aborted" && instance.abortedAt !== void 0) {
3427
3912
  const reason = abortReason(instance);
3428
3913
  return {
@@ -3439,7 +3924,7 @@ function diagnoseInstance(input) {
3439
3924
  at: instance.completedAt,
3440
3925
  ...liveChildrenField(instance)
3441
3926
  };
3442
- const cause = failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input) ?? noTransitionFiresCause(input);
3927
+ const cause = stuckFromDocumentState(input) ?? noTransitionFiresCause(input);
3443
3928
  return cause !== void 0 ? {
3444
3929
  state: "stuck",
3445
3930
  cause: cause
@@ -3576,7 +4061,7 @@ function liveSubworkflowRefs(instance) {
3576
4061
  }
3577
4062
 
3578
4063
  function readsRaw(ref) {
3579
- return ref.type === invariants.WORKFLOW_INSTANCE_TYPE || ref.type === "system.release";
4064
+ return ref.type === WORKFLOW_INSTANCE_TYPE || ref.type === "system.release";
3580
4065
  }
3581
4066
 
3582
4067
  const DEFAULT_CONTENT_PERSPECTIVE = "drafts";
@@ -3818,10 +4303,8 @@ function assertRequiredInputProvided({entryDefs: entryDefs, initialFields: initi
3818
4303
  });
3819
4304
  }
3820
4305
 
3821
- const ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([ "doc.refs", "array", "assignees" ]);
3822
-
3823
4306
  function defaultEntryValue(entryType) {
3824
- return ARRAY_FIELD_TYPES.has(entryType) ? [] : null;
4307
+ return invariants.isAlwaysArrayFieldKind(entryType) ? [] : null;
3825
4308
  }
3826
4309
 
3827
4310
  function resolveInputValue({entry: entry, initialFields: initialFields, defaultValue: defaultValue}) {
@@ -4350,7 +4833,7 @@ const TransitionVia = v__namespace.exactOptional(v__namespace.picklist([ "transi
4350
4833
  _type: v__namespace.pipe(v__namespace.string(), v__namespace.check(t => !knownHistoryTypes.has(t), "must not shadow a known history variant"))
4351
4834
  }), HistoryEntrySchema = v__namespace.union([ v__namespace.variant("_type", HISTORY_ARMS), UnknownHistoryEntry ]), WorkflowInstanceSchema = v__namespace.looseObject(invariants.tolerantEntries()({
4352
4835
  _id: NonEmpty,
4353
- _type: v__namespace.literal(invariants.WORKFLOW_INSTANCE_TYPE),
4836
+ _type: v__namespace.literal(WORKFLOW_INSTANCE_TYPE),
4354
4837
  _rev: v__namespace.string(),
4355
4838
  _createdAt: invariants.IsoTimestamp,
4356
4839
  _updatedAt: invariants.IsoTimestamp,
@@ -4383,7 +4866,7 @@ function parseInstanceDocument(doc) {
4383
4866
  return invariants.parsePersistedDoc({
4384
4867
  schema: WorkflowInstanceSchema,
4385
4868
  doc: doc,
4386
- docType: invariants.WORKFLOW_INSTANCE_TYPE
4869
+ docType: WORKFLOW_INSTANCE_TYPE
4387
4870
  });
4388
4871
  }
4389
4872
 
@@ -4422,7 +4905,9 @@ const SYNC_COMMIT = {
4422
4905
  effect: "workflow.effect",
4423
4906
  verifyDefinitions: "workflow.verify-definitions",
4424
4907
  accessResolveActor: "workflow.access.resolve-actor",
4425
- accessGrants: "workflow.access.grants"
4908
+ accessGrants: "workflow.access.grants",
4909
+ accessResolveOrg: "workflow.access.resolve-org",
4910
+ accessAttributes: "workflow.access.attributes"
4426
4911
  }, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
4427
4912
 
4428
4913
  function unwrapPatch(patch) {
@@ -4829,7 +5314,7 @@ async function getInstanceDocument(client, instanceId) {
4829
5314
  }
4830
5315
 
4831
5316
  function readInstanceDoc(doc) {
4832
- return parseInstanceDocument(invariants.assertReadableModel(doc));
5317
+ return parseInstanceDocument(assertReadableModel(doc));
4833
5318
  }
4834
5319
 
4835
5320
  async function reload({client: client, instanceId: instanceId, tag: tag}) {
@@ -4900,7 +5385,7 @@ function buildInstanceBase(args) {
4900
5385
  } : {}
4901
5386
  }, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
4902
5387
  _id: id,
4903
- _type: invariants.WORKFLOW_INSTANCE_TYPE,
5388
+ _type: WORKFLOW_INSTANCE_TYPE,
4904
5389
  _rev: "",
4905
5390
  _createdAt: now,
4906
5391
  _updatedAt: now,
@@ -4929,7 +5414,7 @@ function buildInstanceBase(args) {
4929
5414
  };
4930
5415
  return {
4931
5416
  ...body,
4932
- ...invariants.modelStampFor({
5417
+ ...modelStampFor({
4933
5418
  documentType: "instance",
4934
5419
  document: body
4935
5420
  })
@@ -5027,7 +5512,7 @@ async function readBatch(args) {
5027
5512
  }
5028
5513
 
5029
5514
  function validateRawDoc(doc, perspective) {
5030
- return perspective !== "raw" ? doc : doc._type === invariants.WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc) : invariants.assertReadableModel(doc);
5515
+ return perspective !== "raw" ? doc : doc._type === WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc) : assertReadableModel(doc);
5031
5516
  }
5032
5517
 
5033
5518
  function groupReads(reads) {
@@ -5110,7 +5595,7 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
5110
5595
  clientForGdr: options.clientForGdr,
5111
5596
  refSurface: options.refSurface,
5112
5597
  instance: instance,
5113
- definition: invariants.parseDefinitionSnapshot(instance),
5598
+ definition: parseDefinitionSnapshot(instance),
5114
5599
  ...options.actor !== void 0 ? {
5115
5600
  actor: options.actor
5116
5601
  } : {},
@@ -5390,10 +5875,6 @@ function userLoginProvider(user) {
5390
5875
  return user?.provider ?? user?.loginProvider;
5391
5876
  }
5392
5877
 
5393
- function isRecord(value) {
5394
- return typeof value == "object" && value !== null && !Array.isArray(value);
5395
- }
5396
-
5397
5878
  function optionalString(value) {
5398
5879
  return value === void 0 || typeof value == "string";
5399
5880
  }
@@ -5898,12 +6379,14 @@ function resolveGuard({guard: guard, instance: instance, stageName: stageName, n
5898
6379
 
5899
6380
  async function upsertGuard(args) {
5900
6381
  const {client: client, doc: doc, exists: exists} = args;
5901
- if (!exists) {
6382
+ if (!exists) try {
5902
6383
  await client.create(doc, {
5903
6384
  ...SYNC_COMMIT,
5904
6385
  tag: REQUEST_TAG.guardDeploy
5905
6386
  });
5906
6387
  return;
6388
+ } catch (error) {
6389
+ if (!isCreateIdCollision(error)) throw error;
5907
6390
  }
5908
6391
  const {_id: _id, _type: _type, _rev: _rev, _createdAt: _createdAt, _updatedAt: _updatedAt, ...body} = doc;
5909
6392
  await client.patch(doc._id).set(body).commit({
@@ -6249,7 +6732,7 @@ async function persistThenDeploy({ctx: ctx, mutation: mutation, deploy: deploy})
6249
6732
  committedRev: committed._rev,
6250
6733
  restore: instanceStateFields({
6251
6734
  ...ctx.instance,
6252
- minReaderModel: invariants.minReaderModelOf(ctx.instance)
6735
+ minReaderModel: minReaderModelOf(ctx.instance)
6253
6736
  }),
6254
6737
  unset: ctx.instance.completedAt === void 0 ? [ "completedAt" ] : [],
6255
6738
  reversible: !spawned,
@@ -6615,16 +7098,16 @@ async function resolveDefinitionRef({client: client, ref: ref, tag: tag}) {
6615
7098
  };
6616
7099
  wantsExplicit && (params.version = ref.version);
6617
7100
  const result = await client.fetch(definitionLookupGroq(wantsExplicit), params);
6618
- return result ? invariants.assertReadableModel(result) : null;
7101
+ return result ? assertReadableModel(result) : null;
6619
7102
  }
6620
7103
 
6621
7104
  async function prepareChildInstance(args) {
6622
7105
  const {client: client, parent: parent, definition: definition, initialFields: initialFields, context: context, actor: actor, now: now, refSurface: refSurface} = args, childTag = parent.tag, workflowResource = parent.workflowResource, childDocId = instanceDocId(childTag), childRef = {
6623
7106
  id: invariants.gdrFromResource(workflowResource, childDocId),
6624
- type: invariants.WORKFLOW_INSTANCE_TYPE
7107
+ type: WORKFLOW_INSTANCE_TYPE
6625
7108
  }, ancestors = [ ...parent.ancestors, {
6626
7109
  id: invariants.selfGdr(parent),
6627
- type: invariants.WORKFLOW_INSTANCE_TYPE
7110
+ type: WORKFLOW_INSTANCE_TYPE
6628
7111
  } ], inheritedPerspective = parent.perspective, fieldDiscards = [], childFields = await resolveDeclaredFields({
6629
7112
  entryDefs: definition.fields,
6630
7113
  initialFields: initialFields,
@@ -6929,53 +7412,460 @@ async function advisoryCan({instance: instance, identity: identity, grants: gran
6929
7412
  return can;
6930
7413
  }
6931
7414
 
6932
- function requirementDescriptor(requirement) {
7415
+ const DANGEROUS_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([ "__proto__", "constructor", "prototype" ]);
7416
+
7417
+ function attributeEntry(row) {
7418
+ if (!(!isRecord(row) || typeof row.key != "string" || row.key.length === 0) && !DANGEROUS_ATTRIBUTE_KEYS.has(row.key) && !(!("activeValue" in row) || row.activeValue === void 0)) return [ row.key, row.activeValue ];
7419
+ }
7420
+
7421
+ function normalizeUserAttributes(response) {
7422
+ if (!isRecord(response)) return;
7423
+ const rows = response.attributes;
7424
+ if (!Array.isArray(rows)) return;
7425
+ const out = {};
7426
+ for (const row of rows) {
7427
+ const entry = attributeEntry(row);
7428
+ entry !== void 0 && (out[entry[0]] = entry[1]);
7429
+ }
7430
+ return out;
7431
+ }
7432
+
7433
+ const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap, orgIdCache = /* @__PURE__ */ new WeakMap, attributesCache = /* @__PURE__ */ new WeakMap;
7434
+
7435
+ async function resolveAccess(taggedClient, args = {}) {
7436
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7437
+ if (requestFn === void 0) throw new invariants.ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({ uri: '/users/me' })`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
7438
+ const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
7439
+ client: client,
7440
+ requestFn: requestFn,
7441
+ resourcePath: args.grantsFromPath
7442
+ }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
7443
+ if (identity === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
6933
7444
  return {
6934
- name: requirement.name,
6935
- ...requirement.title !== void 0 ? {
6936
- title: requirement.title
7445
+ actor: identity.actor,
7446
+ ...identity.localPrincipalId !== void 0 ? {
7447
+ localPrincipalId: identity.localPrincipalId
6937
7448
  } : {},
6938
- ...requirement.description !== void 0 ? {
6939
- description: requirement.description
7449
+ ...grants !== void 0 ? {
7450
+ grants: grants
6940
7451
  } : {}
6941
7452
  };
6942
7453
  }
6943
7454
 
6944
- function subjectDenialLabels(denied) {
6945
- return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
7455
+ async function resolveUserAttributes(taggedClient) {
7456
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7457
+ if (requestFn !== void 0) return cachedAttributes({
7458
+ client: client,
7459
+ requestFn: requestFn
7460
+ });
6946
7461
  }
6947
7462
 
6948
- class ActionDisabledError extends invariants.WorkflowError {
6949
- reason;
6950
- activity;
6951
- action;
6952
- constructor(args) {
6953
- super("action-disabled", formatDisabledReason({
6954
- activity: args.activity,
6955
- action: args.action,
6956
- reason: args.reason
6957
- })), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
6958
- this.action = args.action;
6959
- }
7463
+ function cachedActor(client, requestFn) {
7464
+ const cached = actorCache.get(client);
7465
+ if (cached !== void 0) return cached;
7466
+ const pending = fetchActor(client, requestFn).catch(err => {
7467
+ throw actorCache.get(client) === pending && actorCache.delete(client), err;
7468
+ });
7469
+ return actorCache.set(client, pending), pending;
6960
7470
  }
6961
7471
 
6962
- class StartNotAllowedError extends invariants.WorkflowError {
6963
- definition;
6964
- unmetRequirements;
6965
- constructor(args) {
6966
- super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
6967
- this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
6968
- }
7472
+ function grantsForClientPath(taggedClient, resourcePath) {
7473
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7474
+ return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
7475
+ client: client,
7476
+ requestFn: requestFn,
7477
+ resourcePath: resourcePath
7478
+ });
6969
7479
  }
6970
7480
 
6971
- function actionRendering(action) {
6972
- const kind = action.disabledReason?.kind;
6973
- return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
7481
+ function lazyRequest(client) {
7482
+ return client.request === void 0 ? void 0 : opts => client.request(opts);
6974
7483
  }
6975
7484
 
6976
- const disabledReasonDetail = {
6977
- "filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
6978
- "cascade-fired": r => `the action is cascade-fired (when: ${JSON.stringify(r.when)}) — the engine fires it on truth; it cannot be invoked via fireAction`,
7485
+ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
7486
+ return cachedByKey({
7487
+ store: grantsCache,
7488
+ client: client,
7489
+ key: resourcePath,
7490
+ load: () => fetchGrantsCached(requestFn, resourcePath)
7491
+ });
7492
+ }
7493
+
7494
+ function cachedByKey(args) {
7495
+ let byKey = args.store.get(args.client);
7496
+ byKey === void 0 && (byKey = /* @__PURE__ */ new Map, args.store.set(args.client, byKey));
7497
+ const cached = byKey.get(args.key);
7498
+ if (cached !== void 0) return cached;
7499
+ const pending = args.evictOnRejection ? args.load().catch(err => {
7500
+ throw byKey.get(args.key) === pending && byKey.delete(args.key), err;
7501
+ }) : args.load();
7502
+ return byKey.set(args.key, pending), pending;
7503
+ }
7504
+
7505
+ async function fetchActor(client, requestFn) {
7506
+ const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = invariants.firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
7507
+ if (sessionId === void 0) return;
7508
+ const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
7509
+ client: client,
7510
+ sessionId: sessionId,
7511
+ resourceId: resourceId
7512
+ }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
7513
+ refuseProjectScopedActor({
7514
+ id: id,
7515
+ globalUser: globalUser,
7516
+ globalHostId: globalHostId,
7517
+ bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
7518
+ });
7519
+ const roleNames = roleNamesFor(resourceUser, globalUser);
7520
+ return {
7521
+ actor: {
7522
+ kind: "person",
7523
+ id: id,
7524
+ ...roleNames.length > 0 ? {
7525
+ roles: roleNames
7526
+ } : {}
7527
+ },
7528
+ ...resourceId !== void 0 && resourceId !== id ? {
7529
+ localPrincipalId: resourceId
7530
+ } : {}
7531
+ };
7532
+ }
7533
+
7534
+ function roleNamesFor(resourceUser, globalUser) {
7535
+ return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
7536
+ }
7537
+
7538
+ const NO_BRIDGE = {
7539
+ status: "not-applicable"
7540
+ };
7541
+
7542
+ function globalRouteReason(globalUser, globalHostId) {
7543
+ return "reason" in globalUser ? globalUser.reason : globalHostId === void 0 ? "no record" : `the global host answered with project-scoped principal "${globalHostId}"`;
7544
+ }
7545
+
7546
+ async function bridgeProjectPrincipal(args) {
7547
+ const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
7548
+ return invariants.classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project" ? {
7549
+ status: "unavailable",
7550
+ reason: "no project-scoped principal from the resource host to address the directory with"
7551
+ } : directoryGlobalId({
7552
+ client: client,
7553
+ principalId: resourceId
7554
+ });
7555
+ }
7556
+
7557
+ async function directoryGlobalId(args) {
7558
+ const {client: client, principalId: principalId} = args, projectId = projectIdOf(client);
7559
+ if (projectId === void 0) return {
7560
+ status: "unavailable",
7561
+ reason: "the client reports no projectId, so its user directory has no address"
7562
+ };
7563
+ const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
7564
+ if (lookup.status !== "resolved") return {
7565
+ status: "unavailable",
7566
+ reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
7567
+ ...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
7568
+ cause: lookup.cause
7569
+ } : {}
7570
+ };
7571
+ const globalId = invariants.directoryBridgeId(lookup.user.sanityUserId);
7572
+ return globalId === void 0 ? {
7573
+ status: "unavailable",
7574
+ reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
7575
+ } : {
7576
+ status: "resolved",
7577
+ globalId: globalId
7578
+ };
7579
+ }
7580
+
7581
+ function refuseProjectScopedActor(args) {
7582
+ const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
7583
+ if (invariants.classifyPrincipalId(id).namespace !== "project") return;
7584
+ const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
7585
+ bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
7586
+ const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
7587
+ throw new Error(`workflow: the caller's identity resolves to the project-scoped principal "${id}" and its account-global id could not be resolved. ${routes.join(" ")} The engine speaks account-global user ids only and never acts as a project-scoped principal.`, cause === void 0 ? void 0 : {
7588
+ cause: cause
7589
+ });
7590
+ }
7591
+
7592
+ function usableId(user) {
7593
+ if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
7594
+ }
7595
+
7596
+ async function fetchCurrentUser(requestFn, hostDescription) {
7597
+ try {
7598
+ return await requestFn({
7599
+ uri: "/users/me",
7600
+ tag: REQUEST_TAG.accessResolveActor
7601
+ });
7602
+ } catch (err) {
7603
+ throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({ uri: '/users/me' })\`. Check the token/connectivity.`, {
7604
+ cause: err
7605
+ });
7606
+ }
7607
+ }
7608
+
7609
+ async function fetchGlobalUser(client) {
7610
+ const sibling = globalHostRequestOf(client);
7611
+ if ("reason" in sibling) return {
7612
+ user: void 0,
7613
+ reason: sibling.reason,
7614
+ ...sibling.cause !== void 0 ? {
7615
+ cause: sibling.cause
7616
+ } : {}
7617
+ };
7618
+ try {
7619
+ const user = await sibling.request({
7620
+ uri: "/users/me",
7621
+ tag: REQUEST_TAG.accessResolveActor
7622
+ }), id = usableId(user);
7623
+ return sibling.requireGlobalPrincipal && id !== void 0 && invariants.classifyPrincipalId(id).namespace === "project" ? {
7624
+ user: void 0,
7625
+ reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
7626
+ } : {
7627
+ user: user
7628
+ };
7629
+ } catch (err) {
7630
+ return {
7631
+ user: void 0,
7632
+ reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
7633
+ cause: err
7634
+ };
7635
+ }
7636
+ }
7637
+
7638
+ function globalHostRequestOf(client) {
7639
+ if (typeof client.withConfig != "function") return {
7640
+ reason: "the client cannot reach the global API host (no withConfig)"
7641
+ };
7642
+ const hostResolution = resolveGlobalApiHost(client);
7643
+ try {
7644
+ const globalClient = client.withConfig({
7645
+ useProjectHostname: !1,
7646
+ apiVersion: ENGINE_API_VERSION,
7647
+ ...hostResolution.apiHost === void 0 ? {} : {
7648
+ apiHost: hostResolution.apiHost
7649
+ }
7650
+ }), request = lazyRequest(globalClient);
7651
+ return request === void 0 ? {
7652
+ reason: "the global-host sibling client cannot issue requests"
7653
+ } : {
7654
+ request: request,
7655
+ requireGlobalPrincipal: hostResolution.requireGlobalPrincipal
7656
+ };
7657
+ } catch (err) {
7658
+ return {
7659
+ reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
7660
+ cause: err
7661
+ };
7662
+ }
7663
+ }
7664
+
7665
+ function resolveGlobalApiHost(client) {
7666
+ if (typeof client.config != "function") return {
7667
+ requireGlobalPrincipal: !1
7668
+ };
7669
+ const apiHost = client.config().apiHost;
7670
+ if (apiHost === void 0) return {
7671
+ requireGlobalPrincipal: !1
7672
+ };
7673
+ let parsed;
7674
+ try {
7675
+ parsed = new URL(apiHost);
7676
+ } catch {
7677
+ return {
7678
+ requireGlobalPrincipal: !0
7679
+ };
7680
+ }
7681
+ if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
7682
+ requireGlobalPrincipal: !1
7683
+ };
7684
+ const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
7685
+ return match === null ? {
7686
+ requireGlobalPrincipal: !0
7687
+ } : (parsed.hostname = `api.sanity.${match[1]}`, {
7688
+ apiHost: parsed.origin,
7689
+ requireGlobalPrincipal: !0
7690
+ });
7691
+ }
7692
+
7693
+ async function fetchGrantsCached(requestFn, resourcePath) {
7694
+ try {
7695
+ return await fetchGrants({
7696
+ client: {
7697
+ request: requestFn
7698
+ },
7699
+ resourcePath: resourcePath
7700
+ });
7701
+ } catch (err) {
7702
+ console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
7703
+ return;
7704
+ }
7705
+ }
7706
+
7707
+ function projectIdOf(client) {
7708
+ if (typeof client.config != "function") return;
7709
+ const projectId = client.config().projectId;
7710
+ return typeof projectId == "string" && projectId.length > 0 ? projectId : void 0;
7711
+ }
7712
+
7713
+ function cachedAttributes(args) {
7714
+ const projectId = projectIdOf(args.client);
7715
+ return projectId === void 0 ? Promise.resolve(void 0) : resolveOrganizationId({
7716
+ client: args.client,
7717
+ requestFn: args.requestFn,
7718
+ projectId: projectId
7719
+ }).then(orgId => {
7720
+ if (orgId !== void 0) return cachedByKey({
7721
+ store: attributesCache,
7722
+ client: args.client,
7723
+ key: orgId,
7724
+ evictOnRejection: !0,
7725
+ load: () => fetchAttributesCached({
7726
+ client: args.client,
7727
+ orgId: orgId
7728
+ })
7729
+ });
7730
+ });
7731
+ }
7732
+
7733
+ async function resolveOrganizationId(args) {
7734
+ const {client: client, requestFn: requestFn, projectId: projectId} = args;
7735
+ return cachedByKey({
7736
+ store: orgIdCache,
7737
+ client: client,
7738
+ key: projectId,
7739
+ evictOnRejection: !0,
7740
+ load: async () => {
7741
+ try {
7742
+ const project = await requestFn({
7743
+ uri: `/projects/${encodeURIComponent(projectId)}`,
7744
+ tag: REQUEST_TAG.accessResolveOrg
7745
+ });
7746
+ if (!isRecord(project)) return;
7747
+ const orgId = project.organizationId;
7748
+ return typeof orgId == "string" && orgId.length > 0 ? orgId : void 0;
7749
+ } catch (err) {
7750
+ const status = httpStatusOf(err);
7751
+ if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
7752
+ throw new Error(`workflow: failed to resolve organizationId for project "${projectId}"; advisory $attributes cannot be bound. Original error: ${invariants.errorMessage(err)}`, {
7753
+ cause: err
7754
+ });
7755
+ }
7756
+ }
7757
+ });
7758
+ }
7759
+
7760
+ const ATTRIBUTES_FETCH_LIMIT = 100, EXPECTED_ATTRIBUTES_ABSENCE = /* @__PURE__ */ new Set([ 401, 402, 403, 404 ]);
7761
+
7762
+ function httpStatusOf(err) {
7763
+ if (!isRecord(err)) return;
7764
+ const status = err.statusCode;
7765
+ return typeof status == "number" ? status : void 0;
7766
+ }
7767
+
7768
+ async function fetchAttributesCached(args) {
7769
+ const {client: client, orgId: orgId} = args, sibling = globalHostRequestOf(client);
7770
+ if ("reason" in sibling) {
7771
+ console.warn(`workflow: skipped org attributes fetch (${sibling.reason}); advisory $attributes stays undefined (conditions referencing it fail closed).`);
7772
+ return;
7773
+ }
7774
+ try {
7775
+ const response = await sibling.request({
7776
+ uri: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
7777
+ tag: REQUEST_TAG.accessAttributes
7778
+ }), envelope = isRecord(response) ? response : void 0;
7779
+ if (envelope?.hasMore === !0) {
7780
+ const page = Array.isArray(envelope.attributes) ? envelope.attributes : [];
7781
+ console.warn(`workflow: org attributes for organization "${orgId}" report hasMore=true (bound ${page.length} of the requested limit ${ATTRIBUTES_FETCH_LIMIT}); advisory $attributes may be incomplete — the engine fetches no further pages. Conditions that read missing keys fail closed.`);
7782
+ }
7783
+ const normalized = normalizeUserAttributes(response);
7784
+ return normalized === void 0 && console.warn(`workflow: org attributes response for organization "${orgId}" was unusable; advisory $attributes stays undefined (conditions referencing it fail closed).`),
7785
+ normalized;
7786
+ } catch (err) {
7787
+ const status = httpStatusOf(err);
7788
+ if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
7789
+ throw new Error(`workflow: failed to fetch org attributes for organization "${orgId}". Original error: ${invariants.errorMessage(err)}`, {
7790
+ cause: err
7791
+ });
7792
+ }
7793
+ }
7794
+
7795
+ function callerBoundVars(args) {
7796
+ const vars = {
7797
+ ...args.can !== void 0 ? {
7798
+ can: args.can
7799
+ } : {},
7800
+ ...args.attributes !== void 0 ? {
7801
+ attributes: args.attributes
7802
+ } : {}
7803
+ };
7804
+ return Object.keys(vars).length > 0 ? vars : void 0;
7805
+ }
7806
+
7807
+ async function callerBoundVarsForCall(args) {
7808
+ const can = await advisoryCanForCall({
7809
+ instance: args.instance,
7810
+ options: args.options
7811
+ }), attributes = args.options?.attributes !== void 0 ? args.options.attributes : await resolveUserAttributes(args.client);
7812
+ return callerBoundVars({
7813
+ ...can !== void 0 ? {
7814
+ can: can
7815
+ } : {},
7816
+ ...attributes !== void 0 ? {
7817
+ attributes: attributes
7818
+ } : {}
7819
+ });
7820
+ }
7821
+
7822
+ function requirementDescriptor(requirement) {
7823
+ return {
7824
+ name: requirement.name,
7825
+ ...requirement.title !== void 0 ? {
7826
+ title: requirement.title
7827
+ } : {},
7828
+ ...requirement.description !== void 0 ? {
7829
+ description: requirement.description
7830
+ } : {}
7831
+ };
7832
+ }
7833
+
7834
+ function subjectDenialLabels(denied) {
7835
+ return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
7836
+ }
7837
+
7838
+ class ActionDisabledError extends invariants.WorkflowError {
7839
+ reason;
7840
+ activity;
7841
+ action;
7842
+ constructor(args) {
7843
+ super("action-disabled", formatDisabledReason({
7844
+ activity: args.activity,
7845
+ action: args.action,
7846
+ reason: args.reason
7847
+ })), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
7848
+ this.action = args.action;
7849
+ }
7850
+ }
7851
+
7852
+ class StartNotAllowedError extends invariants.WorkflowError {
7853
+ definition;
7854
+ unmetRequirements;
7855
+ constructor(args) {
7856
+ super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
7857
+ this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
7858
+ }
7859
+ }
7860
+
7861
+ function actionRendering(action) {
7862
+ const kind = action.disabledReason?.kind;
7863
+ return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
7864
+ }
7865
+
7866
+ const disabledReasonDetail = {
7867
+ "filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
7868
+ "cascade-fired": r => `the action is cascade-fired (when: ${JSON.stringify(r.when)}) — the engine fires it on truth; it cannot be invoked via fireAction`,
6979
7869
  "activity-not-active": r => `activity status is "${r.status}"`,
6980
7870
  "stage-terminal": r => `stage "${r.stage}" is terminal`,
6981
7871
  "instance-completed": r => `instance completed at ${r.completedAt}`,
@@ -7049,7 +7939,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7049
7939
  }
7050
7940
  });
7051
7941
  if (action.filter !== void 0) {
7052
- const can = await advisoryCanForCall({
7942
+ const vars = await callerBoundVarsForCall({
7943
+ client: ctx.client,
7053
7944
  instance: ctx.instance,
7054
7945
  options: options
7055
7946
  });
@@ -7061,10 +7952,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7061
7952
  ...actor !== void 0 ? {
7062
7953
  actor: actor
7063
7954
  } : {},
7064
- ...can !== void 0 ? {
7065
- vars: {
7066
- can: can
7067
- }
7955
+ ...vars !== void 0 ? {
7956
+ vars: vars
7068
7957
  } : {}
7069
7958
  }
7070
7959
  })) throw new ActionDisabledError({
@@ -7408,7 +8297,7 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
7408
8297
  }) : await buildEngineContext({
7409
8298
  client: client,
7410
8299
  instance: instance,
7411
- definition: invariants.parseDefinitionSnapshot(instance),
8300
+ definition: parseDefinitionSnapshot(instance),
7412
8301
  ...contextOptions
7413
8302
  });
7414
8303
  if (isTerminal(ctx)) return {
@@ -7589,7 +8478,7 @@ async function loadInstancesById(client, ids) {
7589
8478
  const children = await client.fetch("*[_id in $ids]", {
7590
8479
  ids: ids
7591
8480
  });
7592
- return new Map(children.filter(child => child._type === invariants.WORKFLOW_INSTANCE_TYPE).map(child => {
8481
+ return new Map(children.filter(child => child._type === WORKFLOW_INSTANCE_TYPE).map(child => {
7593
8482
  const instance = readInstanceDoc(child);
7594
8483
  return [ instance._id, instance ];
7595
8484
  }));
@@ -7649,10 +8538,10 @@ async function propagateToAncestors(args) {
7649
8538
  async function loadPropagationPair({client: client, instanceId: instanceId, instance: instance}) {
7650
8539
  const child = instance ?? await getInstanceDocument(client, instanceId);
7651
8540
  if (!child) return;
7652
- const parentGdr = invariants.parentRef(child);
8541
+ const parentGdr = parentRef(child);
7653
8542
  if (parentGdr === void 0) return;
7654
8543
  const parentDoc = await client.getDocument(invariants.toBareId(parentGdr.id));
7655
- if (!(!parentDoc || parentDoc._type !== invariants.WORKFLOW_INSTANCE_TYPE)) return {
8544
+ if (!(!parentDoc || parentDoc._type !== WORKFLOW_INSTANCE_TYPE)) return {
7656
8545
  child: child,
7657
8546
  parent: readInstanceDoc(parentDoc)
7658
8547
  };
@@ -7679,7 +8568,7 @@ async function buildCascadeStepContext(args, instance) {
7679
8568
  clientForGdr: args.clientForGdr,
7680
8569
  refSurface: args.refSurface,
7681
8570
  instance: instance,
7682
- definition: invariants.parseDefinitionSnapshot(instance),
8571
+ definition: parseDefinitionSnapshot(instance),
7683
8572
  ...args.clock ? {
7684
8573
  clock: args.clock
7685
8574
  } : {},
@@ -7730,7 +8619,7 @@ function stampSpawnBatch({mutation: mutation, parent: parent, children: children
7730
8619
  function requireSpawnBatchChild({parent: parent, children: children, childId: childId}) {
7731
8620
  const child = children.get(childId);
7732
8621
  if (child === void 0) throw new Error(`Spawn batch child ${childId} disappeared`);
7733
- const expectedParent = invariants.parentRef(child);
8622
+ const expectedParent = parentRef(child);
7734
8623
  if (expectedParent === void 0 || invariants.toBareId(expectedParent.id) !== parent._id) throw new Error(`Spawn batch child ${childId} does not belong to parent ${parent._id}`);
7735
8624
  return child;
7736
8625
  }
@@ -7753,7 +8642,7 @@ async function recordOrphanedPropagation({ctx: ctx, mutation: mutation, child: c
7753
8642
  at: ctx.now,
7754
8643
  instanceRef: {
7755
8644
  id: childUri,
7756
- type: invariants.WORKFLOW_INSTANCE_TYPE
8645
+ type: WORKFLOW_INSTANCE_TYPE
7757
8646
  },
7758
8647
  detail: `Instance "${child._id}" names this instance as its parent but no subworkflow-registry row matches it, so its state cannot drive any gate here.`
7759
8648
  }), await persist(ctx, mutation));
@@ -7761,7 +8650,7 @@ async function recordOrphanedPropagation({ctx: ctx, mutation: mutation, child: c
7761
8650
 
7762
8651
  function startMutation(instance) {
7763
8652
  return {
7764
- minReaderModel: invariants.minReaderModelOf(instance),
8653
+ minReaderModel: minReaderModelOf(instance),
7765
8654
  currentStage: instance.currentStage,
7766
8655
  fields: (instance.fields ?? []).map(s => ({
7767
8656
  ...s
@@ -7828,7 +8717,7 @@ function instanceStateFields(src) {
7828
8717
  } : {}
7829
8718
  };
7830
8719
  return {
7831
- ...invariants.modelStampFor({
8720
+ ...modelStampFor({
7832
8721
  documentType: "instance",
7833
8722
  document: state,
7834
8723
  storedMinReaderModel: src.minReaderModel
@@ -8307,352 +9196,109 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
8307
9196
  });
8308
9197
  const pending = requirePendingEffect(ctx.instance, effectKey), reason = staleClaimReason({
8309
9198
  pending: pending,
8310
- claimToken: claimToken,
8311
- now: ctx.now
8312
- });
8313
- if (reason !== void 0) throw new StaleEffectClaimError({
8314
- instanceId: ctx.instance._id,
8315
- effectKey: effectKey,
8316
- reason: reason
8317
- });
8318
- const validatedOps = validateEffectOps(ops, pending.name);
8319
- if (validatedOps.length === 0) throw new EffectOpsInvalidError({
8320
- effect: pending.name,
8321
- issues: [ "a mid-dispatch report must carry at least one field op — there is nothing to commit" ]
8322
- });
8323
- const mutation = startMutation(ctx.instance);
8324
- return recordProcessedRequest({
8325
- mutation: mutation,
8326
- record: requestRecord,
8327
- now: ctx.now
8328
- }), renewClaimLease({
8329
- mutation: mutation,
8330
- effectKey: effectKey,
8331
- now: ctx.now,
8332
- leaseMs: leaseMs
8333
- }), await runOps({
8334
- ops: validatedOps,
8335
- mutation: mutation,
8336
- stage: ctx.instance.currentStage,
8337
- origin: {
8338
- effect: pending.name
8339
- },
8340
- params: pending.params,
8341
- actor: ctx.actor,
8342
- self: invariants.selfGdr(ctx.instance),
8343
- now: ctx.now,
8344
- snapshot: ctx.snapshot,
8345
- refSurface: ctx.refSurface
8346
- }), await persistThenMaybeRefresh({
8347
- ctx: ctx,
8348
- mutation: mutation,
8349
- stageName: ctx.instance.currentStage,
8350
- didChangeState: !0
8351
- }), {
8352
- effectKey: effectKey,
8353
- effect: pending.name
8354
- };
8355
- }
8356
-
8357
- const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8358
-
8359
- function isResetActivityTarget(value) {
8360
- return RESET_ACTIVITY_TARGETS.includes(value);
8361
- }
8362
-
8363
- async function resetActivity(args) {
8364
- const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8365
- client: client,
8366
- instanceId: instanceId,
8367
- options: options
8368
- });
8369
- return commitResetActivity({
8370
- ctx: ctx,
8371
- activity: activity,
8372
- to: to,
8373
- requestRecord: requestRecord,
8374
- actor: options?.actor
8375
- });
8376
- }
8377
-
8378
- async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
8379
- if (assertRequestUnprocessed({
8380
- instance: ctx.instance,
8381
- record: requestRecord,
8382
- now: ctx.now
8383
- }), isTerminal(ctx)) return {
8384
- fired: !1
8385
- };
8386
- const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
8387
- if (openStage2 === void 0 || entry === void 0) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
8388
- const from = entry.status;
8389
- if (from === to) return {
8390
- fired: !1
8391
- };
8392
- if (!invariants.isTerminalActivityStatus(from)) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is "${from}", not a terminal status — a reset only recovers a resolved (typically failed) activity. Use setStage to force past a live stage.`);
8393
- return recordProcessedRequest({
8394
- mutation: mutation,
8395
- record: requestRecord,
8396
- now: ctx.now
8397
- }), applyActivityStatusChange({
8398
- entry: entry,
8399
- history: mutation.history,
8400
- stage: openStage2.name,
8401
- to: to,
8402
- at: ctx.now,
8403
- ...actor !== void 0 ? {
8404
- actor: actor
8405
- } : {}
8406
- }), await persist(ctx, mutation), {
8407
- fired: !0,
8408
- stage: openStage2.name,
8409
- activity: activity,
8410
- from: from,
8411
- to: to
8412
- };
8413
- }
8414
-
8415
- const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
8416
-
8417
- async function resolveAccess(taggedClient, args = {}) {
8418
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8419
- if (requestFn === void 0) throw new invariants.ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({ uri: '/users/me' })`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
8420
- const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
8421
- client: client,
8422
- requestFn: requestFn,
8423
- resourcePath: args.grantsFromPath
8424
- }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
8425
- if (identity === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
8426
- return {
8427
- actor: identity.actor,
8428
- ...identity.localPrincipalId !== void 0 ? {
8429
- localPrincipalId: identity.localPrincipalId
8430
- } : {},
8431
- ...grants !== void 0 ? {
8432
- grants: grants
8433
- } : {}
8434
- };
8435
- }
8436
-
8437
- function cachedActor(client, requestFn) {
8438
- const cached = actorCache.get(client);
8439
- if (cached !== void 0) return cached;
8440
- const pending = fetchActor(client, requestFn).catch(err => {
8441
- throw actorCache.get(client) === pending && actorCache.delete(client), err;
8442
- });
8443
- return actorCache.set(client, pending), pending;
8444
- }
8445
-
8446
- function grantsForClientPath(taggedClient, resourcePath) {
8447
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8448
- return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
8449
- client: client,
8450
- requestFn: requestFn,
8451
- resourcePath: resourcePath
8452
- });
8453
- }
8454
-
8455
- function lazyRequest(client) {
8456
- return client.request === void 0 ? void 0 : opts => client.request(opts);
8457
- }
8458
-
8459
- function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
8460
- let byPath = grantsCache.get(client);
8461
- byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
8462
- let cached = byPath.get(resourcePath);
8463
- return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
8464
- byPath.set(resourcePath, cached)), cached;
8465
- }
8466
-
8467
- async function fetchActor(client, requestFn) {
8468
- const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = invariants.firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
8469
- if (sessionId === void 0) return;
8470
- const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
8471
- client: client,
8472
- sessionId: sessionId,
8473
- resourceId: resourceId
8474
- }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
8475
- refuseProjectScopedActor({
8476
- id: id,
8477
- globalUser: globalUser,
8478
- globalHostId: globalHostId,
8479
- bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
8480
- });
8481
- const roleNames = roleNamesFor(resourceUser, globalUser);
8482
- return {
8483
- actor: {
8484
- kind: "person",
8485
- id: id,
8486
- ...roleNames.length > 0 ? {
8487
- roles: roleNames
8488
- } : {}
8489
- },
8490
- ...resourceId !== void 0 && resourceId !== id ? {
8491
- localPrincipalId: resourceId
8492
- } : {}
8493
- };
8494
- }
8495
-
8496
- function roleNamesFor(resourceUser, globalUser) {
8497
- return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8498
- }
8499
-
8500
- const NO_BRIDGE = {
8501
- status: "not-applicable"
8502
- };
8503
-
8504
- function globalRouteReason(globalUser, globalHostId) {
8505
- return "reason" in globalUser ? globalUser.reason : globalHostId === void 0 ? "no record" : `the global host answered with project-scoped principal "${globalHostId}"`;
8506
- }
8507
-
8508
- async function bridgeProjectPrincipal(args) {
8509
- const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
8510
- return invariants.classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project" ? {
8511
- status: "unavailable",
8512
- reason: "no project-scoped principal from the resource host to address the directory with"
8513
- } : directoryGlobalId({
8514
- client: client,
8515
- principalId: resourceId
8516
- });
8517
- }
8518
-
8519
- async function directoryGlobalId(args) {
8520
- const {client: client, principalId: principalId} = args, projectId = typeof client.config == "function" ? client.config().projectId : void 0;
8521
- if (projectId === void 0) return {
8522
- status: "unavailable",
8523
- reason: "the client reports no projectId, so its user directory has no address"
8524
- };
8525
- const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
8526
- if (lookup.status !== "resolved") return {
8527
- status: "unavailable",
8528
- reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
8529
- ...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
8530
- cause: lookup.cause
8531
- } : {}
8532
- };
8533
- const globalId = invariants.directoryBridgeId(lookup.user.sanityUserId);
8534
- return globalId === void 0 ? {
8535
- status: "unavailable",
8536
- reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
8537
- } : {
8538
- status: "resolved",
8539
- globalId: globalId
8540
- };
8541
- }
8542
-
8543
- function refuseProjectScopedActor(args) {
8544
- const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
8545
- if (invariants.classifyPrincipalId(id).namespace !== "project") return;
8546
- const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
8547
- bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
8548
- const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
8549
- throw new Error(`workflow: the caller's identity resolves to the project-scoped principal "${id}" and its account-global id could not be resolved. ${routes.join(" ")} The engine speaks account-global user ids only and never acts as a project-scoped principal.`, cause === void 0 ? void 0 : {
8550
- cause: cause
9199
+ claimToken: claimToken,
9200
+ now: ctx.now
9201
+ });
9202
+ if (reason !== void 0) throw new StaleEffectClaimError({
9203
+ instanceId: ctx.instance._id,
9204
+ effectKey: effectKey,
9205
+ reason: reason
9206
+ });
9207
+ const validatedOps = validateEffectOps(ops, pending.name);
9208
+ if (validatedOps.length === 0) throw new EffectOpsInvalidError({
9209
+ effect: pending.name,
9210
+ issues: [ "a mid-dispatch report must carry at least one field op — there is nothing to commit" ]
8551
9211
  });
9212
+ const mutation = startMutation(ctx.instance);
9213
+ return recordProcessedRequest({
9214
+ mutation: mutation,
9215
+ record: requestRecord,
9216
+ now: ctx.now
9217
+ }), renewClaimLease({
9218
+ mutation: mutation,
9219
+ effectKey: effectKey,
9220
+ now: ctx.now,
9221
+ leaseMs: leaseMs
9222
+ }), await runOps({
9223
+ ops: validatedOps,
9224
+ mutation: mutation,
9225
+ stage: ctx.instance.currentStage,
9226
+ origin: {
9227
+ effect: pending.name
9228
+ },
9229
+ params: pending.params,
9230
+ actor: ctx.actor,
9231
+ self: invariants.selfGdr(ctx.instance),
9232
+ now: ctx.now,
9233
+ snapshot: ctx.snapshot,
9234
+ refSurface: ctx.refSurface
9235
+ }), await persistThenMaybeRefresh({
9236
+ ctx: ctx,
9237
+ mutation: mutation,
9238
+ stageName: ctx.instance.currentStage,
9239
+ didChangeState: !0
9240
+ }), {
9241
+ effectKey: effectKey,
9242
+ effect: pending.name
9243
+ };
8552
9244
  }
8553
9245
 
8554
- function usableId(user) {
8555
- if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
8556
- }
9246
+ const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8557
9247
 
8558
- async function fetchCurrentUser(requestFn, hostDescription) {
8559
- try {
8560
- return await requestFn({
8561
- uri: "/users/me",
8562
- tag: REQUEST_TAG.accessResolveActor
8563
- });
8564
- } catch (err) {
8565
- throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({ uri: '/users/me' })\`. Check the token/connectivity.`, {
8566
- cause: err
8567
- });
8568
- }
9248
+ function isResetActivityTarget(value) {
9249
+ return RESET_ACTIVITY_TARGETS.includes(value);
8569
9250
  }
8570
9251
 
8571
- async function fetchGlobalUser(client) {
8572
- if (typeof client.withConfig != "function") return {
8573
- user: void 0,
8574
- reason: "the client cannot reach the global API host (no withConfig)"
8575
- };
8576
- let globalRequest, globalClient;
8577
- const hostResolution = resolveGlobalApiHost(client);
8578
- try {
8579
- globalClient = client.withConfig({
8580
- useProjectHostname: !1,
8581
- ...hostResolution.apiHost === void 0 ? {} : {
8582
- apiHost: hostResolution.apiHost
8583
- }
8584
- }), globalRequest = lazyRequest(globalClient);
8585
- } catch (err) {
8586
- return {
8587
- user: void 0,
8588
- reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
8589
- cause: err
8590
- };
8591
- }
8592
- if (globalRequest === void 0) return {
8593
- user: void 0,
8594
- reason: "the global-host sibling client cannot issue requests"
8595
- };
8596
- try {
8597
- const user = await globalRequest({
8598
- uri: "/users/me",
8599
- tag: REQUEST_TAG.accessResolveActor
8600
- }), id = usableId(user);
8601
- return hostResolution.requireGlobalPrincipal && id !== void 0 && invariants.classifyPrincipalId(id).namespace === "project" ? {
8602
- user: void 0,
8603
- reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
8604
- } : {
8605
- user: user
8606
- };
8607
- } catch (err) {
8608
- return {
8609
- user: void 0,
8610
- reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
8611
- cause: err
8612
- };
8613
- }
9252
+ async function resetActivity(args) {
9253
+ const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
9254
+ client: client,
9255
+ instanceId: instanceId,
9256
+ options: options
9257
+ });
9258
+ return commitResetActivity({
9259
+ ctx: ctx,
9260
+ activity: activity,
9261
+ to: to,
9262
+ requestRecord: requestRecord,
9263
+ actor: options?.actor
9264
+ });
8614
9265
  }
8615
9266
 
8616
- function resolveGlobalApiHost(client) {
8617
- if (typeof client.config != "function") return {
8618
- requireGlobalPrincipal: !1
9267
+ async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
9268
+ if (assertRequestUnprocessed({
9269
+ instance: ctx.instance,
9270
+ record: requestRecord,
9271
+ now: ctx.now
9272
+ }), isTerminal(ctx)) return {
9273
+ fired: !1
8619
9274
  };
8620
- const apiHost = client.config().apiHost;
8621
- if (apiHost === void 0) return {
8622
- requireGlobalPrincipal: !1
9275
+ const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
9276
+ if (openStage2 === void 0 || entry === void 0) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
9277
+ const from = entry.status;
9278
+ if (from === to) return {
9279
+ fired: !1
8623
9280
  };
8624
- let parsed;
8625
- try {
8626
- parsed = new URL(apiHost);
8627
- } catch {
8628
- return {
8629
- requireGlobalPrincipal: !0
8630
- };
8631
- }
8632
- if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
8633
- requireGlobalPrincipal: !1
9281
+ if (!invariants.isTerminalActivityStatus(from)) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is "${from}", not a terminal status — a reset only recovers a resolved (typically failed) activity. Use setStage to force past a live stage.`);
9282
+ return recordProcessedRequest({
9283
+ mutation: mutation,
9284
+ record: requestRecord,
9285
+ now: ctx.now
9286
+ }), applyActivityStatusChange({
9287
+ entry: entry,
9288
+ history: mutation.history,
9289
+ stage: openStage2.name,
9290
+ to: to,
9291
+ at: ctx.now,
9292
+ ...actor !== void 0 ? {
9293
+ actor: actor
9294
+ } : {}
9295
+ }), await persist(ctx, mutation), {
9296
+ fired: !0,
9297
+ stage: openStage2.name,
9298
+ activity: activity,
9299
+ from: from,
9300
+ to: to
8634
9301
  };
8635
- const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
8636
- return match === null ? {
8637
- requireGlobalPrincipal: !0
8638
- } : (parsed.hostname = `api.sanity.${match[1]}`, {
8639
- apiHost: parsed.origin,
8640
- requireGlobalPrincipal: !0
8641
- });
8642
- }
8643
-
8644
- async function fetchGrantsCached(requestFn, resourcePath) {
8645
- try {
8646
- return await fetchGrants({
8647
- client: {
8648
- request: requestFn
8649
- },
8650
- resourcePath: resourcePath
8651
- });
8652
- } catch (err) {
8653
- console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
8654
- return;
8655
- }
8656
9302
  }
8657
9303
 
8658
9304
  const REPLAY_SURFACE = {
@@ -8704,7 +9350,7 @@ async function whatIfFireAction(args) {
8704
9350
 
8705
9351
  function replayable(args) {
8706
9352
  const {instance: instance, stage: stage, action: action} = args;
8707
- if (invariants.terminalState(instance) !== "in-flight" || (action.params ?? []).length > 0 || action.spawn !== void 0) return !1;
9353
+ if (terminalState(instance) !== "in-flight" || (action.params ?? []).length > 0 || action.spawn !== void 0) return !1;
8708
9354
  const primed = new Set((findOpenStageEntry(instance)?.activities ?? []).map(e => e.name));
8709
9355
  return (stage.activities ?? []).every(declared => primed.has(declared.name)) ? !(stage.activities ?? []).flatMap(declared => declared.actions ?? []).some(sibling => invariants.isCascadeFired(sibling) && sibling.spawn !== void 0) : !1;
8710
9356
  }
@@ -8836,7 +9482,7 @@ async function resourceActorId(client) {
8836
9482
  async function evaluateInstance(args) {
8837
9483
  const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
8838
9484
  invariants.validateTag(tag);
8839
- const [access, instance] = await Promise.all([ resolveAccess(client, {
9485
+ const [access, instance, attributes] = await Promise.all([ resolveAccess(client, {
8840
9486
  ...args.grantsFromPath !== void 0 ? {
8841
9487
  grantsFromPath: args.grantsFromPath
8842
9488
  } : {}
@@ -8844,7 +9490,7 @@ async function evaluateInstance(args) {
8844
9490
  client: client,
8845
9491
  instanceId: instanceId,
8846
9492
  tag: tag
8847
- }) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
9493
+ }), resolveUserAttributes(client) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
8848
9494
  client: client,
8849
9495
  workflowResource: workflowResource,
8850
9496
  resourceClients: resourceClients
@@ -8869,6 +9515,9 @@ async function evaluateInstance(args) {
8869
9515
  } : {},
8870
9516
  ...grants !== void 0 ? {
8871
9517
  grants: grants
9518
+ } : {},
9519
+ ...attributes !== void 0 ? {
9520
+ attributes: attributes
8872
9521
  } : {}
8873
9522
  });
8874
9523
  }
@@ -8883,6 +9532,33 @@ function memoizedByName(render) {
8883
9532
  };
8884
9533
  }
8885
9534
 
9535
+ async function callerBoundProjectionScopes(args) {
9536
+ const can = await advisoryCan({
9537
+ instance: args.instance,
9538
+ identity: args.identity,
9539
+ grants: args.grants
9540
+ }), vars = callerBoundVars({
9541
+ ...can !== void 0 ? {
9542
+ can: can
9543
+ } : {},
9544
+ ...args.attributes !== void 0 ? {
9545
+ attributes: args.attributes
9546
+ } : {}
9547
+ }), opts = {
9548
+ actor: args.actor,
9549
+ ...vars !== void 0 ? {
9550
+ vars: vars
9551
+ } : {}
9552
+ };
9553
+ return {
9554
+ scope: await renderConditionScope(args.scopeSource, opts),
9555
+ scopeForActivity: memoizedByName(activityName => renderConditionScope(args.scopeSource, {
9556
+ activityName: activityName,
9557
+ ...opts
9558
+ }))
9559
+ };
9560
+ }
9561
+
8886
9562
  function currentStageOf(instance, definition) {
8887
9563
  try {
8888
9564
  return findStage(definition, instance.currentStage);
@@ -8908,7 +9584,7 @@ async function explainSite(args) {
8908
9584
  }
8909
9585
 
8910
9586
  async function evaluateFromSnapshot(args) {
8911
- const {instance: instance, definition: definition, actor: actor, grants: grants, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), fireConsequence = (activity, action) => whatIfFireAction({
9587
+ const {instance: instance, definition: definition, actor: actor, grants: grants, attributes: attributes, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), fireConsequence = (activity, action) => whatIfFireAction({
8912
9588
  instance: instance,
8913
9589
  definition: definition,
8914
9590
  snapshot: snapshot,
@@ -8925,22 +9601,14 @@ async function evaluateFromSnapshot(args) {
8925
9601
  }, anchorIdentity = invariants.lakePrincipalId({
8926
9602
  actor: actor,
8927
9603
  localPrincipalId: args.localPrincipalId
8928
- }), can = await advisoryCan({
8929
- instance: instance,
8930
- identity: anchorIdentity,
8931
- grants: grants
8932
- }), scope = await renderConditionScope(scopeSource, {
8933
- actor: actor,
8934
- vars: {
8935
- can: can
8936
- }
8937
- }), scopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
8938
- activityName: activityName,
9604
+ }), {scope: scope, scopeForActivity: scopeForActivity} = await callerBoundProjectionScopes({
9605
+ scopeSource: scopeSource,
8939
9606
  actor: actor,
8940
- vars: {
8941
- can: can
8942
- }
8943
- })), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
9607
+ instance: instance,
9608
+ grants: grants,
9609
+ attributes: attributes,
9610
+ identity: anchorIdentity
9611
+ }), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
8944
9612
  activityName: activityName
8945
9613
  })), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
8946
9614
  instance: instance,
@@ -8989,6 +9657,7 @@ async function evaluateFromSnapshot(args) {
8989
9657
  }
8990
9658
  const currentStage = {
8991
9659
  stage: stage,
9660
+ ...semanticsOf(stage),
8992
9661
  activities: activityEvaluations,
8993
9662
  transitions: transitionEvaluations,
8994
9663
  autonomy: stageAutonomy2
@@ -9005,6 +9674,7 @@ async function evaluateFromSnapshot(args) {
9005
9674
  return {
9006
9675
  instance: instance,
9007
9676
  definition: definition,
9677
+ ...semanticsOf(definition),
9008
9678
  actor: actor,
9009
9679
  currentStage: currentStage,
9010
9680
  pendingOnYou: pendingOnYou,
@@ -9160,6 +9830,7 @@ async function evaluateActivity(args) {
9160
9830
  }));
9161
9831
  return {
9162
9832
  activity: activity,
9833
+ ...semanticsOf(activity),
9163
9834
  status: status,
9164
9835
  kind: invariants.deriveActivityKind(activity),
9165
9836
  classification: invariants.deriveExecutorClassification(activity),
@@ -9330,9 +10001,13 @@ function fireableActionVerdict({args: args, insights: insights}) {
9330
10001
  function actionEvaluationIdentity(action) {
9331
10002
  return {
9332
10003
  action: action,
9333
- ...action.semantics !== void 0 ? {
9334
- semantics: action.semantics
9335
- } : {}
10004
+ ...semanticsOf(action)
10005
+ };
10006
+ }
10007
+
10008
+ function semanticsOf(node) {
10009
+ return node.semantics === void 0 ? {} : {
10010
+ semantics: node.semantics
9336
10011
  };
9337
10012
  }
9338
10013
 
@@ -9404,7 +10079,7 @@ function idsArm(filter, params) {
9404
10079
  function instancesQuery(args) {
9405
10080
  const {tag: tag, filter: filter = {}} = args;
9406
10081
  if (invariants.validateTag(tag), filter.limit !== void 0 && (!Number.isInteger(filter.limit) || filter.limit <= 0)) throw new invariants.ContractViolationError(`instancesQuery: limit must be a positive integer; got ${JSON.stringify(filter.limit)}`);
9407
- const conditions = [ `_type == "${invariants.WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ], params = {
10082
+ const conditions = [ `_type == "${WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ], params = {
9408
10083
  tag: tag
9409
10084
  };
9410
10085
  filter.includeCompleted !== !0 && conditions.push(inFlightFilter()), filter.definition !== void 0 && (conditions.push("definition == $definition"),
@@ -9613,7 +10288,7 @@ function planDefinitionDeploy({def: def, latest: latest, target: target}) {
9613
10288
  tag: target.tag,
9614
10289
  version: version,
9615
10290
  contentHash: contentHash,
9616
- ...invariants.modelStampFor({
10291
+ ...modelStampFor({
9617
10292
  documentType: "definition",
9618
10293
  document: expanded
9619
10294
  })
@@ -9690,7 +10365,7 @@ async function loadDefinition({client: client, definition: definition, version:
9690
10365
  definition: definition,
9691
10366
  version: version
9692
10367
  });
9693
- return invariants.assertReadableModel(doc);
10368
+ return assertReadableModel(doc);
9694
10369
  }
9695
10370
  const latest = await loadLatestDeployed({
9696
10371
  client: client,
@@ -9708,14 +10383,14 @@ async function loadLatestDeployed({client: client, definition: definition, tag:
9708
10383
  definition: definition,
9709
10384
  tag: tag
9710
10385
  });
9711
- return doc ? invariants.assertReadableModel(doc) : void 0;
10386
+ return doc ? assertReadableModel(doc) : void 0;
9712
10387
  }
9713
10388
 
9714
10389
  async function loadDefinitionVersions({client: client, definition: definition, tag: tag}) {
9715
10390
  return (await client.fetch(`*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && name == $definition && ${invariants.tagScopeFilter()}] | order(version desc)`, {
9716
10391
  definition: definition,
9717
10392
  tag: tag
9718
- })).map(invariants.assertReadableModel);
10393
+ })).map(assertReadableModel);
9719
10394
  }
9720
10395
 
9721
10396
  async function loadDefinitionVersionsOrThrow({client: client, definition: definition, tag: tag}) {
@@ -9811,7 +10486,8 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
9811
10486
  }
9812
10487
 
9813
10488
  async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
9814
- const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
10489
+ const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), vars = await callerBoundVarsForCall({
10490
+ client: ctx.client,
9815
10491
  instance: ctx.instance,
9816
10492
  options: options
9817
10493
  }), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
@@ -9824,10 +10500,8 @@ async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
9824
10500
  ...actor !== void 0 ? {
9825
10501
  actor: actor
9826
10502
  } : {},
9827
- ...can !== void 0 ? {
9828
- vars: {
9829
- can: can
9830
- }
10503
+ ...vars !== void 0 ? {
10504
+ vars: vars
9831
10505
  } : {}
9832
10506
  }
9833
10507
  }) : site.effective === !0, reason = editDisabledReason({
@@ -10103,8 +10777,8 @@ async function resumeStart(args) {
10103
10777
  version: args.version
10104
10778
  });
10105
10779
  if (mismatch !== void 0) throw new invariants.ContractViolationError(`startInstance: instanceId "${existing._id}" already exists and ${mismatch}. A supplied instanceId is start's idempotency key — reuse one only to retry the same start.`);
10106
- if (existing.stages.length === 0 && invariants.terminalState(existing) !== "in-flight") throw new invariants.ContractViolationError(`startInstance: instanceId "${existing._id}" belongs to a start that was discarded (aborted before it finished starting) — mint a new id to start again.`);
10107
- const completesStart = invariants.isUnprimed(existing), emitStarted = () => resolveTelemetry(args.telemetry).log(WorkflowInstanceStarted, instanceStartedDataFor({
10780
+ if (existing.stages.length === 0 && terminalState(existing) !== "in-flight") throw new invariants.ContractViolationError(`startInstance: instanceId "${existing._id}" belongs to a start that was discarded (aborted before it finished starting) — mint a new id to start again.`);
10781
+ const completesStart = isUnprimed(existing), emitStarted = () => resolveTelemetry(args.telemetry).log(WorkflowInstanceStarted, instanceStartedDataFor({
10108
10782
  instance: existing,
10109
10783
  initialFieldCount: args.initialFieldCount,
10110
10784
  viaSpawn: !1
@@ -10317,6 +10991,9 @@ function buildEngineCallOptions(args) {
10317
10991
  ...args.grants !== void 0 ? {
10318
10992
  grants: args.grants
10319
10993
  } : {},
10994
+ ...args.attributes !== void 0 ? {
10995
+ attributes: args.attributes
10996
+ } : {},
10320
10997
  ...args.clock !== void 0 ? {
10321
10998
  clock: args.clock
10322
10999
  } : {},
@@ -10411,7 +11088,7 @@ async function deleteDefinition(args) {
10411
11088
  async function assertNoSpawnReferrers({client: client, tag: tag, definition: definition, targets: targets, lastVersionGoes: lastVersionGoes}) {
10412
11089
  const deployed = (await client.fetch(`*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}]`, {
10413
11090
  tag: tag
10414
- })).map(invariants.assertReadableModel), targetIds = new Set(targets.map(d => d._id)), targetVersions = new Set(targets.map(d => d.version)), referrers = deployed.filter(d => !targetIds.has(d._id)).filter(d => refsOf(d).some(ref => ref.name === definition && (typeof ref.version == "number" ? targetVersions.has(ref.version) : lastVersionGoes)));
11091
+ })).map(assertReadableModel), targetIds = new Set(targets.map(d => d._id)), targetVersions = new Set(targets.map(d => d.version)), referrers = deployed.filter(d => !targetIds.has(d._id)).filter(d => refsOf(d).some(ref => ref.name === definition && (typeof ref.version == "number" ? targetVersions.has(ref.version) : lastVersionGoes)));
10415
11092
  if (referrers.length > 0) throw new invariants.DefinitionInUseError({
10416
11093
  definition: definition,
10417
11094
  blockedBy: {
@@ -10426,7 +11103,7 @@ async function assertNoSpawnReferrers({client: client, tag: tag, definition: def
10426
11103
 
10427
11104
  async function nonTerminalInstanceIds({client: client, tag: tag, definition: definition, version: version}) {
10428
11105
  const versionFilter = version === void 0 ? "" : " && pinnedVersion == $version";
10429
- return (await client.fetch(`*[_type == "${invariants.WORKFLOW_INSTANCE_TYPE}" && definition == $definition && ${invariants.tagScopeFilter()} && ${inFlightFilter()}${versionFilter}] | order(_id asc){_id}`, {
11106
+ return (await client.fetch(`*[_type == "${WORKFLOW_INSTANCE_TYPE}" && definition == $definition && ${invariants.tagScopeFilter()} && ${inFlightFilter()}${versionFilter}] | order(_id asc){_id}`, {
10430
11107
  definition: definition,
10431
11108
  tag: tag,
10432
11109
  ...version !== void 0 ? {
@@ -10471,12 +11148,12 @@ async function fetchStartSlice(args) {
10471
11148
  includeCompleted: !0
10472
11149
  }
10473
11150
  });
10474
- return (await client.fetch(query, params)).map(invariants.assertReadableModel).map(projectStartSliceRow);
11151
+ return (await client.fetch(query, params)).map(assertReadableModel).map(projectStartSliceRow);
10475
11152
  }
10476
11153
 
10477
11154
  const workflow = {
10478
11155
  deployDefinitions: async rawArgs => {
10479
- invariants.assertReaderModelAcknowledgement(rawArgs.expectedMinReaderModel);
11156
+ assertReaderModelAcknowledgement(rawArgs.expectedMinReaderModel);
10480
11157
  const args = taggedScope(rawArgs, REQUEST_TAG.deploy), {client: client, tag: tag, resourceAliases: resourceAliases} = args;
10481
11158
  invariants.validateTag(tag);
10482
11159
  const definitions = args.definitions.map(def => parseDefinitionInput(def, "workflow.deployDefinitions"));
@@ -11102,7 +11779,7 @@ const workflow = {
11102
11779
  instance: instance
11103
11780
  }), reserved = await renderConditionScope({
11104
11781
  instance: instance,
11105
- definition: invariants.parseDefinitionSnapshot(instance),
11782
+ definition: parseDefinitionSnapshot(instance),
11106
11783
  snapshot: snapshot,
11107
11784
  now: clock()
11108
11785
  }), tree = groqJs.parse(groq, {
@@ -11181,7 +11858,7 @@ const workflow = {
11181
11858
  invariants.validateTag(tag);
11182
11859
  const clock = args.clock ?? wallClock, deployed = (await client.fetch(latestDefinitionsGroq(), {
11183
11860
  tag: tag
11184
- })).map(invariants.assertReadableModel);
11861
+ })).map(assertReadableModel);
11185
11862
  let slice;
11186
11863
  return applicableDefinitions({
11187
11864
  definitions: deployed,
@@ -11563,7 +12240,7 @@ async function verifyDeployedDefinitionsInternal(args) {
11563
12240
  invariants.validateTag(tag);
11564
12241
  const log = logger("verifyDeployedDefinitions"), definitions = (await client.fetch(definitionsListGroq("asc"), {
11565
12242
  tag: tag
11566
- })).map(invariants.assertReadableModel), seen = [], missingByName = /* @__PURE__ */ new Map;
12243
+ })).map(assertReadableModel), seen = [], missingByName = /* @__PURE__ */ new Map;
11567
12244
  for (const def of definitions) seen.push({
11568
12245
  name: def.name,
11569
12246
  version: def.version,
@@ -12008,7 +12685,7 @@ function createInstanceSession(args) {
12008
12685
  }, uri = invariants.gdrFromResource(owned.resource, owned.doc._id);
12009
12686
  if (uri === selfUri()) {
12010
12687
  const rawStamp = owned.doc._updatedAt;
12011
- !invariants.isParseableInstant(rawStamp) || owned.doc._type !== invariants.WORKFLOW_INSTANCE_TYPE ? asHeldInstance(owned.doc) : Date.parse(rawStamp) > Date.parse(instance._updatedAt) && (instance = asHeldInstance(owned.doc));
12688
+ !invariants.isParseableInstant(rawStamp) || owned.doc._type !== WORKFLOW_INSTANCE_TYPE ? asHeldInstance(owned.doc) : Date.parse(rawStamp) > Date.parse(instance._updatedAt) && (instance = asHeldInstance(owned.doc));
12012
12689
  return;
12013
12690
  }
12014
12691
  target.set(uri, owned);
@@ -12031,7 +12708,7 @@ function createInstanceSession(args) {
12031
12708
  let parsedDefinition;
12032
12709
  const definitionOf = () => (parsedDefinition?.source !== instance && (parsedDefinition = {
12033
12710
  source: instance,
12034
- definition: invariants.parseDefinitionSnapshot(instance)
12711
+ definition: parseDefinitionSnapshot(instance)
12035
12712
  }), parsedDefinition.definition), siteKey = site => JSON.stringify([ site.scope, site.activity ?? null, site.name ]), stagePreview = ({target: target, mode: mode, value: value}) => {
12036
12713
  const site = previewSiteOf({
12037
12714
  instance: instance,
@@ -12075,7 +12752,7 @@ function createInstanceSession(args) {
12075
12752
  refSurface: evalScope.refSurface
12076
12753
  });
12077
12754
  }, evaluateWith = async ({held: held, guards: guards, self: self}) => {
12078
- const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
12755
+ const [{actor: actor, localPrincipalId: localPrincipalId, grants: grants}, attributes] = await Promise.all([ access(), resolveUserAttributes(client) ]), resourceGrants = await subjectResourceGrants({
12079
12756
  clientForGdr: evalScope.clientForGdr,
12080
12757
  instance: instance
12081
12758
  }), normalizedSelf = await normalizeInstanceIdentities({
@@ -12097,6 +12774,9 @@ function createInstanceSession(args) {
12097
12774
  } : {},
12098
12775
  ...grants !== void 0 ? {
12099
12776
  grants: grants
12777
+ } : {},
12778
+ ...attributes !== void 0 ? {
12779
+ attributes: attributes
12100
12780
  } : {}
12101
12781
  });
12102
12782
  }, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope}) => {
@@ -12670,7 +13350,7 @@ function attributeMember({member: member, group: group, chain: chain}) {
12670
13350
  }
12671
13351
 
12672
13352
  function diffEntry({def: rawDef, latestRaw: latestRaw, target: target}) {
12673
- invariants.assertReaderModelAcknowledgement(target.expectedMinReaderModel);
13353
+ assertReaderModelAcknowledgement(target.expectedMinReaderModel);
12674
13354
  const def = parseDefinitionInput(rawDef, "diffEntry"), plan = planDefinitionDeploy({
12675
13355
  def: def,
12676
13356
  latest: asLatest(latestRaw),
@@ -12702,7 +13382,7 @@ function asLatest(raw) {
12702
13382
  }
12703
13383
 
12704
13384
  async function computeDiffEntries({client: client, defs: defs, target: target}) {
12705
- invariants.assertReaderModelAcknowledgement(target.expectedMinReaderModel);
13385
+ assertReaderModelAcknowledgement(target.expectedMinReaderModel);
12706
13386
  const entries = [];
12707
13387
  for (const rawDef of defs) {
12708
13388
  const def = parseDefinitionInput(rawDef, "computeDiffEntries"), latest = await loadLatestDeployed({
@@ -12792,7 +13472,7 @@ const HISTORY_DISPLAY = {
12792
13472
  },
12793
13473
  opApplied: {
12794
13474
  title: "Op applied",
12795
- description: "An inline field-mutation op (field.set / field.append / status.set / etc.) ran during an action commit."
13475
+ description: "An action, direct edit, or effect completion executed an operation and recorded its audit payload."
12796
13476
  },
12797
13477
  fieldQueryDiscarded: {
12798
13478
  title: "Query result discarded",
@@ -12897,6 +13577,10 @@ const HISTORY_DISPLAY = {
12897
13577
  title: "Set field entry",
12898
13578
  description: "Overwrite a field entry's value with a resolved value expression."
12899
13579
  },
13580
+ "field.setIfMissing": {
13581
+ title: "Set field entry if missing",
13582
+ description: "Set a nullable field entry's value only when it is currently null or undefined; array, assignees, and doc.refs entries are always arrays and are not supported."
13583
+ },
12900
13584
  "field.unset": {
12901
13585
  title: "Unset field entry",
12902
13586
  description: "Reset a field entry to its default (null for scalars, [] for array kinds)."
@@ -12905,6 +13589,14 @@ const HISTORY_DISPLAY = {
12905
13589
  title: "Append to field entry",
12906
13590
  description: "Push a resolved item onto an array-kind entry (array, assignees, doc.refs)."
12907
13591
  },
13592
+ "field.inc": {
13593
+ title: "Increment field entry",
13594
+ description: "Add a resolved numeric delta, defaulting to 1, to a number entry that already holds a finite number."
13595
+ },
13596
+ "field.dec": {
13597
+ title: "Decrement field entry",
13598
+ description: "Subtract a resolved numeric delta, defaulting to 1, from a number entry that already holds a finite number."
13599
+ },
12908
13600
  "field.updateWhere": {
12909
13601
  title: "Update matching rows",
12910
13602
  description: "Merge declared sub-fields into rows of an `array` entry that match the `where` condition (`array` only — `doc.refs`/`assignees` rows are engine-shaped)."
@@ -12951,7 +13643,7 @@ const HISTORY_DISPLAY = {
12951
13643
  title: "Workflow definition",
12952
13644
  description: "An immutable workflow blueprint, addressed by `name` + `version`."
12953
13645
  },
12954
- [invariants.WORKFLOW_INSTANCE_TYPE]: {
13646
+ [WORKFLOW_INSTANCE_TYPE]: {
12955
13647
  title: "Workflow instance",
12956
13648
  description: "A running (or finished) workflow against its declared fields."
12957
13649
  }
@@ -13030,11 +13722,7 @@ exports.CONDITION_VARS = invariants.CONDITION_VARS;
13030
13722
 
13031
13723
  exports.ContractViolationError = invariants.ContractViolationError;
13032
13724
 
13033
- exports.DATA_MODEL_CHANGES = invariants.DATA_MODEL_CHANGES;
13034
-
13035
- exports.DATA_MODEL_MIN_READER = invariants.DATA_MODEL_MIN_READER;
13036
-
13037
- exports.DATA_MODEL_VERSION = invariants.DATA_MODEL_VERSION;
13725
+ exports.DECISION_SEMANTICS = invariants.DECISION_SEMANTICS;
13038
13726
 
13039
13727
  exports.DEFAULT_TRANSITION_WHEN = invariants.DEFAULT_TRANSITION_WHEN;
13040
13728
 
@@ -13058,15 +13746,11 @@ exports.GUARD_PREDICATE_VARS = invariants.GUARD_PREDICATE_VARS;
13058
13746
 
13059
13747
  exports.InstanceNotFoundError = invariants.InstanceNotFoundError;
13060
13748
 
13061
- exports.ModelVersionAheadError = invariants.ModelVersionAheadError;
13062
-
13063
13749
  exports.PersistedDocShapeError = invariants.PersistedDocShapeError;
13064
13750
 
13065
- exports.READER_MODEL_ROLLOUT_URL = invariants.READER_MODEL_ROLLOUT_URL;
13066
-
13067
13751
  exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
13068
13752
 
13069
- exports.ReaderModelAcknowledgementError = invariants.ReaderModelAcknowledgementError;
13753
+ exports.SIGNAL_SEMANTICS = invariants.SIGNAL_SEMANTICS;
13070
13754
 
13071
13755
  exports.START_FILTER_VARS = invariants.START_FILTER_VARS;
13072
13756
 
@@ -13078,14 +13762,8 @@ exports.SpawnContractsInvalidError = invariants.SpawnContractsInvalidError;
13078
13762
 
13079
13763
  exports.WORKFLOW_DEFINITION_TYPE = invariants.WORKFLOW_DEFINITION_TYPE;
13080
13764
 
13081
- exports.WORKFLOW_INSTANCE_TYPE = invariants.WORKFLOW_INSTANCE_TYPE;
13082
-
13083
13765
  exports.WorkflowError = invariants.WorkflowError;
13084
13766
 
13085
- exports.assertReadableModel = invariants.assertReadableModel;
13086
-
13087
- exports.assertReaderModelAcknowledgement = invariants.assertReaderModelAcknowledgement;
13088
-
13089
13767
  exports.classifyPrincipalId = invariants.classifyPrincipalId;
13090
13768
 
13091
13769
  exports.clientConfigFromResource = invariants.clientConfigFromResource;
@@ -13104,8 +13782,6 @@ exports.errorMessage = invariants.errorMessage;
13104
13782
 
13105
13783
  exports.extractDocumentId = invariants.extractDocumentId;
13106
13784
 
13107
- exports.fieldTreeShape = invariants.fieldTreeShape;
13108
-
13109
13785
  exports.gdrFromResource = invariants.gdrFromResource;
13110
13786
 
13111
13787
  exports.gdrRef = invariants.gdrRef;
@@ -13136,20 +13812,8 @@ exports.isTodoListEntry = invariants.isTodoListEntry;
13136
13812
 
13137
13813
  exports.isTodoListItem = invariants.isTodoListItem;
13138
13814
 
13139
- exports.isUnprimed = invariants.isUnprimed;
13140
-
13141
13815
  exports.lakePrincipalId = invariants.lakePrincipalId;
13142
13816
 
13143
- exports.minReaderModelOf = invariants.minReaderModelOf;
13144
-
13145
- exports.modelVersionOf = invariants.modelVersionOf;
13146
-
13147
- exports.parentRef = invariants.parentRef;
13148
-
13149
- exports.parseDefinitionSnapshot = invariants.parseDefinitionSnapshot;
13150
-
13151
- exports.parseDefinitionSnapshotValue = invariants.parseDefinitionSnapshotValue;
13152
-
13153
13817
  exports.parseGdr = invariants.parseGdr;
13154
13818
 
13155
13819
  exports.parseResourceGdr = invariants.parseResourceGdr;
@@ -13172,10 +13836,6 @@ exports.releaseDocId = invariants.releaseDocId;
13172
13836
 
13173
13837
  exports.releaseRef = invariants.releaseRef;
13174
13838
 
13175
- exports.requiredModelFeatures = invariants.requiredModelFeatures;
13176
-
13177
- exports.requiredReaderModel = invariants.requiredReaderModel;
13178
-
13179
13839
  exports.resourceAliasesToMap = invariants.resourceAliasesToMap;
13180
13840
 
13181
13841
  exports.resourceFromParsed = invariants.resourceFromParsed;
@@ -13192,8 +13852,6 @@ exports.startKindOf = invariants.startKindOf;
13192
13852
 
13193
13853
  exports.tagScopeFilter = invariants.tagScopeFilter;
13194
13854
 
13195
- exports.terminalState = invariants.terminalState;
13196
-
13197
13855
  exports.toBareId = invariants.toBareId;
13198
13856
 
13199
13857
  exports.tryParseGdr = invariants.tryParseGdr;
@@ -13318,6 +13976,12 @@ exports.ConcurrentEditFieldError = ConcurrentEditFieldError;
13318
13976
 
13319
13977
  exports.ConcurrentFireActionError = ConcurrentFireActionError;
13320
13978
 
13979
+ exports.DATA_MODEL_CHANGES = DATA_MODEL_CHANGES;
13980
+
13981
+ exports.DATA_MODEL_MIN_READER = DATA_MODEL_MIN_READER;
13982
+
13983
+ exports.DATA_MODEL_VERSION = DATA_MODEL_VERSION;
13984
+
13321
13985
  exports.DEFAULT_CONTENT_PERSPECTIVE = DEFAULT_CONTENT_PERSPECTIVE;
13322
13986
 
13323
13987
  exports.DEFAULT_EFFECT_LEASE_MS = DEFAULT_EFFECT_LEASE_MS;
@@ -13360,6 +14024,8 @@ exports.InitialFieldsInvalidError = InitialFieldsInvalidError;
13360
14024
 
13361
14025
  exports.MissingHandlerError = MissingHandlerError;
13362
14026
 
14027
+ exports.ModelVersionAheadError = ModelVersionAheadError;
14028
+
13363
14029
  exports.MutationGuardDeniedError = MutationGuardDeniedError;
13364
14030
 
13365
14031
  exports.MutationGuardDocSchema = MutationGuardDocSchema;
@@ -13368,6 +14034,10 @@ exports.OP_DISPLAY = OP_DISPLAY;
13368
14034
 
13369
14035
  exports.PartialGuardDeployError = PartialGuardDeployError;
13370
14036
 
14037
+ exports.READER_MODEL_ROLLOUT_URL = READER_MODEL_ROLLOUT_URL;
14038
+
14039
+ exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
14040
+
13371
14041
  exports.RefResourceUndeclaredError = RefResourceUndeclaredError;
13372
14042
 
13373
14043
  exports.RequiredFieldNotProvidedError = RequiredFieldNotProvidedError;
@@ -13380,6 +14050,8 @@ exports.StartNotPrimedError = StartNotPrimedError;
13380
14050
 
13381
14051
  exports.StartNotSettledError = StartNotSettledError;
13382
14052
 
14053
+ exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
14054
+
13383
14055
  exports.WorkflowActionFired = WorkflowActionFired;
13384
14056
 
13385
14057
  exports.WorkflowActivityReset = WorkflowActivityReset;
@@ -13426,6 +14098,10 @@ exports.activityAutonomyOf = activityAutonomyOf;
13426
14098
 
13427
14099
  exports.applicableDefinitions = applicableDefinitions;
13428
14100
 
14101
+ exports.assertReadableModel = assertReadableModel;
14102
+
14103
+ exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
14104
+
13429
14105
  exports.autonomySummary = autonomySummary;
13430
14106
 
13431
14107
  exports.availableActions = availableActions;
@@ -13508,6 +14184,8 @@ exports.documentActionDenials = documentActionDenials;
13508
14184
 
13509
14185
  exports.documentPrefilter = documentPrefilter;
13510
14186
 
14187
+ exports.documentStuckCause = documentStuckCause;
14188
+
13511
14189
  exports.effectOutputsMap = effectOutputsMap;
13512
14190
 
13513
14191
  exports.entryDocRefs = entryDocRefs;
@@ -13522,10 +14200,16 @@ exports.expandResourceAliases = expandResourceAliases;
13522
14200
 
13523
14201
  exports.explainStartRequirement = explainStartRequirement;
13524
14202
 
14203
+ exports.fieldTreeShape = fieldTreeShape;
14204
+
14205
+ exports.findActivityNode = findActivityNode;
14206
+
13525
14207
  exports.findCurrentActivityEntry = findCurrentActivityEntry;
13526
14208
 
13527
14209
  exports.findOpenStageEntry = findOpenStageEntry;
13528
14210
 
14211
+ exports.findStageNode = findStageNode;
14212
+
13529
14213
  exports.groupSitesOf = groupSitesOf;
13530
14214
 
13531
14215
  exports.guardMatches = guardMatches;
@@ -13564,10 +14248,14 @@ exports.isFilterScopedOut = isFilterScopedOut;
13564
14248
 
13565
14249
  exports.isProjectUserNotFoundError = isProjectUserNotFoundError;
13566
14250
 
14251
+ exports.isRevisionConflict = isRevisionConflict;
14252
+
13567
14253
  exports.isTelemetryEnvDenied = isTelemetryEnvDenied;
13568
14254
 
13569
14255
  exports.isTerminalStage = isTerminalStage;
13570
14256
 
14257
+ exports.isUnprimed = isUnprimed;
14258
+
13571
14259
  exports.lakeGuardId = lakeGuardId;
13572
14260
 
13573
14261
  exports.latestDefinitionsGroq = latestDefinitionsGroq;
@@ -13576,14 +14264,24 @@ exports.latestDeployedDefinitions = latestDeployedDefinitions;
13576
14264
 
13577
14265
  exports.lintEffectOutputs = lintEffectOutputs;
13578
14266
 
14267
+ exports.minReaderModelOf = minReaderModelOf;
14268
+
13579
14269
  exports.missingRequiredInputs = missingRequiredInputs;
13580
14270
 
14271
+ exports.modelVersionOf = modelVersionOf;
14272
+
13581
14273
  exports.narrateAutonomyWaits = narrateAutonomyWaits;
13582
14274
 
13583
14275
  exports.noopTelemetry = noopTelemetry;
13584
14276
 
14277
+ exports.parentRef = parentRef;
14278
+
13585
14279
  exports.parseDefinitionInput = parseDefinitionInput;
13586
14280
 
14281
+ exports.parseDefinitionSnapshot = parseDefinitionSnapshot;
14282
+
14283
+ exports.parseDefinitionSnapshotValue = parseDefinitionSnapshotValue;
14284
+
13587
14285
  exports.parseGuardDocument = parseGuardDocument;
13588
14286
 
13589
14287
  exports.parseInstanceDocument = parseInstanceDocument;
@@ -13602,6 +14300,10 @@ exports.refsOf = refsOf;
13602
14300
 
13603
14301
  exports.remediationsFor = remediationsFor;
13604
14302
 
14303
+ exports.requiredModelFeatures = requiredModelFeatures;
14304
+
14305
+ exports.requiredReaderModel = requiredReaderModel;
14306
+
13605
14307
  exports.resolveAccess = resolveAccess;
13606
14308
 
13607
14309
  exports.resolveActor = resolveActor;
@@ -13610,6 +14312,8 @@ exports.resolveClientActor = resolveClientActor;
13610
14312
 
13611
14313
  exports.resolveFieldEntry = resolveFieldEntry$1;
13612
14314
 
14315
+ exports.resolveUserAttributes = resolveUserAttributes;
14316
+
13613
14317
  exports.retractStageGuards = retractStageGuards;
13614
14318
 
13615
14319
  exports.silentLogger = silentLogger;
@@ -13632,6 +14336,8 @@ exports.subscriptionDocumentsForInstance = subscriptionDocumentsForInstance;
13632
14336
 
13633
14337
  exports.sweepStaleClaims = sweepStaleClaims;
13634
14338
 
14339
+ exports.terminalState = terminalState;
14340
+
13635
14341
  exports.unboundRequirementReads = unboundRequirementReads;
13636
14342
 
13637
14343
  exports.unsatisfiedTransitionSummaries = unsatisfiedTransitionSummaries;