@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.js CHANGED
@@ -1,6 +1,6 @@
1
- import { terminalState, andConditions, deriveActivityKind, parseDefinitionSnapshot, CALLER_BOUND_VARS, START_REQUIREMENT_VARS, CONDITION_VARS, isSubjectEntry, isUnevaluable, ContractViolationError, isStartableDefinition, conditionFieldReadNames, rethrowWithContext, isGdr, errorMessage, conditionParameterNames, START_FILTER_VARS, gdrFromResource, selfGdr, isSingleDocRefKind, parentRef, actorFulfillsRole, toBareId, WorkflowError, sameResource, resourceFromParsed, tryParseGdr, isTerminalActivityStatus, FieldValueShapeError, validateFieldValue, validateFieldAppendItem, evaluateCondition, isSingleDocRefEntry, choiceValueIssues, scalarValidationIssues, StoredFieldOpSchema, formatIssues, conditionSyntaxIssues, checkWorkflowInvariants, formatIssuePath, isGuardReadExpr, conditionEffectReads, EFFECTS_READ, datasetResourceParts, evaluatePredicates, WORKFLOW_DEFINITION_TYPE, tagScopeFilter, isCascadeFired, WORKFLOW_INSTANCE_TYPE, parseGdr, isGdrUri, gdrRef, isInputSourced, parseFieldValue, VersionSpecificDatasetGdrError, toPhysicalGdr, isBareSeedId, tolerantEntries, NonEmptyString, FIELD_VALUE_KINDS, tolerantObject, ActorShape, IsoTimestamp, ACTIVITY_STATUSES, GdrShape, DRIVER_KINDS, FIELD_SCOPES, fieldValueSchemas, parsePersistedDoc, ACTOR_KINDS, classifyPrincipalId, directoryBridgeId, assertReadableModel, InstanceNotFoundError, modelStampFor, evaluateConditionOutcome, runGroq, FIELD_READ, MUTATION_GUARD_ACTIONS, resourceGdr, minReaderModelOf, resourceFromGdrUri, refTypeIssues, rejectedRefTypes, DOCUMENT_VALUE_PERMISSIONS, lakePrincipalId, driverKind, EffectNotFoundError, firstCarriedGlobalId, deriveExecutorClassification, validateTag, extractDocumentId, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, isUnprimed, DefinitionInUseError, assertReaderModelAcknowledgement, isParseableInstant, groupMembershipNames } from "./_chunks-es/invariants.js";
1
+ import { rethrowWithContext, andConditions, deriveActivityKind, WorkflowError, CALLER_BOUND_VARS, START_REQUIREMENT_VARS, CONDITION_VARS, isSubjectEntry, isUnevaluable, ContractViolationError, isStartableDefinition, conditionFieldReadNames, isGdr, errorMessage, conditionParameterNames, START_FILTER_VARS, gdrFromResource, selfGdr, isSingleDocRefKind, actorFulfillsRole, toBareId, sameResource, resourceFromParsed, tryParseGdr, isTerminalActivityStatus, FieldValueShapeError, validateFieldValue, validateFieldAppendItem, isAlwaysArrayFieldKind, evaluateCondition, isSingleDocRefEntry, choiceValueIssues, scalarValidationIssues, StoredFieldOpSchema, formatIssues, conditionSyntaxIssues, checkWorkflowInvariants, formatIssuePath, isGuardReadExpr, conditionEffectReads, EFFECTS_READ, datasetResourceParts, evaluatePredicates, WORKFLOW_DEFINITION_TYPE, tagScopeFilter, isCascadeFired, parseGdr, isGdrUri, gdrRef, isInputSourced, parseFieldValue, VersionSpecificDatasetGdrError, toPhysicalGdr, isBareSeedId, tolerantEntries, NonEmptyString, FIELD_VALUE_KINDS, tolerantObject, ActorShape, IsoTimestamp, ACTIVITY_STATUSES, GdrShape, DRIVER_KINDS, FIELD_SCOPES, fieldValueSchemas, parsePersistedDoc, ACTOR_KINDS, classifyPrincipalId, directoryBridgeId, InstanceNotFoundError, evaluateConditionOutcome, runGroq, FIELD_READ, MUTATION_GUARD_ACTIONS, resourceGdr, resourceFromGdrUri, refTypeIssues, rejectedRefTypes, DOCUMENT_VALUE_PERMISSIONS, lakePrincipalId, firstCarriedGlobalId, driverKind, EffectNotFoundError, deriveExecutorClassification, validateTag, extractDocumentId, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, DefinitionInUseError, isParseableInstant, groupMembershipNames } from "./_chunks-es/invariants.js";
2
2
 
3
- import { ACTION_SEMANTICS, ACTIVITY_KINDS, ANONYMOUS_IDENTITY, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, EXECUTOR_CLASSIFICATIONS, FILTER_SCOPE_VARS, GROUP_KINDS, GUARD_PREDICATE_VARS, ModelVersionAheadError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, SYSTEM_IDENTITY, clientConfigFromResource, fieldTreeShape, gdrUri, isNotesEntry, isTodoListEntry, isTodoListItem, modelVersionOf, parseDefinitionSnapshotValue, parseResourceGdr, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, schemaTreeShape, startKindOf } from "./_chunks-es/invariants.js";
3
+ import { ACTION_SEMANTICS, ACTIVITY_KINDS, ANONYMOUS_IDENTITY, DECISION_SEMANTICS, DEFAULT_TRANSITION_WHEN, EXECUTOR_CLASSIFICATIONS, FILTER_SCOPE_VARS, GROUP_KINDS, GUARD_PREDICATE_VARS, PersistedDocShapeError, RESERVED_CONDITION_VARS, SIGNAL_SEMANTICS, SYSTEM_IDENTITY, clientConfigFromResource, gdrUri, isNotesEntry, isTodoListEntry, isTodoListItem, parseResourceGdr, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, releaseDocId, releaseRef, resourceAliasesToMap, schemaTreeShape, startKindOf } from "./_chunks-es/invariants.js";
4
4
 
5
5
  import { atomNode, dedupeBy, analyzeCondition, atomReadsDataset, checklistLines as checklistLines$1, phrase, quoted, listAnd, describeAtom as describeAtom$1, describeCondition as describeCondition$1, guillemets, formatValue, humanize, listOr, scopeReadOf, describeRead, explainCondition, dedupeReads, whatIfCondition, MAX_COUNTERFACTUAL_INDEX } from "@sanity/groq-condition-describe";
6
6
 
@@ -41,6 +41,53 @@ function findCurrentActivityEntry(host, activityName) {
41
41
  return findOpenStageEntry(host)?.activities.find(a => a.name === activityName);
42
42
  }
43
43
 
44
+ const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
45
+
46
+ function terminalState(instance) {
47
+ return instance.abortedAt !== void 0 ? "aborted" : instance.completedAt !== void 0 ? "completed" : "in-flight";
48
+ }
49
+
50
+ function isUnprimed(instance) {
51
+ return instance.stages.length === 0 && terminalState(instance) === "in-flight";
52
+ }
53
+
54
+ function parseDefinitionSnapshotValue(instance) {
55
+ try {
56
+ return normalizeLegacyActivityRequirements(JSON.parse(instance.definitionSnapshot));
57
+ } catch (err) {
58
+ rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
59
+ }
60
+ }
61
+
62
+ function normalizeLegacyActivityRequirements(value) {
63
+ for (const stage of arrayMember(value, "stages")) for (const activity of arrayMember(stage, "activities")) normalizeLegacyRequirementMap(activity);
64
+ return value;
65
+ }
66
+
67
+ function arrayMember(value, key) {
68
+ if (typeof value != "object" || value === null) return [];
69
+ const member = value[key];
70
+ return Array.isArray(member) ? member : [];
71
+ }
72
+
73
+ function normalizeLegacyRequirementMap(value) {
74
+ if (typeof value != "object" || value === null) return;
75
+ const activity = value, requirements = activity.requirements;
76
+ typeof requirements != "object" || requirements === null || Array.isArray(requirements) || (activity.requirements = Object.entries(requirements).map(([name, query]) => ({
77
+ type: "groq",
78
+ name: name,
79
+ query: query
80
+ })));
81
+ }
82
+
83
+ function parseDefinitionSnapshot(instance) {
84
+ return parseDefinitionSnapshotValue(instance);
85
+ }
86
+
87
+ function parentRef(instance) {
88
+ return instance.ancestors.at(-1);
89
+ }
90
+
44
91
  function effectiveEditable(baseline, override) {
45
92
  if (baseline === void 0) return;
46
93
  if (override === void 0) return baseline;
@@ -388,6 +435,313 @@ function fieldEditedData(args) {
388
435
  };
389
436
  }
390
437
 
438
+ const DATA_MODEL_VERSION = 7, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
439
+
440
+ class ReaderModelAcknowledgementError extends WorkflowError {
441
+ code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
442
+ expectedMinReaderModel;
443
+ engineMinReaderModel=DATA_MODEL_MIN_READER;
444
+ engineModelVersion=DATA_MODEL_VERSION;
445
+ documentationUrl=READER_MODEL_ROLLOUT_URL;
446
+ constructor(expectedMinReaderModel, context = "Deployment") {
447
+ const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
448
+ 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}`),
449
+ this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
450
+ }
451
+ }
452
+
453
+ function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
454
+ if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
455
+ }
456
+
457
+ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
458
+ id: "governed-model-stamps",
459
+ introducedInModel: 1,
460
+ minReaderModel: 0,
461
+ documentTypes: Object.freeze([ "definition", "instance" ]),
462
+ compatibility: "additive",
463
+ applicability: "unconditional",
464
+ summary: "Definition and instance documents carry model provenance and reader-floor stamps."
465
+ }), Object.freeze({
466
+ id: "subject-field-kind",
467
+ introducedInModel: 2,
468
+ minReaderModel: 0,
469
+ documentTypes: Object.freeze([ "definition", "instance" ]),
470
+ compatibility: "additive",
471
+ applicability: "detectable",
472
+ summary: "A workflow-level subject field identifies the document a workflow is about."
473
+ }), Object.freeze({
474
+ id: "typed-scalar-choice-lists",
475
+ introducedInModel: 2,
476
+ minReaderModel: 2,
477
+ documentTypes: Object.freeze([ "definition", "instance" ]),
478
+ compatibility: "reader-floor",
479
+ applicability: "detectable",
480
+ summary: "Scalar fields may constrain writes to a persisted typed choice list."
481
+ }), Object.freeze({
482
+ id: "action-semantics",
483
+ introducedInModel: 2,
484
+ minReaderModel: 0,
485
+ documentTypes: Object.freeze([ "definition" ]),
486
+ compatibility: "additive",
487
+ applicability: "detectable",
488
+ summary: "Ordinary actions may carry advisory workflow semantics."
489
+ }), Object.freeze({
490
+ id: "inclusive-scalar-bounds",
491
+ introducedInModel: 2,
492
+ minReaderModel: 2,
493
+ documentTypes: Object.freeze([ "definition", "instance" ]),
494
+ compatibility: "reader-floor",
495
+ applicability: "detectable",
496
+ summary: "String, text, and number values may carry persisted inclusive bounds."
497
+ }), Object.freeze({
498
+ id: "progress-field-kind",
499
+ introducedInModel: 3,
500
+ minReaderModel: 0,
501
+ documentTypes: Object.freeze([ "definition", "instance" ]),
502
+ compatibility: "additive",
503
+ applicability: "detectable",
504
+ summary: "A progress field kind carries application-defined 0–100 completion."
505
+ }), Object.freeze({
506
+ id: "effect-claim-tokens",
507
+ introducedInModel: 3,
508
+ minReaderModel: 0,
509
+ documentTypes: Object.freeze([ "instance" ]),
510
+ compatibility: "additive",
511
+ applicability: "detectable",
512
+ summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
513
+ }), Object.freeze({
514
+ id: "classified-principal-ids",
515
+ introducedInModel: 4,
516
+ minReaderModel: 4,
517
+ documentTypes: Object.freeze([ "instance" ]),
518
+ compatibility: "reader-floor",
519
+ applicability: "unconditional",
520
+ 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."
521
+ }), Object.freeze({
522
+ id: "readiness-requirements",
523
+ introducedInModel: 4,
524
+ minReaderModel: 4,
525
+ documentTypes: Object.freeze([ "definition" ]),
526
+ compatibility: "reader-floor",
527
+ applicability: "detectable",
528
+ summary: "Start and activity readiness use named polymorphic requirement arrays."
529
+ }), Object.freeze({
530
+ id: "due-date-field-kinds",
531
+ introducedInModel: 5,
532
+ minReaderModel: 0,
533
+ documentTypes: Object.freeze([ "definition", "instance" ]),
534
+ compatibility: "additive",
535
+ applicability: "detectable",
536
+ summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
537
+ }), Object.freeze({
538
+ id: "node-semantics",
539
+ introducedInModel: 6,
540
+ minReaderModel: 0,
541
+ documentTypes: Object.freeze([ "definition" ]),
542
+ compatibility: "additive",
543
+ applicability: "detectable",
544
+ summary: "Workflow, stage, activity, and action nodes may carry signal or custom advisory semantics."
545
+ }), Object.freeze({
546
+ id: "field-patch-ops",
547
+ introducedInModel: 6,
548
+ minReaderModel: 0,
549
+ documentTypes: Object.freeze([ "definition", "instance" ]),
550
+ compatibility: "additive",
551
+ applicability: "detectable",
552
+ summary: "Field ops may increment, decrement, or initialize a missing field value."
553
+ }), Object.freeze({
554
+ id: "attributes-condition-var",
555
+ introducedInModel: 7,
556
+ minReaderModel: 0,
557
+ documentTypes: Object.freeze([ "definition" ]),
558
+ compatibility: "additive",
559
+ applicability: "unconditional",
560
+ summary: "Caller-bound $attributes condition variable binds the acting token's org-level User Attributes (advisory; absent when unavailable)."
561
+ }) ]);
562
+
563
+ function recordOf(value) {
564
+ return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
565
+ }
566
+
567
+ function recordsAt(record, key) {
568
+ const value = record[key];
569
+ return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
570
+ }
571
+
572
+ function nestedFieldEntries(entries) {
573
+ return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
574
+ }
575
+
576
+ function parsedDefinitionSnapshot(root) {
577
+ if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
578
+ _id: typeof root._id == "string" ? root._id : "<unknown instance>",
579
+ definitionSnapshot: root.definitionSnapshot
580
+ }));
581
+ }
582
+
583
+ function persistedDefinitionTree(document) {
584
+ const root = recordOf(document);
585
+ if (root === void 0) return;
586
+ const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], {stages: stages, activities: activities, actions: actions} = definitionDescendants(roots);
587
+ return {
588
+ roots: roots,
589
+ stages: stages,
590
+ activities: activities,
591
+ actions: actions
592
+ };
593
+ }
594
+
595
+ function persistedFieldEntries(document) {
596
+ const tree = persistedDefinitionTree(document);
597
+ if (tree === void 0) return [];
598
+ const {roots: roots, stages: stages, activities: activities, actions: actions} = tree, effects = actions.flatMap(action => recordsAt(action, "effects"));
599
+ 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")) ]);
600
+ }
601
+
602
+ function definitionDescendants(roots) {
603
+ const stages = roots.flatMap(root => recordsAt(root, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions"));
604
+ return {
605
+ stages: stages,
606
+ activities: activities,
607
+ actions: actions
608
+ };
609
+ }
610
+
611
+ function hasChoiceList(document) {
612
+ return persistedFieldEntries(document).some(entry => {
613
+ const options = recordOf(entry.options);
614
+ return options !== void 0 && Array.isArray(options.list);
615
+ });
616
+ }
617
+
618
+ function hasFieldKind(document, kind) {
619
+ return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
620
+ }
621
+
622
+ function definitionNodes(document) {
623
+ const root = recordOf(document);
624
+ if (root !== void 0) return {
625
+ root: root,
626
+ ...definitionDescendants([ root ])
627
+ };
628
+ }
629
+
630
+ function hasActionSemantics(document) {
631
+ return definitionNodes(document)?.actions.some(hasSemantics) ?? !1;
632
+ }
633
+
634
+ function hasNodeSemantics(document) {
635
+ const nodes = definitionNodes(document);
636
+ return nodes === void 0 ? !1 : [ nodes.root, ...nodes.stages, ...nodes.activities ].some(hasSemantics) ? !0 : nodes.actions.some(action => hasSemantics(action) && action.semantics.some(isNodeSemanticValue));
637
+ }
638
+
639
+ function isNodeSemanticValue(semantic) {
640
+ return typeof semantic == "string" && (semantic.startsWith("signal.") || semantic.startsWith("custom."));
641
+ }
642
+
643
+ function hasSemantics(node) {
644
+ return Array.isArray(node.semantics);
645
+ }
646
+
647
+ function hasPersistedOpType(document, types) {
648
+ const tree = persistedDefinitionTree(document);
649
+ 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)));
650
+ }
651
+
652
+ function hasScalarValidation(document) {
653
+ return persistedFieldEntries(document).some(entry => {
654
+ const validation = recordOf(entry.validation);
655
+ return typeof validation?.min == "number" || typeof validation?.max == "number";
656
+ });
657
+ }
658
+
659
+ function hasClaimTokens(document) {
660
+ const root = recordOf(document);
661
+ return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
662
+ const claim = recordOf(entry.claim);
663
+ return claim !== void 0 && typeof claim.claimToken == "string";
664
+ });
665
+ }
666
+
667
+ function hasReadinessRequirements(document) {
668
+ const root = recordOf(document);
669
+ 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)));
670
+ }
671
+
672
+ const featureDetectors = {
673
+ "governed-model-stamps": () => !0,
674
+ "subject-field-kind": document => hasFieldKind(document, "subject"),
675
+ "typed-scalar-choice-lists": hasChoiceList,
676
+ "action-semantics": hasActionSemantics,
677
+ "inclusive-scalar-bounds": hasScalarValidation,
678
+ "progress-field-kind": document => hasFieldKind(document, "progress"),
679
+ "effect-claim-tokens": hasClaimTokens,
680
+ "classified-principal-ids": () => !0,
681
+ "readiness-requirements": hasReadinessRequirements,
682
+ "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime"),
683
+ "node-semantics": hasNodeSemantics,
684
+ "field-patch-ops": document => hasPersistedOpType(document, [ "field.inc", "field.dec", "field.setIfMissing" ]),
685
+ "attributes-condition-var": () => !0
686
+ };
687
+
688
+ function requiredModelFeatures(documentType, document) {
689
+ return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
690
+ }
691
+
692
+ function requiredReaderModel(documentType, document) {
693
+ return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
694
+ }
695
+
696
+ function modelStampFor(args) {
697
+ return {
698
+ modelVersion: DATA_MODEL_VERSION,
699
+ minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
700
+ };
701
+ }
702
+
703
+ function fieldTreeShape(value) {
704
+ if (Array.isArray(value)) return value.map(fieldTreeShape);
705
+ if (value === null) return "null";
706
+ if (typeof value == "object") {
707
+ const record = value;
708
+ return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
709
+ }
710
+ return typeof value;
711
+ }
712
+
713
+ function modelVersionOf(doc) {
714
+ const stamp = doc.modelVersion;
715
+ return typeof stamp == "number" ? stamp : 0;
716
+ }
717
+
718
+ function minReaderModelOf(doc) {
719
+ const floor = doc.minReaderModel;
720
+ return typeof floor == "number" ? floor : modelVersionOf(doc);
721
+ }
722
+
723
+ class ModelVersionAheadError extends WorkflowError {
724
+ documentId;
725
+ documentModelVersion;
726
+ requiredReaderModel;
727
+ engineModelVersion;
728
+ constructor(args) {
729
+ 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.`),
730
+ this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
731
+ this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
732
+ }
733
+ }
734
+
735
+ function assertReadableModel(doc) {
736
+ const documentReaderModel = minReaderModelOf(doc);
737
+ if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
738
+ documentId: doc._id,
739
+ documentModelVersion: modelVersionOf(doc),
740
+ requiredReaderModel: documentReaderModel
741
+ });
742
+ return doc;
743
+ }
744
+
391
745
  function effectSites(def) {
392
746
  const sites = [];
393
747
  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({
@@ -862,12 +1216,8 @@ function renderWorkflowRead(read, ctx) {
862
1216
  text: guillemets(title)
863
1217
  });
864
1218
  }
865
- if (read.variable === "can" && typeof read.path[0] == "string") return phrase("read.permission", {
866
- params: {
867
- permission: read.path[0]
868
- },
869
- text: `your ${read.path[0]} permission`
870
- });
1219
+ const keyed = keyedCallerRead(read);
1220
+ if (keyed !== void 0) return keyed;
871
1221
  if (read.variable === "actor" && read.path.length === 1 && read.path[0] === "id") return phrase("read.actor-id", {
872
1222
  params: {},
873
1223
  text: "your id"
@@ -889,6 +1239,24 @@ function renderWorkflowRead(read, ctx) {
889
1239
  });
890
1240
  }
891
1241
 
1242
+ function keyedCallerRead(read) {
1243
+ const key = read.path[0];
1244
+ if (typeof key == "string") {
1245
+ if (read.variable === "can") return phrase("read.permission", {
1246
+ params: {
1247
+ permission: key
1248
+ },
1249
+ text: `your ${key} permission`
1250
+ });
1251
+ if (read.variable === "attributes") return phrase("read.attribute", {
1252
+ params: {
1253
+ attribute: key
1254
+ },
1255
+ text: `your ${guillemets(key)} attribute`
1256
+ });
1257
+ }
1258
+ }
1259
+
892
1260
  function workflowRequirement(requirement, ctx) {
893
1261
  const {target: target} = requirement, clause = clauseVarRequirement(requirement);
894
1262
  if (clause !== void 0) return clause;
@@ -1789,6 +2157,10 @@ function derefBase(ref, snapshot) {
1789
2157
  };
1790
2158
  }
1791
2159
 
2160
+ function isRecord(value) {
2161
+ return typeof value == "object" && value !== null && !Array.isArray(value);
2162
+ }
2163
+
1792
2164
  function buildParams(args) {
1793
2165
  const {instance: instance, now: now, snapshot: snapshot, extra: extra} = args, currentActivities2 = findOpenStageEntry(instance)?.activities ?? [];
1794
2166
  return {
@@ -2258,6 +2630,12 @@ function isRevisionConflict(error) {
2258
2630
  return statusCode === 409 ? !0 : typeof message == "string" && message.includes("ifRevisionId check failed");
2259
2631
  }
2260
2632
 
2633
+ function isCreateIdCollision(error) {
2634
+ if (typeof error != "object" || error === null) return !1;
2635
+ const {message: message, responseBody: responseBody} = error;
2636
+ return typeof message == "string" && message.includes("already exists") && (message.includes("Document by ID") || message.includes("create() failed")) ? !0 : typeof responseBody == "string" && responseBody.includes("documentAlreadyExistsError");
2637
+ }
2638
+
2261
2639
  class ConcurrentEditFieldError extends WorkflowError {
2262
2640
  instanceId;
2263
2641
  target;
@@ -2310,7 +2688,7 @@ class CascadeLimitError extends WorkflowError {
2310
2688
  }
2311
2689
  }
2312
2690
 
2313
- const FIELD_OP_TYPES = [ "field.set", "field.unset", "field.append", "field.updateWhere", "field.removeWhere" ];
2691
+ const FIELD_OP_TYPES = [ "field.set", "field.setIfMissing", "field.unset", "field.append", "field.inc", "field.dec", "field.updateWhere", "field.removeWhere" ];
2314
2692
 
2315
2693
  function isFieldOp(summary) {
2316
2694
  return FIELD_OP_TYPES.includes(summary.opType);
@@ -2411,7 +2789,7 @@ async function runOps(args) {
2411
2789
  refSurface: refSurface,
2412
2790
  opsFromDefinition: opsFromDefinition
2413
2791
  });
2414
- summaries.push(summary), mutation.history.push(opAppliedEntry({
2792
+ summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
2415
2793
  origin: origin,
2416
2794
  summary: summary,
2417
2795
  stage: stage,
@@ -2422,6 +2800,10 @@ async function runOps(args) {
2422
2800
  return summaries;
2423
2801
  }
2424
2802
 
2803
+ function shouldRecordOpApplied(summary) {
2804
+ return summary.opType !== "field.setIfMissing" || summary.resolved !== void 0;
2805
+ }
2806
+
2425
2807
  function opAppliedEntry(args) {
2426
2808
  const {origin: origin, summary: summary, stage: stage, actor: actor, now: now} = args;
2427
2809
  return {
@@ -2493,12 +2875,19 @@ async function applyOp(op, ctx) {
2493
2875
  case "field.set":
2494
2876
  return applyFieldSet(op, ctx);
2495
2877
 
2878
+ case "field.setIfMissing":
2879
+ return applyFieldSetIfMissing(op, ctx);
2880
+
2496
2881
  case "field.unset":
2497
2882
  return applyFieldUnset(op, ctx);
2498
2883
 
2499
2884
  case "field.append":
2500
2885
  return applyFieldAppend(op, ctx);
2501
2886
 
2887
+ case "field.inc":
2888
+ case "field.dec":
2889
+ return applyFieldArithmetic(op, ctx);
2890
+
2502
2891
  case "field.updateWhere":
2503
2892
  return applyFieldUpdateWhere(op, ctx);
2504
2893
 
@@ -2537,6 +2926,78 @@ function applyFieldSet(op, ctx) {
2537
2926
  };
2538
2927
  }
2539
2928
 
2929
+ function applyFieldSetIfMissing(op, ctx) {
2930
+ const entry = locateEntry(ctx, op.target);
2931
+ return isAlwaysArrayFieldKind(entry._type) && rejectFieldOpTarget({
2932
+ entry: entry,
2933
+ op: op,
2934
+ issue: "is always array-valued — setIfMissing applies to nullable entries only; an empty array entry already holds []"
2935
+ }), entry.value !== null && entry.value !== void 0 ? {
2936
+ opType: op.type,
2937
+ target: op.target
2938
+ } : {
2939
+ ...applyFieldSet({
2940
+ ...op,
2941
+ type: "field.set"
2942
+ }, ctx),
2943
+ opType: op.type
2944
+ };
2945
+ }
2946
+
2947
+ function applyFieldArithmetic(op, ctx) {
2948
+ const entry = locateEntry(ctx, op.target);
2949
+ entry._type !== "number" && rejectFieldOpTarget({
2950
+ entry: entry,
2951
+ op: op,
2952
+ issue: `is a ${entry._type} entry — arithmetic ops target \`number\` entries only`
2953
+ }), typeof entry.value != "number" && rejectFieldOpTarget({
2954
+ entry: entry,
2955
+ op: op,
2956
+ issue: "has no numeric value — initialize it before applying arithmetic"
2957
+ });
2958
+ const resolvedDelta = op.value === void 0 ? 1 : resolveOpValue({
2959
+ src: op.value,
2960
+ ctx: ctx,
2961
+ target: {
2962
+ kind: "number"
2963
+ }
2964
+ });
2965
+ (typeof resolvedDelta != "number" || !Number.isFinite(resolvedDelta)) && rejectFieldOpTarget({
2966
+ entry: entry,
2967
+ op: op,
2968
+ issue: "value must resolve to a finite number"
2969
+ });
2970
+ const nextValue = entry.value + (op.type === "field.inc" ? resolvedDelta : -resolvedDelta);
2971
+ Number.isFinite(nextValue) || rejectFieldOpTarget({
2972
+ entry: entry,
2973
+ op: op,
2974
+ issue: "result must be a finite number"
2975
+ });
2976
+ const value = validateFieldValue({
2977
+ entryType: entry._type,
2978
+ entryName: entry.name,
2979
+ value: nextValue,
2980
+ ...entryShape(entry)
2981
+ });
2982
+ return setEntryValue(entry, value), {
2983
+ opType: op.type,
2984
+ target: op.target,
2985
+ resolved: {
2986
+ value: value
2987
+ }
2988
+ };
2989
+ }
2990
+
2991
+ function rejectFieldOpTarget(args) {
2992
+ const {entry: entry, op: op, issue: issue} = args;
2993
+ throw new FieldValueShapeError({
2994
+ entryType: entry._type,
2995
+ entryName: entry.name,
2996
+ mode: "value",
2997
+ issues: [ `${op.type} target ${op.target.scope}:"${op.target.field}" ${issue}` ]
2998
+ });
2999
+ }
3000
+
2540
3001
  function entryShape(entry) {
2541
3002
  return entry._type === "object" ? {
2542
3003
  fields: entry.fields
@@ -2572,15 +3033,9 @@ function appendItemSlot(entry) {
2572
3033
  };
2573
3034
  }
2574
3035
 
2575
- const EMPTY_BY_KIND = {
2576
- "doc.refs": [],
2577
- array: [],
2578
- assignees: []
2579
- };
2580
-
2581
3036
  function applyFieldUnset(op, ctx) {
2582
3037
  const entry = locateEntry(ctx, op.target);
2583
- return setEntryValue(entry, EMPTY_BY_KIND[entry._type] ?? null), {
3038
+ return setEntryValue(entry, isAlwaysArrayFieldKind(entry._type) ? [] : null), {
2584
3039
  opType: op.type,
2585
3040
  target: op.target
2586
3041
  };
@@ -2619,7 +3074,7 @@ function applyFieldAppend(op, ctx) {
2619
3074
  }
2620
3075
 
2621
3076
  function withRowKey(item) {
2622
- return typeof item == "object" && item !== null && !Array.isArray(item) && !("_key" in item) ? {
3077
+ return isRecord(item) && !("_key" in item) ? {
2623
3078
  _key: randomKey(),
2624
3079
  ...item
2625
3080
  } : item;
@@ -3318,6 +3773,14 @@ function latestDeployedDefinitions(rows) {
3318
3773
  return [ ...byName.values() ];
3319
3774
  }
3320
3775
 
3776
+ function findStageNode(args) {
3777
+ return args.definition?.stages.find(entry => entry.name === args.stageName);
3778
+ }
3779
+
3780
+ function findActivityNode(args) {
3781
+ return findStageNode(args)?.activities?.find(entry => entry.name === args.activityName);
3782
+ }
3783
+
3321
3784
  function liveChildrenField(instance) {
3322
3785
  const live = liveSubworkflows(instance).length;
3323
3786
  return live > 0 ? {
@@ -3406,6 +3869,27 @@ function noTransitionFiresCause(input) {
3406
3869
  };
3407
3870
  }
3408
3871
 
3872
+ function stuckFromDocumentState(input) {
3873
+ return failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input);
3874
+ }
3875
+
3876
+ function documentStuckCause(args) {
3877
+ const stage = findOpenStageEntry(args.instance);
3878
+ if (stage !== void 0) return stuckFromDocumentState({
3879
+ instance: args.instance,
3880
+ activities: stage.activities.map(entry => ({
3881
+ status: entry.status,
3882
+ activity: findActivityNode({
3883
+ activityName: entry.name,
3884
+ definition: args.definition,
3885
+ stageName: stage.name
3886
+ }) ?? {
3887
+ name: entry.name
3888
+ }
3889
+ }))
3890
+ });
3891
+ }
3892
+
3409
3893
  function diagnoseInstance(input) {
3410
3894
  const {instance: instance} = input, terminal = terminalState(instance);
3411
3895
  if (terminal === "aborted" && instance.abortedAt !== void 0) {
@@ -3424,7 +3908,7 @@ function diagnoseInstance(input) {
3424
3908
  at: instance.completedAt,
3425
3909
  ...liveChildrenField(instance)
3426
3910
  };
3427
- const cause = failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input) ?? noTransitionFiresCause(input);
3911
+ const cause = stuckFromDocumentState(input) ?? noTransitionFiresCause(input);
3428
3912
  return cause !== void 0 ? {
3429
3913
  state: "stuck",
3430
3914
  cause: cause
@@ -3803,10 +4287,8 @@ function assertRequiredInputProvided({entryDefs: entryDefs, initialFields: initi
3803
4287
  });
3804
4288
  }
3805
4289
 
3806
- const ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([ "doc.refs", "array", "assignees" ]);
3807
-
3808
4290
  function defaultEntryValue(entryType) {
3809
- return ARRAY_FIELD_TYPES.has(entryType) ? [] : null;
4291
+ return isAlwaysArrayFieldKind(entryType) ? [] : null;
3810
4292
  }
3811
4293
 
3812
4294
  function resolveInputValue({entry: entry, initialFields: initialFields, defaultValue: defaultValue}) {
@@ -4407,7 +4889,9 @@ const SYNC_COMMIT = {
4407
4889
  effect: "workflow.effect",
4408
4890
  verifyDefinitions: "workflow.verify-definitions",
4409
4891
  accessResolveActor: "workflow.access.resolve-actor",
4410
- accessGrants: "workflow.access.grants"
4892
+ accessGrants: "workflow.access.grants",
4893
+ accessResolveOrg: "workflow.access.resolve-org",
4894
+ accessAttributes: "workflow.access.attributes"
4411
4895
  }, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
4412
4896
 
4413
4897
  function unwrapPatch(patch) {
@@ -5375,10 +5859,6 @@ function userLoginProvider(user) {
5375
5859
  return user?.provider ?? user?.loginProvider;
5376
5860
  }
5377
5861
 
5378
- function isRecord(value) {
5379
- return typeof value == "object" && value !== null && !Array.isArray(value);
5380
- }
5381
-
5382
5862
  function optionalString(value) {
5383
5863
  return value === void 0 || typeof value == "string";
5384
5864
  }
@@ -5883,12 +6363,14 @@ function resolveGuard({guard: guard, instance: instance, stageName: stageName, n
5883
6363
 
5884
6364
  async function upsertGuard(args) {
5885
6365
  const {client: client, doc: doc, exists: exists} = args;
5886
- if (!exists) {
6366
+ if (!exists) try {
5887
6367
  await client.create(doc, {
5888
6368
  ...SYNC_COMMIT,
5889
6369
  tag: REQUEST_TAG.guardDeploy
5890
6370
  });
5891
6371
  return;
6372
+ } catch (error) {
6373
+ if (!isCreateIdCollision(error)) throw error;
5892
6374
  }
5893
6375
  const {_id: _id, _type: _type, _rev: _rev, _createdAt: _createdAt, _updatedAt: _updatedAt, ...body} = doc;
5894
6376
  await client.patch(doc._id).set(body).commit({
@@ -6913,54 +7395,461 @@ async function advisoryCan({instance: instance, identity: identity, grants: gran
6913
7395
  return can;
6914
7396
  }
6915
7397
 
6916
- function requirementDescriptor(requirement) {
7398
+ const DANGEROUS_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([ "__proto__", "constructor", "prototype" ]);
7399
+
7400
+ function attributeEntry(row) {
7401
+ 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 ];
7402
+ }
7403
+
7404
+ function normalizeUserAttributes(response) {
7405
+ if (!isRecord(response)) return;
7406
+ const rows = response.attributes;
7407
+ if (!Array.isArray(rows)) return;
7408
+ const out = {};
7409
+ for (const row of rows) {
7410
+ const entry = attributeEntry(row);
7411
+ entry !== void 0 && (out[entry[0]] = entry[1]);
7412
+ }
7413
+ return out;
7414
+ }
7415
+
7416
+ const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap, orgIdCache = /* @__PURE__ */ new WeakMap, attributesCache = /* @__PURE__ */ new WeakMap;
7417
+
7418
+ async function resolveAccess(taggedClient, args = {}) {
7419
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7420
+ if (requestFn === void 0) throw new 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).");
7421
+ const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
7422
+ client: client,
7423
+ requestFn: requestFn,
7424
+ resourcePath: args.grantsFromPath
7425
+ }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
7426
+ if (identity === void 0) throw new ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
6917
7427
  return {
6918
- name: requirement.name,
6919
- ...requirement.title !== void 0 ? {
6920
- title: requirement.title
7428
+ actor: identity.actor,
7429
+ ...identity.localPrincipalId !== void 0 ? {
7430
+ localPrincipalId: identity.localPrincipalId
6921
7431
  } : {},
6922
- ...requirement.description !== void 0 ? {
6923
- description: requirement.description
7432
+ ...grants !== void 0 ? {
7433
+ grants: grants
6924
7434
  } : {}
6925
7435
  };
6926
7436
  }
6927
7437
 
6928
- function subjectDenialLabels(denied) {
6929
- return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
7438
+ async function resolveUserAttributes(taggedClient) {
7439
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7440
+ if (requestFn !== void 0) return cachedAttributes({
7441
+ client: client,
7442
+ requestFn: requestFn
7443
+ });
6930
7444
  }
6931
7445
 
6932
- class ActionDisabledError extends WorkflowError {
6933
- reason;
6934
- activity;
6935
- action;
6936
- constructor(args) {
6937
- super("action-disabled", formatDisabledReason({
6938
- activity: args.activity,
6939
- action: args.action,
6940
- reason: args.reason
6941
- })), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
6942
- this.action = args.action;
6943
- }
7446
+ function cachedActor(client, requestFn) {
7447
+ const cached = actorCache.get(client);
7448
+ if (cached !== void 0) return cached;
7449
+ const pending = fetchActor(client, requestFn).catch(err => {
7450
+ throw actorCache.get(client) === pending && actorCache.delete(client), err;
7451
+ });
7452
+ return actorCache.set(client, pending), pending;
6944
7453
  }
6945
7454
 
6946
- class StartNotAllowedError extends WorkflowError {
6947
- definition;
6948
- unmetRequirements;
6949
- constructor(args) {
6950
- super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
6951
- this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
6952
- }
7455
+ function grantsForClientPath(taggedClient, resourcePath) {
7456
+ const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
7457
+ return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
7458
+ client: client,
7459
+ requestFn: requestFn,
7460
+ resourcePath: resourcePath
7461
+ });
6953
7462
  }
6954
7463
 
6955
- function actionRendering(action) {
6956
- const kind = action.disabledReason?.kind;
6957
- return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
7464
+ function lazyRequest(client) {
7465
+ return client.request === void 0 ? void 0 : opts => client.request(opts);
6958
7466
  }
6959
7467
 
6960
- const disabledReasonDetail = {
6961
- "filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
6962
- "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`,
6963
- "activity-not-active": r => `activity status is "${r.status}"`,
7468
+ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
7469
+ return cachedByKey({
7470
+ store: grantsCache,
7471
+ client: client,
7472
+ key: resourcePath,
7473
+ load: () => fetchGrantsCached(requestFn, resourcePath)
7474
+ });
7475
+ }
7476
+
7477
+ function cachedByKey(args) {
7478
+ let byKey = args.store.get(args.client);
7479
+ byKey === void 0 && (byKey = /* @__PURE__ */ new Map, args.store.set(args.client, byKey));
7480
+ const cached = byKey.get(args.key);
7481
+ if (cached !== void 0) return cached;
7482
+ const pending = args.evictOnRejection ? args.load().catch(err => {
7483
+ throw byKey.get(args.key) === pending && byKey.delete(args.key), err;
7484
+ }) : args.load();
7485
+ return byKey.set(args.key, pending), pending;
7486
+ }
7487
+
7488
+ async function fetchActor(client, requestFn) {
7489
+ const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
7490
+ if (sessionId === void 0) return;
7491
+ const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
7492
+ client: client,
7493
+ sessionId: sessionId,
7494
+ resourceId: resourceId
7495
+ }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
7496
+ refuseProjectScopedActor({
7497
+ id: id,
7498
+ globalUser: globalUser,
7499
+ globalHostId: globalHostId,
7500
+ bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
7501
+ });
7502
+ const roleNames = roleNamesFor(resourceUser, globalUser);
7503
+ return {
7504
+ actor: {
7505
+ kind: "person",
7506
+ id: id,
7507
+ ...roleNames.length > 0 ? {
7508
+ roles: roleNames
7509
+ } : {}
7510
+ },
7511
+ ...resourceId !== void 0 && resourceId !== id ? {
7512
+ localPrincipalId: resourceId
7513
+ } : {}
7514
+ };
7515
+ }
7516
+
7517
+ function roleNamesFor(resourceUser, globalUser) {
7518
+ return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
7519
+ }
7520
+
7521
+ const NO_BRIDGE = {
7522
+ status: "not-applicable"
7523
+ };
7524
+
7525
+ function globalRouteReason(globalUser, globalHostId) {
7526
+ return "reason" in globalUser ? globalUser.reason : globalHostId === void 0 ? "no record" : `the global host answered with project-scoped principal "${globalHostId}"`;
7527
+ }
7528
+
7529
+ async function bridgeProjectPrincipal(args) {
7530
+ const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
7531
+ return classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || classifyPrincipalId(resourceId).namespace !== "project" ? {
7532
+ status: "unavailable",
7533
+ reason: "no project-scoped principal from the resource host to address the directory with"
7534
+ } : directoryGlobalId({
7535
+ client: client,
7536
+ principalId: resourceId
7537
+ });
7538
+ }
7539
+
7540
+ async function directoryGlobalId(args) {
7541
+ const {client: client, principalId: principalId} = args, projectId = projectIdOf(client);
7542
+ if (projectId === void 0) return {
7543
+ status: "unavailable",
7544
+ reason: "the client reports no projectId, so its user directory has no address"
7545
+ };
7546
+ const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
7547
+ if (lookup.status !== "resolved") return {
7548
+ status: "unavailable",
7549
+ reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
7550
+ ...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
7551
+ cause: lookup.cause
7552
+ } : {}
7553
+ };
7554
+ const globalId = directoryBridgeId(lookup.user.sanityUserId);
7555
+ return globalId === void 0 ? {
7556
+ status: "unavailable",
7557
+ reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
7558
+ } : {
7559
+ status: "resolved",
7560
+ globalId: globalId
7561
+ };
7562
+ }
7563
+
7564
+ function refuseProjectScopedActor(args) {
7565
+ const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
7566
+ if (classifyPrincipalId(id).namespace !== "project") return;
7567
+ const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
7568
+ bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
7569
+ const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
7570
+ 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 : {
7571
+ cause: cause
7572
+ });
7573
+ }
7574
+
7575
+ function usableId(user) {
7576
+ if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
7577
+ }
7578
+
7579
+ async function fetchCurrentUser(requestFn, hostDescription) {
7580
+ try {
7581
+ return await requestFn({
7582
+ uri: "/users/me",
7583
+ tag: REQUEST_TAG.accessResolveActor
7584
+ });
7585
+ } catch (err) {
7586
+ 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.`, {
7587
+ cause: err
7588
+ });
7589
+ }
7590
+ }
7591
+
7592
+ async function fetchGlobalUser(client) {
7593
+ const sibling = globalHostRequestOf(client);
7594
+ if ("reason" in sibling) return {
7595
+ user: void 0,
7596
+ reason: sibling.reason,
7597
+ ...sibling.cause !== void 0 ? {
7598
+ cause: sibling.cause
7599
+ } : {}
7600
+ };
7601
+ try {
7602
+ const user = await sibling.request({
7603
+ uri: "/users/me",
7604
+ tag: REQUEST_TAG.accessResolveActor
7605
+ }), id = usableId(user);
7606
+ return sibling.requireGlobalPrincipal && id !== void 0 && classifyPrincipalId(id).namespace === "project" ? {
7607
+ user: void 0,
7608
+ reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
7609
+ } : {
7610
+ user: user
7611
+ };
7612
+ } catch (err) {
7613
+ return {
7614
+ user: void 0,
7615
+ reason: `global-host /users/me failed: ${errorMessage(err)}`,
7616
+ cause: err
7617
+ };
7618
+ }
7619
+ }
7620
+
7621
+ function globalHostRequestOf(client) {
7622
+ if (typeof client.withConfig != "function") return {
7623
+ reason: "the client cannot reach the global API host (no withConfig)"
7624
+ };
7625
+ const hostResolution = resolveGlobalApiHost(client);
7626
+ try {
7627
+ const globalClient = client.withConfig({
7628
+ useProjectHostname: !1,
7629
+ apiVersion: ENGINE_API_VERSION,
7630
+ ...hostResolution.apiHost === void 0 ? {} : {
7631
+ apiHost: hostResolution.apiHost
7632
+ }
7633
+ }), request = lazyRequest(globalClient);
7634
+ return request === void 0 ? {
7635
+ reason: "the global-host sibling client cannot issue requests"
7636
+ } : {
7637
+ request: request,
7638
+ requireGlobalPrincipal: hostResolution.requireGlobalPrincipal
7639
+ };
7640
+ } catch (err) {
7641
+ return {
7642
+ reason: `building the global-host sibling client failed: ${errorMessage(err)}`,
7643
+ cause: err
7644
+ };
7645
+ }
7646
+ }
7647
+
7648
+ function resolveGlobalApiHost(client) {
7649
+ if (typeof client.config != "function") return {
7650
+ requireGlobalPrincipal: !1
7651
+ };
7652
+ const apiHost = client.config().apiHost;
7653
+ if (apiHost === void 0) return {
7654
+ requireGlobalPrincipal: !1
7655
+ };
7656
+ let parsed;
7657
+ try {
7658
+ parsed = new URL(apiHost);
7659
+ } catch {
7660
+ return {
7661
+ requireGlobalPrincipal: !0
7662
+ };
7663
+ }
7664
+ if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
7665
+ requireGlobalPrincipal: !1
7666
+ };
7667
+ const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
7668
+ return match === null ? {
7669
+ requireGlobalPrincipal: !0
7670
+ } : (parsed.hostname = `api.sanity.${match[1]}`, {
7671
+ apiHost: parsed.origin,
7672
+ requireGlobalPrincipal: !0
7673
+ });
7674
+ }
7675
+
7676
+ async function fetchGrantsCached(requestFn, resourcePath) {
7677
+ try {
7678
+ return await fetchGrants({
7679
+ client: {
7680
+ request: requestFn
7681
+ },
7682
+ resourcePath: resourcePath
7683
+ });
7684
+ } catch (err) {
7685
+ 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: ${errorMessage(err)}`);
7686
+ return;
7687
+ }
7688
+ }
7689
+
7690
+ function projectIdOf(client) {
7691
+ if (typeof client.config != "function") return;
7692
+ const projectId = client.config().projectId;
7693
+ return typeof projectId == "string" && projectId.length > 0 ? projectId : void 0;
7694
+ }
7695
+
7696
+ function cachedAttributes(args) {
7697
+ const projectId = projectIdOf(args.client);
7698
+ return projectId === void 0 ? Promise.resolve(void 0) : resolveOrganizationId({
7699
+ client: args.client,
7700
+ requestFn: args.requestFn,
7701
+ projectId: projectId
7702
+ }).then(orgId => {
7703
+ if (orgId !== void 0) return cachedByKey({
7704
+ store: attributesCache,
7705
+ client: args.client,
7706
+ key: orgId,
7707
+ evictOnRejection: !0,
7708
+ load: () => fetchAttributesCached({
7709
+ client: args.client,
7710
+ orgId: orgId
7711
+ })
7712
+ });
7713
+ });
7714
+ }
7715
+
7716
+ async function resolveOrganizationId(args) {
7717
+ const {client: client, requestFn: requestFn, projectId: projectId} = args;
7718
+ return cachedByKey({
7719
+ store: orgIdCache,
7720
+ client: client,
7721
+ key: projectId,
7722
+ evictOnRejection: !0,
7723
+ load: async () => {
7724
+ try {
7725
+ const project = await requestFn({
7726
+ uri: `/projects/${encodeURIComponent(projectId)}`,
7727
+ tag: REQUEST_TAG.accessResolveOrg
7728
+ });
7729
+ if (!isRecord(project)) return;
7730
+ const orgId = project.organizationId;
7731
+ return typeof orgId == "string" && orgId.length > 0 ? orgId : void 0;
7732
+ } catch (err) {
7733
+ const status = httpStatusOf(err);
7734
+ if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
7735
+ throw new Error(`workflow: failed to resolve organizationId for project "${projectId}"; advisory $attributes cannot be bound. Original error: ${errorMessage(err)}`, {
7736
+ cause: err
7737
+ });
7738
+ }
7739
+ }
7740
+ });
7741
+ }
7742
+
7743
+ const ATTRIBUTES_FETCH_LIMIT = 100, EXPECTED_ATTRIBUTES_ABSENCE = /* @__PURE__ */ new Set([ 401, 402, 403, 404 ]);
7744
+
7745
+ function httpStatusOf(err) {
7746
+ if (!isRecord(err)) return;
7747
+ const status = err.statusCode;
7748
+ return typeof status == "number" ? status : void 0;
7749
+ }
7750
+
7751
+ async function fetchAttributesCached(args) {
7752
+ const {client: client, orgId: orgId} = args, sibling = globalHostRequestOf(client);
7753
+ if ("reason" in sibling) {
7754
+ console.warn(`workflow: skipped org attributes fetch (${sibling.reason}); advisory $attributes stays undefined (conditions referencing it fail closed).`);
7755
+ return;
7756
+ }
7757
+ try {
7758
+ const response = await sibling.request({
7759
+ uri: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
7760
+ tag: REQUEST_TAG.accessAttributes
7761
+ }), envelope = isRecord(response) ? response : void 0;
7762
+ if (envelope?.hasMore === !0) {
7763
+ const page = Array.isArray(envelope.attributes) ? envelope.attributes : [];
7764
+ 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.`);
7765
+ }
7766
+ const normalized = normalizeUserAttributes(response);
7767
+ return normalized === void 0 && console.warn(`workflow: org attributes response for organization "${orgId}" was unusable; advisory $attributes stays undefined (conditions referencing it fail closed).`),
7768
+ normalized;
7769
+ } catch (err) {
7770
+ const status = httpStatusOf(err);
7771
+ if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
7772
+ throw new Error(`workflow: failed to fetch org attributes for organization "${orgId}". Original error: ${errorMessage(err)}`, {
7773
+ cause: err
7774
+ });
7775
+ }
7776
+ }
7777
+
7778
+ function callerBoundVars(args) {
7779
+ const vars = {
7780
+ ...args.can !== void 0 ? {
7781
+ can: args.can
7782
+ } : {},
7783
+ ...args.attributes !== void 0 ? {
7784
+ attributes: args.attributes
7785
+ } : {}
7786
+ };
7787
+ return Object.keys(vars).length > 0 ? vars : void 0;
7788
+ }
7789
+
7790
+ async function callerBoundVarsForCall(args) {
7791
+ const can = await advisoryCanForCall({
7792
+ instance: args.instance,
7793
+ options: args.options
7794
+ }), attributes = args.options?.attributes !== void 0 ? args.options.attributes : await resolveUserAttributes(args.client);
7795
+ return callerBoundVars({
7796
+ ...can !== void 0 ? {
7797
+ can: can
7798
+ } : {},
7799
+ ...attributes !== void 0 ? {
7800
+ attributes: attributes
7801
+ } : {}
7802
+ });
7803
+ }
7804
+
7805
+ function requirementDescriptor(requirement) {
7806
+ return {
7807
+ name: requirement.name,
7808
+ ...requirement.title !== void 0 ? {
7809
+ title: requirement.title
7810
+ } : {},
7811
+ ...requirement.description !== void 0 ? {
7812
+ description: requirement.description
7813
+ } : {}
7814
+ };
7815
+ }
7816
+
7817
+ function subjectDenialLabels(denied) {
7818
+ return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
7819
+ }
7820
+
7821
+ class ActionDisabledError extends WorkflowError {
7822
+ reason;
7823
+ activity;
7824
+ action;
7825
+ constructor(args) {
7826
+ super("action-disabled", formatDisabledReason({
7827
+ activity: args.activity,
7828
+ action: args.action,
7829
+ reason: args.reason
7830
+ })), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
7831
+ this.action = args.action;
7832
+ }
7833
+ }
7834
+
7835
+ class StartNotAllowedError extends WorkflowError {
7836
+ definition;
7837
+ unmetRequirements;
7838
+ constructor(args) {
7839
+ super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
7840
+ this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
7841
+ }
7842
+ }
7843
+
7844
+ function actionRendering(action) {
7845
+ const kind = action.disabledReason?.kind;
7846
+ return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
7847
+ }
7848
+
7849
+ const disabledReasonDetail = {
7850
+ "filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
7851
+ "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`,
7852
+ "activity-not-active": r => `activity status is "${r.status}"`,
6964
7853
  "stage-terminal": r => `stage "${r.stage}" is terminal`,
6965
7854
  "instance-completed": r => `instance completed at ${r.completedAt}`,
6966
7855
  "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
@@ -7033,7 +7922,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7033
7922
  }
7034
7923
  });
7035
7924
  if (action.filter !== void 0) {
7036
- const can = await advisoryCanForCall({
7925
+ const vars = await callerBoundVarsForCall({
7926
+ client: ctx.client,
7037
7927
  instance: ctx.instance,
7038
7928
  options: options
7039
7929
  });
@@ -7045,10 +7935,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7045
7935
  ...actor !== void 0 ? {
7046
7936
  actor: actor
7047
7937
  } : {},
7048
- ...can !== void 0 ? {
7049
- vars: {
7050
- can: can
7051
- }
7938
+ ...vars !== void 0 ? {
7939
+ vars: vars
7052
7940
  } : {}
7053
7941
  }
7054
7942
  })) throw new ActionDisabledError({
@@ -8303,340 +9191,97 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
8303
9191
  if (validatedOps.length === 0) throw new EffectOpsInvalidError({
8304
9192
  effect: pending.name,
8305
9193
  issues: [ "a mid-dispatch report must carry at least one field op — there is nothing to commit" ]
8306
- });
8307
- const mutation = startMutation(ctx.instance);
8308
- return recordProcessedRequest({
8309
- mutation: mutation,
8310
- record: requestRecord,
8311
- now: ctx.now
8312
- }), renewClaimLease({
8313
- mutation: mutation,
8314
- effectKey: effectKey,
8315
- now: ctx.now,
8316
- leaseMs: leaseMs
8317
- }), await runOps({
8318
- ops: validatedOps,
8319
- mutation: mutation,
8320
- stage: ctx.instance.currentStage,
8321
- origin: {
8322
- effect: pending.name
8323
- },
8324
- params: pending.params,
8325
- actor: ctx.actor,
8326
- self: selfGdr(ctx.instance),
8327
- now: ctx.now,
8328
- snapshot: ctx.snapshot,
8329
- refSurface: ctx.refSurface
8330
- }), await persistThenMaybeRefresh({
8331
- ctx: ctx,
8332
- mutation: mutation,
8333
- stageName: ctx.instance.currentStage,
8334
- didChangeState: !0
8335
- }), {
8336
- effectKey: effectKey,
8337
- effect: pending.name
8338
- };
8339
- }
8340
-
8341
- const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8342
-
8343
- function isResetActivityTarget(value) {
8344
- return RESET_ACTIVITY_TARGETS.includes(value);
8345
- }
8346
-
8347
- async function resetActivity(args) {
8348
- const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8349
- client: client,
8350
- instanceId: instanceId,
8351
- options: options
8352
- });
8353
- return commitResetActivity({
8354
- ctx: ctx,
8355
- activity: activity,
8356
- to: to,
8357
- requestRecord: requestRecord,
8358
- actor: options?.actor
8359
- });
8360
- }
8361
-
8362
- async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
8363
- if (assertRequestUnprocessed({
8364
- instance: ctx.instance,
8365
- record: requestRecord,
8366
- now: ctx.now
8367
- }), isTerminal(ctx)) return {
8368
- fired: !1
8369
- };
8370
- const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
8371
- if (openStage2 === void 0 || entry === void 0) throw new ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
8372
- const from = entry.status;
8373
- if (from === to) return {
8374
- fired: !1
8375
- };
8376
- if (!isTerminalActivityStatus(from)) throw new 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.`);
8377
- return recordProcessedRequest({
8378
- mutation: mutation,
8379
- record: requestRecord,
8380
- now: ctx.now
8381
- }), applyActivityStatusChange({
8382
- entry: entry,
8383
- history: mutation.history,
8384
- stage: openStage2.name,
8385
- to: to,
8386
- at: ctx.now,
8387
- ...actor !== void 0 ? {
8388
- actor: actor
8389
- } : {}
8390
- }), await persist(ctx, mutation), {
8391
- fired: !0,
8392
- stage: openStage2.name,
8393
- activity: activity,
8394
- from: from,
8395
- to: to
8396
- };
8397
- }
8398
-
8399
- const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
8400
-
8401
- async function resolveAccess(taggedClient, args = {}) {
8402
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8403
- if (requestFn === void 0) throw new 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).");
8404
- const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
8405
- client: client,
8406
- requestFn: requestFn,
8407
- resourcePath: args.grantsFromPath
8408
- }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
8409
- if (identity === void 0) throw new ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
8410
- return {
8411
- actor: identity.actor,
8412
- ...identity.localPrincipalId !== void 0 ? {
8413
- localPrincipalId: identity.localPrincipalId
8414
- } : {},
8415
- ...grants !== void 0 ? {
8416
- grants: grants
8417
- } : {}
8418
- };
8419
- }
8420
-
8421
- function cachedActor(client, requestFn) {
8422
- const cached = actorCache.get(client);
8423
- if (cached !== void 0) return cached;
8424
- const pending = fetchActor(client, requestFn).catch(err => {
8425
- throw actorCache.get(client) === pending && actorCache.delete(client), err;
8426
- });
8427
- return actorCache.set(client, pending), pending;
8428
- }
8429
-
8430
- function grantsForClientPath(taggedClient, resourcePath) {
8431
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8432
- return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
8433
- client: client,
8434
- requestFn: requestFn,
8435
- resourcePath: resourcePath
8436
- });
8437
- }
8438
-
8439
- function lazyRequest(client) {
8440
- return client.request === void 0 ? void 0 : opts => client.request(opts);
8441
- }
8442
-
8443
- function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
8444
- let byPath = grantsCache.get(client);
8445
- byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
8446
- let cached = byPath.get(resourcePath);
8447
- return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
8448
- byPath.set(resourcePath, cached)), cached;
8449
- }
8450
-
8451
- async function fetchActor(client, requestFn) {
8452
- const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
8453
- if (sessionId === void 0) return;
8454
- const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
8455
- client: client,
8456
- sessionId: sessionId,
8457
- resourceId: resourceId
8458
- }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
8459
- refuseProjectScopedActor({
8460
- id: id,
8461
- globalUser: globalUser,
8462
- globalHostId: globalHostId,
8463
- bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
8464
- });
8465
- const roleNames = roleNamesFor(resourceUser, globalUser);
8466
- return {
8467
- actor: {
8468
- kind: "person",
8469
- id: id,
8470
- ...roleNames.length > 0 ? {
8471
- roles: roleNames
8472
- } : {}
9194
+ });
9195
+ const mutation = startMutation(ctx.instance);
9196
+ return recordProcessedRequest({
9197
+ mutation: mutation,
9198
+ record: requestRecord,
9199
+ now: ctx.now
9200
+ }), renewClaimLease({
9201
+ mutation: mutation,
9202
+ effectKey: effectKey,
9203
+ now: ctx.now,
9204
+ leaseMs: leaseMs
9205
+ }), await runOps({
9206
+ ops: validatedOps,
9207
+ mutation: mutation,
9208
+ stage: ctx.instance.currentStage,
9209
+ origin: {
9210
+ effect: pending.name
8473
9211
  },
8474
- ...resourceId !== void 0 && resourceId !== id ? {
8475
- localPrincipalId: resourceId
8476
- } : {}
9212
+ params: pending.params,
9213
+ actor: ctx.actor,
9214
+ self: selfGdr(ctx.instance),
9215
+ now: ctx.now,
9216
+ snapshot: ctx.snapshot,
9217
+ refSurface: ctx.refSurface
9218
+ }), await persistThenMaybeRefresh({
9219
+ ctx: ctx,
9220
+ mutation: mutation,
9221
+ stageName: ctx.instance.currentStage,
9222
+ didChangeState: !0
9223
+ }), {
9224
+ effectKey: effectKey,
9225
+ effect: pending.name
8477
9226
  };
8478
9227
  }
8479
9228
 
8480
- function roleNamesFor(resourceUser, globalUser) {
8481
- return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8482
- }
8483
-
8484
- const NO_BRIDGE = {
8485
- status: "not-applicable"
8486
- };
9229
+ const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8487
9230
 
8488
- function globalRouteReason(globalUser, globalHostId) {
8489
- return "reason" in globalUser ? globalUser.reason : globalHostId === void 0 ? "no record" : `the global host answered with project-scoped principal "${globalHostId}"`;
9231
+ function isResetActivityTarget(value) {
9232
+ return RESET_ACTIVITY_TARGETS.includes(value);
8490
9233
  }
8491
9234
 
8492
- async function bridgeProjectPrincipal(args) {
8493
- const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
8494
- return classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || classifyPrincipalId(resourceId).namespace !== "project" ? {
8495
- status: "unavailable",
8496
- reason: "no project-scoped principal from the resource host to address the directory with"
8497
- } : directoryGlobalId({
9235
+ async function resetActivity(args) {
9236
+ const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8498
9237
  client: client,
8499
- principalId: resourceId
9238
+ instanceId: instanceId,
9239
+ options: options
8500
9240
  });
8501
- }
8502
-
8503
- async function directoryGlobalId(args) {
8504
- const {client: client, principalId: principalId} = args, projectId = typeof client.config == "function" ? client.config().projectId : void 0;
8505
- if (projectId === void 0) return {
8506
- status: "unavailable",
8507
- reason: "the client reports no projectId, so its user directory has no address"
8508
- };
8509
- const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
8510
- if (lookup.status !== "resolved") return {
8511
- status: "unavailable",
8512
- reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
8513
- ...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
8514
- cause: lookup.cause
8515
- } : {}
8516
- };
8517
- const globalId = directoryBridgeId(lookup.user.sanityUserId);
8518
- return globalId === void 0 ? {
8519
- status: "unavailable",
8520
- reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
8521
- } : {
8522
- status: "resolved",
8523
- globalId: globalId
8524
- };
8525
- }
8526
-
8527
- function refuseProjectScopedActor(args) {
8528
- const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
8529
- if (classifyPrincipalId(id).namespace !== "project") return;
8530
- const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
8531
- bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
8532
- const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
8533
- 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 : {
8534
- cause: cause
9241
+ return commitResetActivity({
9242
+ ctx: ctx,
9243
+ activity: activity,
9244
+ to: to,
9245
+ requestRecord: requestRecord,
9246
+ actor: options?.actor
8535
9247
  });
8536
9248
  }
8537
9249
 
8538
- function usableId(user) {
8539
- if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
8540
- }
8541
-
8542
- async function fetchCurrentUser(requestFn, hostDescription) {
8543
- try {
8544
- return await requestFn({
8545
- uri: "/users/me",
8546
- tag: REQUEST_TAG.accessResolveActor
8547
- });
8548
- } catch (err) {
8549
- 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.`, {
8550
- cause: err
8551
- });
8552
- }
8553
- }
8554
-
8555
- async function fetchGlobalUser(client) {
8556
- if (typeof client.withConfig != "function") return {
8557
- user: void 0,
8558
- reason: "the client cannot reach the global API host (no withConfig)"
8559
- };
8560
- let globalRequest, globalClient;
8561
- const hostResolution = resolveGlobalApiHost(client);
8562
- try {
8563
- globalClient = client.withConfig({
8564
- useProjectHostname: !1,
8565
- ...hostResolution.apiHost === void 0 ? {} : {
8566
- apiHost: hostResolution.apiHost
8567
- }
8568
- }), globalRequest = lazyRequest(globalClient);
8569
- } catch (err) {
8570
- return {
8571
- user: void 0,
8572
- reason: `building the global-host sibling client failed: ${errorMessage(err)}`,
8573
- cause: err
8574
- };
8575
- }
8576
- if (globalRequest === void 0) return {
8577
- user: void 0,
8578
- reason: "the global-host sibling client cannot issue requests"
8579
- };
8580
- try {
8581
- const user = await globalRequest({
8582
- uri: "/users/me",
8583
- tag: REQUEST_TAG.accessResolveActor
8584
- }), id = usableId(user);
8585
- return hostResolution.requireGlobalPrincipal && id !== void 0 && classifyPrincipalId(id).namespace === "project" ? {
8586
- user: void 0,
8587
- reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
8588
- } : {
8589
- user: user
8590
- };
8591
- } catch (err) {
8592
- return {
8593
- user: void 0,
8594
- reason: `global-host /users/me failed: ${errorMessage(err)}`,
8595
- cause: err
8596
- };
8597
- }
8598
- }
8599
-
8600
- function resolveGlobalApiHost(client) {
8601
- if (typeof client.config != "function") return {
8602
- requireGlobalPrincipal: !1
9250
+ async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
9251
+ if (assertRequestUnprocessed({
9252
+ instance: ctx.instance,
9253
+ record: requestRecord,
9254
+ now: ctx.now
9255
+ }), isTerminal(ctx)) return {
9256
+ fired: !1
8603
9257
  };
8604
- const apiHost = client.config().apiHost;
8605
- if (apiHost === void 0) return {
8606
- requireGlobalPrincipal: !1
9258
+ const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
9259
+ if (openStage2 === void 0 || entry === void 0) throw new ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
9260
+ const from = entry.status;
9261
+ if (from === to) return {
9262
+ fired: !1
8607
9263
  };
8608
- let parsed;
8609
- try {
8610
- parsed = new URL(apiHost);
8611
- } catch {
8612
- return {
8613
- requireGlobalPrincipal: !0
8614
- };
8615
- }
8616
- if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
8617
- requireGlobalPrincipal: !1
9264
+ if (!isTerminalActivityStatus(from)) throw new 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.`);
9265
+ return recordProcessedRequest({
9266
+ mutation: mutation,
9267
+ record: requestRecord,
9268
+ now: ctx.now
9269
+ }), applyActivityStatusChange({
9270
+ entry: entry,
9271
+ history: mutation.history,
9272
+ stage: openStage2.name,
9273
+ to: to,
9274
+ at: ctx.now,
9275
+ ...actor !== void 0 ? {
9276
+ actor: actor
9277
+ } : {}
9278
+ }), await persist(ctx, mutation), {
9279
+ fired: !0,
9280
+ stage: openStage2.name,
9281
+ activity: activity,
9282
+ from: from,
9283
+ to: to
8618
9284
  };
8619
- const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
8620
- return match === null ? {
8621
- requireGlobalPrincipal: !0
8622
- } : (parsed.hostname = `api.sanity.${match[1]}`, {
8623
- apiHost: parsed.origin,
8624
- requireGlobalPrincipal: !0
8625
- });
8626
- }
8627
-
8628
- async function fetchGrantsCached(requestFn, resourcePath) {
8629
- try {
8630
- return await fetchGrants({
8631
- client: {
8632
- request: requestFn
8633
- },
8634
- resourcePath: resourcePath
8635
- });
8636
- } catch (err) {
8637
- 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: ${errorMessage(err)}`);
8638
- return;
8639
- }
8640
9285
  }
8641
9286
 
8642
9287
  const REPLAY_SURFACE = {
@@ -8820,7 +9465,7 @@ async function resourceActorId(client) {
8820
9465
  async function evaluateInstance(args) {
8821
9466
  const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
8822
9467
  validateTag(tag);
8823
- const [access, instance] = await Promise.all([ resolveAccess(client, {
9468
+ const [access, instance, attributes] = await Promise.all([ resolveAccess(client, {
8824
9469
  ...args.grantsFromPath !== void 0 ? {
8825
9470
  grantsFromPath: args.grantsFromPath
8826
9471
  } : {}
@@ -8828,7 +9473,7 @@ async function evaluateInstance(args) {
8828
9473
  client: client,
8829
9474
  instanceId: instanceId,
8830
9475
  tag: tag
8831
- }) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
9476
+ }), resolveUserAttributes(client) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
8832
9477
  client: client,
8833
9478
  workflowResource: workflowResource,
8834
9479
  resourceClients: resourceClients
@@ -8853,6 +9498,9 @@ async function evaluateInstance(args) {
8853
9498
  } : {},
8854
9499
  ...grants !== void 0 ? {
8855
9500
  grants: grants
9501
+ } : {},
9502
+ ...attributes !== void 0 ? {
9503
+ attributes: attributes
8856
9504
  } : {}
8857
9505
  });
8858
9506
  }
@@ -8867,6 +9515,33 @@ function memoizedByName(render) {
8867
9515
  };
8868
9516
  }
8869
9517
 
9518
+ async function callerBoundProjectionScopes(args) {
9519
+ const can = await advisoryCan({
9520
+ instance: args.instance,
9521
+ identity: args.identity,
9522
+ grants: args.grants
9523
+ }), vars = callerBoundVars({
9524
+ ...can !== void 0 ? {
9525
+ can: can
9526
+ } : {},
9527
+ ...args.attributes !== void 0 ? {
9528
+ attributes: args.attributes
9529
+ } : {}
9530
+ }), opts = {
9531
+ actor: args.actor,
9532
+ ...vars !== void 0 ? {
9533
+ vars: vars
9534
+ } : {}
9535
+ };
9536
+ return {
9537
+ scope: await renderConditionScope(args.scopeSource, opts),
9538
+ scopeForActivity: memoizedByName(activityName => renderConditionScope(args.scopeSource, {
9539
+ activityName: activityName,
9540
+ ...opts
9541
+ }))
9542
+ };
9543
+ }
9544
+
8870
9545
  function currentStageOf(instance, definition) {
8871
9546
  try {
8872
9547
  return findStage(definition, instance.currentStage);
@@ -8892,7 +9567,7 @@ async function explainSite(args) {
8892
9567
  }
8893
9568
 
8894
9569
  async function evaluateFromSnapshot(args) {
8895
- 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({
9570
+ 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({
8896
9571
  instance: instance,
8897
9572
  definition: definition,
8898
9573
  snapshot: snapshot,
@@ -8909,22 +9584,14 @@ async function evaluateFromSnapshot(args) {
8909
9584
  }, anchorIdentity = lakePrincipalId({
8910
9585
  actor: actor,
8911
9586
  localPrincipalId: args.localPrincipalId
8912
- }), can = await advisoryCan({
8913
- instance: instance,
8914
- identity: anchorIdentity,
8915
- grants: grants
8916
- }), scope = await renderConditionScope(scopeSource, {
8917
- actor: actor,
8918
- vars: {
8919
- can: can
8920
- }
8921
- }), scopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
8922
- activityName: activityName,
9587
+ }), {scope: scope, scopeForActivity: scopeForActivity} = await callerBoundProjectionScopes({
9588
+ scopeSource: scopeSource,
8923
9589
  actor: actor,
8924
- vars: {
8925
- can: can
8926
- }
8927
- })), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
9590
+ instance: instance,
9591
+ grants: grants,
9592
+ attributes: attributes,
9593
+ identity: anchorIdentity
9594
+ }), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
8928
9595
  activityName: activityName
8929
9596
  })), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
8930
9597
  instance: instance,
@@ -8973,6 +9640,7 @@ async function evaluateFromSnapshot(args) {
8973
9640
  }
8974
9641
  const currentStage = {
8975
9642
  stage: stage,
9643
+ ...semanticsOf(stage),
8976
9644
  activities: activityEvaluations,
8977
9645
  transitions: transitionEvaluations,
8978
9646
  autonomy: stageAutonomy2
@@ -8989,6 +9657,7 @@ async function evaluateFromSnapshot(args) {
8989
9657
  return {
8990
9658
  instance: instance,
8991
9659
  definition: definition,
9660
+ ...semanticsOf(definition),
8992
9661
  actor: actor,
8993
9662
  currentStage: currentStage,
8994
9663
  pendingOnYou: pendingOnYou,
@@ -9144,6 +9813,7 @@ async function evaluateActivity(args) {
9144
9813
  }));
9145
9814
  return {
9146
9815
  activity: activity,
9816
+ ...semanticsOf(activity),
9147
9817
  status: status,
9148
9818
  kind: deriveActivityKind(activity),
9149
9819
  classification: deriveExecutorClassification(activity),
@@ -9314,9 +9984,13 @@ function fireableActionVerdict({args: args, insights: insights}) {
9314
9984
  function actionEvaluationIdentity(action) {
9315
9985
  return {
9316
9986
  action: action,
9317
- ...action.semantics !== void 0 ? {
9318
- semantics: action.semantics
9319
- } : {}
9987
+ ...semanticsOf(action)
9988
+ };
9989
+ }
9990
+
9991
+ function semanticsOf(node) {
9992
+ return node.semantics === void 0 ? {} : {
9993
+ semantics: node.semantics
9320
9994
  };
9321
9995
  }
9322
9996
 
@@ -9795,7 +10469,8 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
9795
10469
  }
9796
10470
 
9797
10471
  async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
9798
- const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
10472
+ const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), vars = await callerBoundVarsForCall({
10473
+ client: ctx.client,
9799
10474
  instance: ctx.instance,
9800
10475
  options: options
9801
10476
  }), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
@@ -9808,10 +10483,8 @@ async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
9808
10483
  ...actor !== void 0 ? {
9809
10484
  actor: actor
9810
10485
  } : {},
9811
- ...can !== void 0 ? {
9812
- vars: {
9813
- can: can
9814
- }
10486
+ ...vars !== void 0 ? {
10487
+ vars: vars
9815
10488
  } : {}
9816
10489
  }
9817
10490
  }) : site.effective === !0, reason = editDisabledReason({
@@ -10301,6 +10974,9 @@ function buildEngineCallOptions(args) {
10301
10974
  ...args.grants !== void 0 ? {
10302
10975
  grants: args.grants
10303
10976
  } : {},
10977
+ ...args.attributes !== void 0 ? {
10978
+ attributes: args.attributes
10979
+ } : {},
10304
10980
  ...args.clock !== void 0 ? {
10305
10981
  clock: args.clock
10306
10982
  } : {},
@@ -12059,7 +12735,7 @@ function createInstanceSession(args) {
12059
12735
  refSurface: evalScope.refSurface
12060
12736
  });
12061
12737
  }, evaluateWith = async ({held: held, guards: guards, self: self}) => {
12062
- const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
12738
+ const [{actor: actor, localPrincipalId: localPrincipalId, grants: grants}, attributes] = await Promise.all([ access(), resolveUserAttributes(client) ]), resourceGrants = await subjectResourceGrants({
12063
12739
  clientForGdr: evalScope.clientForGdr,
12064
12740
  instance: instance
12065
12741
  }), normalizedSelf = await normalizeInstanceIdentities({
@@ -12081,6 +12757,9 @@ function createInstanceSession(args) {
12081
12757
  } : {},
12082
12758
  ...grants !== void 0 ? {
12083
12759
  grants: grants
12760
+ } : {},
12761
+ ...attributes !== void 0 ? {
12762
+ attributes: attributes
12084
12763
  } : {}
12085
12764
  });
12086
12765
  }, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope}) => {
@@ -12776,7 +13455,7 @@ const HISTORY_DISPLAY = {
12776
13455
  },
12777
13456
  opApplied: {
12778
13457
  title: "Op applied",
12779
- description: "An inline field-mutation op (field.set / field.append / status.set / etc.) ran during an action commit."
13458
+ description: "An action, direct edit, or effect completion executed an operation and recorded its audit payload."
12780
13459
  },
12781
13460
  fieldQueryDiscarded: {
12782
13461
  title: "Query result discarded",
@@ -12881,6 +13560,10 @@ const HISTORY_DISPLAY = {
12881
13560
  title: "Set field entry",
12882
13561
  description: "Overwrite a field entry's value with a resolved value expression."
12883
13562
  },
13563
+ "field.setIfMissing": {
13564
+ title: "Set field entry if missing",
13565
+ 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."
13566
+ },
12884
13567
  "field.unset": {
12885
13568
  title: "Unset field entry",
12886
13569
  description: "Reset a field entry to its default (null for scalars, [] for array kinds)."
@@ -12889,6 +13572,14 @@ const HISTORY_DISPLAY = {
12889
13572
  title: "Append to field entry",
12890
13573
  description: "Push a resolved item onto an array-kind entry (array, assignees, doc.refs)."
12891
13574
  },
13575
+ "field.inc": {
13576
+ title: "Increment field entry",
13577
+ description: "Add a resolved numeric delta, defaulting to 1, to a number entry that already holds a finite number."
13578
+ },
13579
+ "field.dec": {
13580
+ title: "Decrement field entry",
13581
+ description: "Subtract a resolved numeric delta, defaulting to 1, from a number entry that already holds a finite number."
13582
+ },
12892
13583
  "field.updateWhere": {
12893
13584
  title: "Update matching rows",
12894
13585
  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)."
@@ -13002,4 +13693,4 @@ function displayDescription(typeKey) {
13002
13693
  if (typeKey) return DISPLAY[typeKey]?.description;
13003
13694
  }
13004
13695
 
13005
- export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, ANONYMOUS_IDENTITY, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DRIVER_KINDS, DRIVER_KIND_DISPLAY, DefinitionInUseError, DefinitionNotFoundError, EFFECT_COMMIT_DISPATCH_CAP, EFFECT_COMMIT_QUEUE_DEPTH, ENGINE_API_VERSION, EXECUTION_KINDS, EXECUTOR_CLASSIFICATIONS, EXECUTOR_CLASSIFICATION_DISPLAY, EditFieldDeniedError, EffectCommitQueueOverflowError, EffectNotFoundError, EffectOpsInvalidError, EffectOutputsInvalidError, FIELD_KIND_DISPLAY, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GROUP_KIND_DISPLAY, GUARD_DOC_TYPE, GUARD_OWNER, GUARD_PREDICATE_VARS, HISTORY_DISPLAY, InitialFieldsInvalidError, InstanceNotFoundError, MAX_COUNTERFACTUAL_INDEX2 as MAX_COUNTERFACTUAL_INDEX, MissingHandlerError, ModelVersionAheadError, MutationGuardDeniedError, MutationGuardDocSchema, NEUTRAL_MARK, OP_DISPLAY, OUTCOME_MARKS, PartialGuardDeployError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, RefResourceUndeclaredError, RequiredFieldNotProvidedError, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StaleEffectClaimError, StartNotAllowedError, StartNotPrimedError, StartNotSettledError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowActionFired, WorkflowActivityReset, WorkflowDefinitionDeleted, WorkflowDefinitionDeployed, WorkflowEffectCompleted, WorkflowEffectStateReported, WorkflowEffectsDrained, WorkflowError, WorkflowFieldEdited, WorkflowInstanceAborted, WorkflowInstanceSchema, WorkflowInstanceStarted, WorkflowInstanceTicked, WorkflowStageSet, WorkflowStageTransitioned, WorkflowStateDivergedError, abortReason, acceptsDocumentType, aclPathForResource, actionDisabledDetail, actionRendering, actionVerdict, activityAutonomyOf, analyzeCondition2 as analyzeCondition, applicableDefinitions, assertReadableModel, assertReaderModelAcknowledgement, atomReadsDataset2 as atomReadsDataset, autonomySummary, availableActions, buildInitialFields, buildSnapshot, checklistLines, classifyPrincipalId, clientConfigFromResource, clientProjectUserDirectory, compileGuard, computeDiffEntries, conditionFieldReadNames, conditionSitesOf, contentDocQuery, contentDraftFallback, contentReleaseName, contextMap, createEngine, createTelemetryIntake, datasetResourceParts, defaultLoggerFactory, definitionDeployedData, definitionLookupGroq, definitionTagsGroq, definitionsListGroq, deniedGuardLabels, deniedGuardRefs, denyingGuards, deployStageGuards, deployedTagsGroq, deriveActivityKind, deriveExecutorClassification, deriveWorkflowAutonomy, describeAtom, describeAutonomyWait, describeCondition, describeDefinition, describeFieldInsight, describeNode, describeSite, describeSiteHeading, diagnoseInputFromEvaluation, diagnoseInstance, diffEntry, displayDescription, displayTitle, documentActionDenials, documentPrefilter, driverKind, effectOutputsMap, entryDocRefs, errorMessage, evaluateFromSnapshot, evaluateMutationGuard, evaluateStartFilter, expandResourceAliases, explainCondition2 as explainCondition, explainStartRequirement, extractDocumentId, fieldTreeShape, findCurrentActivityEntry, findOpenStageEntry, formatRead, gdrFromResource, gdrRef, gdrUri, groupMembershipNames, groupSitesOf, guardMatches, guardsForDefinition, guardsForInstance, guardsForResource, guillemets2 as guillemets, hasSingleSubjectRequirement, hashDefinitionContent, humanize2 as humanize, inFlightFilter, initialFieldIssues, instanceDocId, instanceGuardQuery, instanceWatchesDocument, instancesGuardQuery, instancesQuery, isCascadeFired, isClaimExpired, isClientProjectUser, isComparisonOp, isDefinitionApplicable, isFilterScopedOut, isGdr, isInputSourced, isNotesEntry, isProjectUserNotFoundError, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTelemetryEnvDenied, isTerminalActivityStatus, isTerminalStage, isTodoListEntry, isTodoListItem, isUnprimed, lakeGuardId, lakePrincipalId, latestDefinitionsGroq, latestDeployedDefinitions, lintEffectOutputs, minReaderModelOf, missingRequiredInputs, modelVersionOf, narrateAutonomyWaits, noopTelemetry, parentRef, parseDefinitionInput, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseGdr, parseGuardDocument, parseInstanceDocument, parseResourceGdr, processShellUserProperties, projectStartSliceRow, projectToWatchRef, quoted2 as quoted, readInstanceDoc, readsRaw, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refsOf, rejectedRefTypes, releaseDocId, releaseRef, remediationsFor, requiredModelFeatures, requiredReaderModel, resolveAccess, resolveActor, resolveClientActor, resolveFieldEntry$1 as resolveFieldEntry, resourceAliasesToMap, resourceFromParsed, resourceGdr, retractStageGuards, sameResource, scalarValidationIssues, schemaTreeShape, sentenceCase, silentLogger, singleSubjectRequirementRefused, stageAutonomyOf, startFieldsParam, startKindOf, startRefusal, stripSystemFields, subjectDenialLabels, subscriptionDocument, subscriptionDocumentsForInstance, sweepStaleClaims, tagScopeFilter, terminalState, toBareId, tryParseGdr, unboundRequirementReads, unsatisfiedTransitionSummaries, userLoginProvider, validateDefinition, validateTag, verdictGuardsForInstance, wallClock, whatIfCondition2 as whatIfCondition, withAssignment, workflow };
13696
+ export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, ANONYMOUS_IDENTITY, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DECISION_SEMANTICS, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DRIVER_KINDS, DRIVER_KIND_DISPLAY, DefinitionInUseError, DefinitionNotFoundError, EFFECT_COMMIT_DISPATCH_CAP, EFFECT_COMMIT_QUEUE_DEPTH, ENGINE_API_VERSION, EXECUTION_KINDS, EXECUTOR_CLASSIFICATIONS, EXECUTOR_CLASSIFICATION_DISPLAY, EditFieldDeniedError, EffectCommitQueueOverflowError, EffectNotFoundError, EffectOpsInvalidError, EffectOutputsInvalidError, FIELD_KIND_DISPLAY, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GROUP_KIND_DISPLAY, GUARD_DOC_TYPE, GUARD_OWNER, GUARD_PREDICATE_VARS, HISTORY_DISPLAY, InitialFieldsInvalidError, InstanceNotFoundError, MAX_COUNTERFACTUAL_INDEX2 as MAX_COUNTERFACTUAL_INDEX, MissingHandlerError, ModelVersionAheadError, MutationGuardDeniedError, MutationGuardDocSchema, NEUTRAL_MARK, OP_DISPLAY, OUTCOME_MARKS, PartialGuardDeployError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, RefResourceUndeclaredError, RequiredFieldNotProvidedError, SIGNAL_SEMANTICS, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StaleEffectClaimError, StartNotAllowedError, StartNotPrimedError, StartNotSettledError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowActionFired, WorkflowActivityReset, WorkflowDefinitionDeleted, WorkflowDefinitionDeployed, WorkflowEffectCompleted, WorkflowEffectStateReported, WorkflowEffectsDrained, WorkflowError, WorkflowFieldEdited, WorkflowInstanceAborted, WorkflowInstanceSchema, WorkflowInstanceStarted, WorkflowInstanceTicked, WorkflowStageSet, WorkflowStageTransitioned, WorkflowStateDivergedError, abortReason, acceptsDocumentType, aclPathForResource, actionDisabledDetail, actionRendering, actionVerdict, activityAutonomyOf, analyzeCondition2 as analyzeCondition, applicableDefinitions, assertReadableModel, assertReaderModelAcknowledgement, atomReadsDataset2 as atomReadsDataset, autonomySummary, availableActions, buildInitialFields, buildSnapshot, checklistLines, classifyPrincipalId, clientConfigFromResource, clientProjectUserDirectory, compileGuard, computeDiffEntries, conditionFieldReadNames, conditionSitesOf, contentDocQuery, contentDraftFallback, contentReleaseName, contextMap, createEngine, createTelemetryIntake, datasetResourceParts, defaultLoggerFactory, definitionDeployedData, definitionLookupGroq, definitionTagsGroq, definitionsListGroq, deniedGuardLabels, deniedGuardRefs, denyingGuards, deployStageGuards, deployedTagsGroq, deriveActivityKind, deriveExecutorClassification, deriveWorkflowAutonomy, describeAtom, describeAutonomyWait, describeCondition, describeDefinition, describeFieldInsight, describeNode, describeSite, describeSiteHeading, diagnoseInputFromEvaluation, diagnoseInstance, diffEntry, displayDescription, displayTitle, documentActionDenials, documentPrefilter, documentStuckCause, driverKind, effectOutputsMap, entryDocRefs, errorMessage, evaluateFromSnapshot, evaluateMutationGuard, evaluateStartFilter, expandResourceAliases, explainCondition2 as explainCondition, explainStartRequirement, extractDocumentId, fieldTreeShape, findActivityNode, findCurrentActivityEntry, findOpenStageEntry, findStageNode, formatRead, gdrFromResource, gdrRef, gdrUri, groupMembershipNames, groupSitesOf, guardMatches, guardsForDefinition, guardsForInstance, guardsForResource, guillemets2 as guillemets, hasSingleSubjectRequirement, hashDefinitionContent, humanize2 as humanize, inFlightFilter, initialFieldIssues, instanceDocId, instanceGuardQuery, instanceWatchesDocument, instancesGuardQuery, instancesQuery, isCascadeFired, isClaimExpired, isClientProjectUser, isComparisonOp, isDefinitionApplicable, isFilterScopedOut, isGdr, isInputSourced, isNotesEntry, isProjectUserNotFoundError, isRevisionConflict, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTelemetryEnvDenied, isTerminalActivityStatus, isTerminalStage, isTodoListEntry, isTodoListItem, isUnprimed, lakeGuardId, lakePrincipalId, latestDefinitionsGroq, latestDeployedDefinitions, lintEffectOutputs, minReaderModelOf, missingRequiredInputs, modelVersionOf, narrateAutonomyWaits, noopTelemetry, parentRef, parseDefinitionInput, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseGdr, parseGuardDocument, parseInstanceDocument, parseResourceGdr, processShellUserProperties, projectStartSliceRow, projectToWatchRef, quoted2 as quoted, readInstanceDoc, readsRaw, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refsOf, rejectedRefTypes, releaseDocId, releaseRef, remediationsFor, requiredModelFeatures, requiredReaderModel, resolveAccess, resolveActor, resolveClientActor, resolveFieldEntry$1 as resolveFieldEntry, resolveUserAttributes, resourceAliasesToMap, resourceFromParsed, resourceGdr, retractStageGuards, sameResource, scalarValidationIssues, schemaTreeShape, sentenceCase, silentLogger, singleSubjectRequirementRefused, stageAutonomyOf, startFieldsParam, startKindOf, startRefusal, stripSystemFields, subjectDenialLabels, subscriptionDocument, subscriptionDocumentsForInstance, sweepStaleClaims, tagScopeFilter, terminalState, toBareId, tryParseGdr, unboundRequirementReads, unsatisfiedTransitionSummaries, userLoginProvider, validateDefinition, validateTag, verdictGuardsForInstance, wallClock, whatIfCondition2 as whatIfCondition, withAssignment, workflow };