@sanity/workflow-engine 0.28.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 { 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, 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, driverKind, EffectNotFoundError, firstCarriedGlobalId, deriveExecutorClassification, validateTag, extractDocumentId, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, DefinitionInUseError, 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, DEFAULT_TRANSITION_WHEN, EXECUTOR_CLASSIFICATIONS, FILTER_SCOPE_VARS, GROUP_KINDS, GUARD_PREDICATE_VARS, PersistedDocShapeError, RESERVED_CONDITION_VARS, SYSTEM_IDENTITY, clientConfigFromResource, gdrUri, isNotesEntry, isTodoListEntry, isTodoListItem, parseResourceGdr, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, releaseDocId, releaseRef, 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
 
@@ -435,7 +435,7 @@ function fieldEditedData(args) {
435
435
  };
436
436
  }
437
437
 
438
- const DATA_MODEL_VERSION = 5, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
438
+ const DATA_MODEL_VERSION = 7, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
439
439
 
440
440
  class ReaderModelAcknowledgementError extends WorkflowError {
441
441
  code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
@@ -485,7 +485,7 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
485
485
  documentTypes: Object.freeze([ "definition" ]),
486
486
  compatibility: "additive",
487
487
  applicability: "detectable",
488
- summary: "Ordinary actions may carry a closed bag of advisory workflow semantics."
488
+ summary: "Ordinary actions may carry advisory workflow semantics."
489
489
  }), Object.freeze({
490
490
  id: "inclusive-scalar-bounds",
491
491
  introducedInModel: 2,
@@ -534,6 +534,30 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
534
534
  compatibility: "additive",
535
535
  applicability: "detectable",
536
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)."
537
561
  }) ]);
538
562
 
539
563
  function recordOf(value) {
@@ -556,13 +580,34 @@ function parsedDefinitionSnapshot(root) {
556
580
  }));
557
581
  }
558
582
 
559
- function persistedFieldEntries(document) {
583
+ function persistedDefinitionTree(document) {
560
584
  const root = recordOf(document);
561
- if (root === void 0) return [];
562
- const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], stages = roots.flatMap(candidate => recordsAt(candidate, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions")), effects = actions.flatMap(action => recordsAt(action, "effects"));
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"));
563
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")) ]);
564
600
  }
565
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
+
566
611
  function hasChoiceList(document) {
567
612
  return persistedFieldEntries(document).some(entry => {
568
613
  const options = recordOf(entry.options);
@@ -574,9 +619,34 @@ function hasFieldKind(document, kind) {
574
619
  return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
575
620
  }
576
621
 
577
- function hasActionSemantics(document) {
622
+ function definitionNodes(document) {
578
623
  const root = recordOf(document);
579
- return root === void 0 ? !1 : recordsAt(root, "stages").flatMap(stage => recordsAt(stage, "activities")).flatMap(activity => recordsAt(activity, "actions")).some(action => Array.isArray(action.semantics));
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)));
580
650
  }
581
651
 
582
652
  function hasScalarValidation(document) {
@@ -609,7 +679,10 @@ const featureDetectors = {
609
679
  "effect-claim-tokens": hasClaimTokens,
610
680
  "classified-principal-ids": () => !0,
611
681
  "readiness-requirements": hasReadinessRequirements,
612
- "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime")
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
613
686
  };
614
687
 
615
688
  function requiredModelFeatures(documentType, document) {
@@ -1143,12 +1216,8 @@ function renderWorkflowRead(read, ctx) {
1143
1216
  text: guillemets(title)
1144
1217
  });
1145
1218
  }
1146
- if (read.variable === "can" && typeof read.path[0] == "string") return phrase("read.permission", {
1147
- params: {
1148
- permission: read.path[0]
1149
- },
1150
- text: `your ${read.path[0]} permission`
1151
- });
1219
+ const keyed = keyedCallerRead(read);
1220
+ if (keyed !== void 0) return keyed;
1152
1221
  if (read.variable === "actor" && read.path.length === 1 && read.path[0] === "id") return phrase("read.actor-id", {
1153
1222
  params: {},
1154
1223
  text: "your id"
@@ -1170,6 +1239,24 @@ function renderWorkflowRead(read, ctx) {
1170
1239
  });
1171
1240
  }
1172
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
+
1173
1260
  function workflowRequirement(requirement, ctx) {
1174
1261
  const {target: target} = requirement, clause = clauseVarRequirement(requirement);
1175
1262
  if (clause !== void 0) return clause;
@@ -2070,6 +2157,10 @@ function derefBase(ref, snapshot) {
2070
2157
  };
2071
2158
  }
2072
2159
 
2160
+ function isRecord(value) {
2161
+ return typeof value == "object" && value !== null && !Array.isArray(value);
2162
+ }
2163
+
2073
2164
  function buildParams(args) {
2074
2165
  const {instance: instance, now: now, snapshot: snapshot, extra: extra} = args, currentActivities2 = findOpenStageEntry(instance)?.activities ?? [];
2075
2166
  return {
@@ -2597,7 +2688,7 @@ class CascadeLimitError extends WorkflowError {
2597
2688
  }
2598
2689
  }
2599
2690
 
2600
- 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" ];
2601
2692
 
2602
2693
  function isFieldOp(summary) {
2603
2694
  return FIELD_OP_TYPES.includes(summary.opType);
@@ -2698,7 +2789,7 @@ async function runOps(args) {
2698
2789
  refSurface: refSurface,
2699
2790
  opsFromDefinition: opsFromDefinition
2700
2791
  });
2701
- summaries.push(summary), mutation.history.push(opAppliedEntry({
2792
+ summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
2702
2793
  origin: origin,
2703
2794
  summary: summary,
2704
2795
  stage: stage,
@@ -2709,6 +2800,10 @@ async function runOps(args) {
2709
2800
  return summaries;
2710
2801
  }
2711
2802
 
2803
+ function shouldRecordOpApplied(summary) {
2804
+ return summary.opType !== "field.setIfMissing" || summary.resolved !== void 0;
2805
+ }
2806
+
2712
2807
  function opAppliedEntry(args) {
2713
2808
  const {origin: origin, summary: summary, stage: stage, actor: actor, now: now} = args;
2714
2809
  return {
@@ -2780,12 +2875,19 @@ async function applyOp(op, ctx) {
2780
2875
  case "field.set":
2781
2876
  return applyFieldSet(op, ctx);
2782
2877
 
2878
+ case "field.setIfMissing":
2879
+ return applyFieldSetIfMissing(op, ctx);
2880
+
2783
2881
  case "field.unset":
2784
2882
  return applyFieldUnset(op, ctx);
2785
2883
 
2786
2884
  case "field.append":
2787
2885
  return applyFieldAppend(op, ctx);
2788
2886
 
2887
+ case "field.inc":
2888
+ case "field.dec":
2889
+ return applyFieldArithmetic(op, ctx);
2890
+
2789
2891
  case "field.updateWhere":
2790
2892
  return applyFieldUpdateWhere(op, ctx);
2791
2893
 
@@ -2824,6 +2926,78 @@ function applyFieldSet(op, ctx) {
2824
2926
  };
2825
2927
  }
2826
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
+
2827
3001
  function entryShape(entry) {
2828
3002
  return entry._type === "object" ? {
2829
3003
  fields: entry.fields
@@ -2859,15 +3033,9 @@ function appendItemSlot(entry) {
2859
3033
  };
2860
3034
  }
2861
3035
 
2862
- const EMPTY_BY_KIND = {
2863
- "doc.refs": [],
2864
- array: [],
2865
- assignees: []
2866
- };
2867
-
2868
3036
  function applyFieldUnset(op, ctx) {
2869
3037
  const entry = locateEntry(ctx, op.target);
2870
- return setEntryValue(entry, EMPTY_BY_KIND[entry._type] ?? null), {
3038
+ return setEntryValue(entry, isAlwaysArrayFieldKind(entry._type) ? [] : null), {
2871
3039
  opType: op.type,
2872
3040
  target: op.target
2873
3041
  };
@@ -2906,7 +3074,7 @@ function applyFieldAppend(op, ctx) {
2906
3074
  }
2907
3075
 
2908
3076
  function withRowKey(item) {
2909
- return typeof item == "object" && item !== null && !Array.isArray(item) && !("_key" in item) ? {
3077
+ return isRecord(item) && !("_key" in item) ? {
2910
3078
  _key: randomKey(),
2911
3079
  ...item
2912
3080
  } : item;
@@ -3605,6 +3773,14 @@ function latestDeployedDefinitions(rows) {
3605
3773
  return [ ...byName.values() ];
3606
3774
  }
3607
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
+
3608
3784
  function liveChildrenField(instance) {
3609
3785
  const live = liveSubworkflows(instance).length;
3610
3786
  return live > 0 ? {
@@ -3693,6 +3869,27 @@ function noTransitionFiresCause(input) {
3693
3869
  };
3694
3870
  }
3695
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
+
3696
3893
  function diagnoseInstance(input) {
3697
3894
  const {instance: instance} = input, terminal = terminalState(instance);
3698
3895
  if (terminal === "aborted" && instance.abortedAt !== void 0) {
@@ -3711,7 +3908,7 @@ function diagnoseInstance(input) {
3711
3908
  at: instance.completedAt,
3712
3909
  ...liveChildrenField(instance)
3713
3910
  };
3714
- const cause = failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input) ?? noTransitionFiresCause(input);
3911
+ const cause = stuckFromDocumentState(input) ?? noTransitionFiresCause(input);
3715
3912
  return cause !== void 0 ? {
3716
3913
  state: "stuck",
3717
3914
  cause: cause
@@ -4090,10 +4287,8 @@ function assertRequiredInputProvided({entryDefs: entryDefs, initialFields: initi
4090
4287
  });
4091
4288
  }
4092
4289
 
4093
- const ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([ "doc.refs", "array", "assignees" ]);
4094
-
4095
4290
  function defaultEntryValue(entryType) {
4096
- return ARRAY_FIELD_TYPES.has(entryType) ? [] : null;
4291
+ return isAlwaysArrayFieldKind(entryType) ? [] : null;
4097
4292
  }
4098
4293
 
4099
4294
  function resolveInputValue({entry: entry, initialFields: initialFields, defaultValue: defaultValue}) {
@@ -4694,7 +4889,9 @@ const SYNC_COMMIT = {
4694
4889
  effect: "workflow.effect",
4695
4890
  verifyDefinitions: "workflow.verify-definitions",
4696
4891
  accessResolveActor: "workflow.access.resolve-actor",
4697
- accessGrants: "workflow.access.grants"
4892
+ accessGrants: "workflow.access.grants",
4893
+ accessResolveOrg: "workflow.access.resolve-org",
4894
+ accessAttributes: "workflow.access.attributes"
4698
4895
  }, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
4699
4896
 
4700
4897
  function unwrapPatch(patch) {
@@ -5662,10 +5859,6 @@ function userLoginProvider(user) {
5662
5859
  return user?.provider ?? user?.loginProvider;
5663
5860
  }
5664
5861
 
5665
- function isRecord(value) {
5666
- return typeof value == "object" && value !== null && !Array.isArray(value);
5667
- }
5668
-
5669
5862
  function optionalString(value) {
5670
5863
  return value === void 0 || typeof value == "string";
5671
5864
  }
@@ -7202,117 +7395,524 @@ async function advisoryCan({instance: instance, identity: identity, grants: gran
7202
7395
  return can;
7203
7396
  }
7204
7397
 
7205
- function requirementDescriptor(requirement) {
7206
- return {
7207
- name: requirement.name,
7208
- ...requirement.title !== void 0 ? {
7209
- title: requirement.title
7210
- } : {},
7211
- ...requirement.description !== void 0 ? {
7212
- description: requirement.description
7213
- } : {}
7214
- };
7215
- }
7398
+ const DANGEROUS_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([ "__proto__", "constructor", "prototype" ]);
7216
7399
 
7217
- function subjectDenialLabels(denied) {
7218
- return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
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 ];
7219
7402
  }
7220
7403
 
7221
- class ActionDisabledError extends WorkflowError {
7222
- reason;
7223
- activity;
7224
- action;
7225
- constructor(args) {
7226
- super("action-disabled", formatDisabledReason({
7227
- activity: args.activity,
7228
- action: args.action,
7229
- reason: args.reason
7230
- })), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
7231
- this.action = args.action;
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]);
7232
7412
  }
7413
+ return out;
7233
7414
  }
7234
7415
 
7235
- class StartNotAllowedError extends WorkflowError {
7236
- definition;
7237
- unmetRequirements;
7238
- constructor(args) {
7239
- super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
7240
- this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
7241
- }
7242
- }
7416
+ const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap, orgIdCache = /* @__PURE__ */ new WeakMap, attributesCache = /* @__PURE__ */ new WeakMap;
7243
7417
 
7244
- function actionRendering(action) {
7245
- const kind = action.disabledReason?.kind;
7246
- return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
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.");
7427
+ return {
7428
+ actor: identity.actor,
7429
+ ...identity.localPrincipalId !== void 0 ? {
7430
+ localPrincipalId: identity.localPrincipalId
7431
+ } : {},
7432
+ ...grants !== void 0 ? {
7433
+ grants: grants
7434
+ } : {}
7435
+ };
7247
7436
  }
7248
7437
 
7249
- const disabledReasonDetail = {
7250
- "filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
7251
- "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`,
7252
- "activity-not-active": r => `activity status is "${r.status}"`,
7253
- "stage-terminal": r => `stage "${r.stage}" is terminal`,
7254
- "instance-completed": r => `instance completed at ${r.completedAt}`,
7255
- "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
7256
- "requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
7257
- "subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
7258
- };
7259
-
7260
- function actionDisabledDetail(reason) {
7261
- return disabledReasonDetail[reason.kind](reason);
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
+ });
7262
7444
  }
7263
7445
 
7264
- function formatDisabledReason({activity: activity, action: action, reason: reason}) {
7265
- return `Action "${activity}:${action}" is not allowed: ${actionDisabledDetail(reason)}`;
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;
7266
7453
  }
7267
7454
 
7268
- class EditFieldDeniedError extends WorkflowError {
7269
- reason;
7270
- target;
7271
- constructor(args) {
7272
- super("edit-field-denied", formatEditDisabledReason(args.target, args.reason)),
7273
- this.name = "EditFieldDeniedError", this.reason = args.reason, this.target = args.target;
7274
- }
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
+ });
7275
7462
  }
7276
7463
 
7277
- const editDisabledReasonDetail = {
7278
- "not-editable": () => "field is not declared editable",
7279
- "instance-completed": r => `instance completed at ${r.completedAt}`,
7280
- "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
7281
- "edit-window-closed": r => `edit window closed (${r.detail})`,
7282
- "editor-not-permitted": r => `editor not permitted (${r.predicate})`
7283
- };
7284
-
7285
- function formatEditDisabledReason(target, reason) {
7286
- const detail = editDisabledReasonDetail[reason.kind](reason), where = target.activity !== void 0 ? `${target.activity}.${target.field}` : target.field;
7287
- return `Field "${target.scope}:${where}" is not editable: ${detail}`;
7464
+ function lazyRequest(client) {
7465
+ return client.request === void 0 ? void 0 : opts => client.request(opts);
7288
7466
  }
7289
7467
 
7290
- async function fireAction(args) {
7291
- const {client: client, instanceId: instanceId, activity: activity, action: action, params: params, requestRecord: requestRecord, options: options} = args;
7292
- return retryOnRevisionConflict({
7468
+ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
7469
+ return cachedByKey({
7470
+ store: grantsCache,
7293
7471
  client: client,
7294
- instanceId: instanceId,
7295
- options: options,
7296
- commit: ctx => commitAction({
7297
- ctx: ctx,
7298
- activityName: activity,
7299
- actionName: action,
7300
- callerParams: params,
7301
- requestRecord: requestRecord,
7302
- options: options
7303
- }),
7304
- onExhausted: () => new ConcurrentFireActionError({
7305
- instanceId: instanceId,
7306
- activity: activity,
7307
- action: action,
7308
- attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
7309
- })
7472
+ key: resourcePath,
7473
+ load: () => fetchGrantsCached(requestFn, resourcePath)
7310
7474
  });
7311
7475
  }
7312
7476
 
7313
- async function resolveActionCommit({ctx: ctx, activityName: activityName, actionName: actionName, callerParams: callerParams, options: options}) {
7314
- const actor = options?.actor, {stage: stage, activity: activity} = findActivityInCurrentStage(ctx, activityName), action = (activity.actions ?? []).find(a => a.name === actionName);
7315
- if (action === void 0) throw new ContractViolationError(`Action "${actionName}" not declared on activity "${activityName}"`);
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}"`,
7853
+ "stage-terminal": r => `stage "${r.stage}" is terminal`,
7854
+ "instance-completed": r => `instance completed at ${r.completedAt}`,
7855
+ "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
7856
+ "requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
7857
+ "subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
7858
+ };
7859
+
7860
+ function actionDisabledDetail(reason) {
7861
+ return disabledReasonDetail[reason.kind](reason);
7862
+ }
7863
+
7864
+ function formatDisabledReason({activity: activity, action: action, reason: reason}) {
7865
+ return `Action "${activity}:${action}" is not allowed: ${actionDisabledDetail(reason)}`;
7866
+ }
7867
+
7868
+ class EditFieldDeniedError extends WorkflowError {
7869
+ reason;
7870
+ target;
7871
+ constructor(args) {
7872
+ super("edit-field-denied", formatEditDisabledReason(args.target, args.reason)),
7873
+ this.name = "EditFieldDeniedError", this.reason = args.reason, this.target = args.target;
7874
+ }
7875
+ }
7876
+
7877
+ const editDisabledReasonDetail = {
7878
+ "not-editable": () => "field is not declared editable",
7879
+ "instance-completed": r => `instance completed at ${r.completedAt}`,
7880
+ "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
7881
+ "edit-window-closed": r => `edit window closed (${r.detail})`,
7882
+ "editor-not-permitted": r => `editor not permitted (${r.predicate})`
7883
+ };
7884
+
7885
+ function formatEditDisabledReason(target, reason) {
7886
+ const detail = editDisabledReasonDetail[reason.kind](reason), where = target.activity !== void 0 ? `${target.activity}.${target.field}` : target.field;
7887
+ return `Field "${target.scope}:${where}" is not editable: ${detail}`;
7888
+ }
7889
+
7890
+ async function fireAction(args) {
7891
+ const {client: client, instanceId: instanceId, activity: activity, action: action, params: params, requestRecord: requestRecord, options: options} = args;
7892
+ return retryOnRevisionConflict({
7893
+ client: client,
7894
+ instanceId: instanceId,
7895
+ options: options,
7896
+ commit: ctx => commitAction({
7897
+ ctx: ctx,
7898
+ activityName: activity,
7899
+ actionName: action,
7900
+ callerParams: params,
7901
+ requestRecord: requestRecord,
7902
+ options: options
7903
+ }),
7904
+ onExhausted: () => new ConcurrentFireActionError({
7905
+ instanceId: instanceId,
7906
+ activity: activity,
7907
+ action: action,
7908
+ attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
7909
+ })
7910
+ });
7911
+ }
7912
+
7913
+ async function resolveActionCommit({ctx: ctx, activityName: activityName, actionName: actionName, callerParams: callerParams, options: options}) {
7914
+ const actor = options?.actor, {stage: stage, activity: activity} = findActivityInCurrentStage(ctx, activityName), action = (activity.actions ?? []).find(a => a.name === actionName);
7915
+ if (action === void 0) throw new ContractViolationError(`Action "${actionName}" not declared on activity "${activityName}"`);
7316
7916
  if (action.when !== void 0) throw new ActionDisabledError({
7317
7917
  activity: activityName,
7318
7918
  action: actionName,
@@ -7322,7 +7922,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7322
7922
  }
7323
7923
  });
7324
7924
  if (action.filter !== void 0) {
7325
- const can = await advisoryCanForCall({
7925
+ const vars = await callerBoundVarsForCall({
7926
+ client: ctx.client,
7326
7927
  instance: ctx.instance,
7327
7928
  options: options
7328
7929
  });
@@ -7334,10 +7935,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
7334
7935
  ...actor !== void 0 ? {
7335
7936
  actor: actor
7336
7937
  } : {},
7337
- ...can !== void 0 ? {
7338
- vars: {
7339
- can: can
7340
- }
7938
+ ...vars !== void 0 ? {
7939
+ vars: vars
7341
7940
  } : {}
7342
7941
  }
7343
7942
  })) throw new ActionDisabledError({
@@ -8592,340 +9191,97 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
8592
9191
  if (validatedOps.length === 0) throw new EffectOpsInvalidError({
8593
9192
  effect: pending.name,
8594
9193
  issues: [ "a mid-dispatch report must carry at least one field op — there is nothing to commit" ]
8595
- });
8596
- const mutation = startMutation(ctx.instance);
8597
- return recordProcessedRequest({
8598
- mutation: mutation,
8599
- record: requestRecord,
8600
- now: ctx.now
8601
- }), renewClaimLease({
8602
- mutation: mutation,
8603
- effectKey: effectKey,
8604
- now: ctx.now,
8605
- leaseMs: leaseMs
8606
- }), await runOps({
8607
- ops: validatedOps,
8608
- mutation: mutation,
8609
- stage: ctx.instance.currentStage,
8610
- origin: {
8611
- effect: pending.name
8612
- },
8613
- params: pending.params,
8614
- actor: ctx.actor,
8615
- self: selfGdr(ctx.instance),
8616
- now: ctx.now,
8617
- snapshot: ctx.snapshot,
8618
- refSurface: ctx.refSurface
8619
- }), await persistThenMaybeRefresh({
8620
- ctx: ctx,
8621
- mutation: mutation,
8622
- stageName: ctx.instance.currentStage,
8623
- didChangeState: !0
8624
- }), {
8625
- effectKey: effectKey,
8626
- effect: pending.name
8627
- };
8628
- }
8629
-
8630
- const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8631
-
8632
- function isResetActivityTarget(value) {
8633
- return RESET_ACTIVITY_TARGETS.includes(value);
8634
- }
8635
-
8636
- async function resetActivity(args) {
8637
- const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8638
- client: client,
8639
- instanceId: instanceId,
8640
- options: options
8641
- });
8642
- return commitResetActivity({
8643
- ctx: ctx,
8644
- activity: activity,
8645
- to: to,
8646
- requestRecord: requestRecord,
8647
- actor: options?.actor
8648
- });
8649
- }
8650
-
8651
- async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
8652
- if (assertRequestUnprocessed({
8653
- instance: ctx.instance,
8654
- record: requestRecord,
8655
- now: ctx.now
8656
- }), isTerminal(ctx)) return {
8657
- fired: !1
8658
- };
8659
- const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
8660
- if (openStage2 === void 0 || entry === void 0) throw new ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
8661
- const from = entry.status;
8662
- if (from === to) return {
8663
- fired: !1
8664
- };
8665
- 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.`);
8666
- return recordProcessedRequest({
8667
- mutation: mutation,
8668
- record: requestRecord,
8669
- now: ctx.now
8670
- }), applyActivityStatusChange({
8671
- entry: entry,
8672
- history: mutation.history,
8673
- stage: openStage2.name,
8674
- to: to,
8675
- at: ctx.now,
8676
- ...actor !== void 0 ? {
8677
- actor: actor
8678
- } : {}
8679
- }), await persist(ctx, mutation), {
8680
- fired: !0,
8681
- stage: openStage2.name,
8682
- activity: activity,
8683
- from: from,
8684
- to: to
8685
- };
8686
- }
8687
-
8688
- const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
8689
-
8690
- async function resolveAccess(taggedClient, args = {}) {
8691
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8692
- 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).");
8693
- const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
8694
- client: client,
8695
- requestFn: requestFn,
8696
- resourcePath: args.grantsFromPath
8697
- }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
8698
- 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.");
8699
- return {
8700
- actor: identity.actor,
8701
- ...identity.localPrincipalId !== void 0 ? {
8702
- localPrincipalId: identity.localPrincipalId
8703
- } : {},
8704
- ...grants !== void 0 ? {
8705
- grants: grants
8706
- } : {}
8707
- };
8708
- }
8709
-
8710
- function cachedActor(client, requestFn) {
8711
- const cached = actorCache.get(client);
8712
- if (cached !== void 0) return cached;
8713
- const pending = fetchActor(client, requestFn).catch(err => {
8714
- throw actorCache.get(client) === pending && actorCache.delete(client), err;
8715
- });
8716
- return actorCache.set(client, pending), pending;
8717
- }
8718
-
8719
- function grantsForClientPath(taggedClient, resourcePath) {
8720
- const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8721
- return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
8722
- client: client,
8723
- requestFn: requestFn,
8724
- resourcePath: resourcePath
8725
- });
8726
- }
8727
-
8728
- function lazyRequest(client) {
8729
- return client.request === void 0 ? void 0 : opts => client.request(opts);
8730
- }
8731
-
8732
- function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
8733
- let byPath = grantsCache.get(client);
8734
- byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
8735
- let cached = byPath.get(resourcePath);
8736
- return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
8737
- byPath.set(resourcePath, cached)), cached;
8738
- }
8739
-
8740
- async function fetchActor(client, requestFn) {
8741
- 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;
8742
- if (sessionId === void 0) return;
8743
- const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
8744
- client: client,
8745
- sessionId: sessionId,
8746
- resourceId: resourceId
8747
- }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
8748
- refuseProjectScopedActor({
8749
- id: id,
8750
- globalUser: globalUser,
8751
- globalHostId: globalHostId,
8752
- bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
8753
- });
8754
- const roleNames = roleNamesFor(resourceUser, globalUser);
8755
- return {
8756
- actor: {
8757
- kind: "person",
8758
- id: id,
8759
- ...roleNames.length > 0 ? {
8760
- roles: roleNames
8761
- } : {}
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
8762
9211
  },
8763
- ...resourceId !== void 0 && resourceId !== id ? {
8764
- localPrincipalId: resourceId
8765
- } : {}
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
8766
9226
  };
8767
9227
  }
8768
9228
 
8769
- function roleNamesFor(resourceUser, globalUser) {
8770
- return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8771
- }
8772
-
8773
- const NO_BRIDGE = {
8774
- status: "not-applicable"
8775
- };
9229
+ const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8776
9230
 
8777
- function globalRouteReason(globalUser, globalHostId) {
8778
- 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);
8779
9233
  }
8780
9234
 
8781
- async function bridgeProjectPrincipal(args) {
8782
- const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
8783
- return classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || classifyPrincipalId(resourceId).namespace !== "project" ? {
8784
- status: "unavailable",
8785
- reason: "no project-scoped principal from the resource host to address the directory with"
8786
- } : directoryGlobalId({
9235
+ async function resetActivity(args) {
9236
+ const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8787
9237
  client: client,
8788
- principalId: resourceId
9238
+ instanceId: instanceId,
9239
+ options: options
8789
9240
  });
8790
- }
8791
-
8792
- async function directoryGlobalId(args) {
8793
- const {client: client, principalId: principalId} = args, projectId = typeof client.config == "function" ? client.config().projectId : void 0;
8794
- if (projectId === void 0) return {
8795
- status: "unavailable",
8796
- reason: "the client reports no projectId, so its user directory has no address"
8797
- };
8798
- const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
8799
- if (lookup.status !== "resolved") return {
8800
- status: "unavailable",
8801
- reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
8802
- ...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
8803
- cause: lookup.cause
8804
- } : {}
8805
- };
8806
- const globalId = directoryBridgeId(lookup.user.sanityUserId);
8807
- return globalId === void 0 ? {
8808
- status: "unavailable",
8809
- reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
8810
- } : {
8811
- status: "resolved",
8812
- globalId: globalId
8813
- };
8814
- }
8815
-
8816
- function refuseProjectScopedActor(args) {
8817
- const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
8818
- if (classifyPrincipalId(id).namespace !== "project") return;
8819
- const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
8820
- bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
8821
- const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
8822
- 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 : {
8823
- cause: cause
9241
+ return commitResetActivity({
9242
+ ctx: ctx,
9243
+ activity: activity,
9244
+ to: to,
9245
+ requestRecord: requestRecord,
9246
+ actor: options?.actor
8824
9247
  });
8825
9248
  }
8826
9249
 
8827
- function usableId(user) {
8828
- if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
8829
- }
8830
-
8831
- async function fetchCurrentUser(requestFn, hostDescription) {
8832
- try {
8833
- return await requestFn({
8834
- uri: "/users/me",
8835
- tag: REQUEST_TAG.accessResolveActor
8836
- });
8837
- } catch (err) {
8838
- 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.`, {
8839
- cause: err
8840
- });
8841
- }
8842
- }
8843
-
8844
- async function fetchGlobalUser(client) {
8845
- if (typeof client.withConfig != "function") return {
8846
- user: void 0,
8847
- reason: "the client cannot reach the global API host (no withConfig)"
8848
- };
8849
- let globalRequest, globalClient;
8850
- const hostResolution = resolveGlobalApiHost(client);
8851
- try {
8852
- globalClient = client.withConfig({
8853
- useProjectHostname: !1,
8854
- ...hostResolution.apiHost === void 0 ? {} : {
8855
- apiHost: hostResolution.apiHost
8856
- }
8857
- }), globalRequest = lazyRequest(globalClient);
8858
- } catch (err) {
8859
- return {
8860
- user: void 0,
8861
- reason: `building the global-host sibling client failed: ${errorMessage(err)}`,
8862
- cause: err
8863
- };
8864
- }
8865
- if (globalRequest === void 0) return {
8866
- user: void 0,
8867
- reason: "the global-host sibling client cannot issue requests"
8868
- };
8869
- try {
8870
- const user = await globalRequest({
8871
- uri: "/users/me",
8872
- tag: REQUEST_TAG.accessResolveActor
8873
- }), id = usableId(user);
8874
- return hostResolution.requireGlobalPrincipal && id !== void 0 && classifyPrincipalId(id).namespace === "project" ? {
8875
- user: void 0,
8876
- reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
8877
- } : {
8878
- user: user
8879
- };
8880
- } catch (err) {
8881
- return {
8882
- user: void 0,
8883
- reason: `global-host /users/me failed: ${errorMessage(err)}`,
8884
- cause: err
8885
- };
8886
- }
8887
- }
8888
-
8889
- function resolveGlobalApiHost(client) {
8890
- if (typeof client.config != "function") return {
8891
- 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
8892
9257
  };
8893
- const apiHost = client.config().apiHost;
8894
- if (apiHost === void 0) return {
8895
- 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
8896
9263
  };
8897
- let parsed;
8898
- try {
8899
- parsed = new URL(apiHost);
8900
- } catch {
8901
- return {
8902
- requireGlobalPrincipal: !0
8903
- };
8904
- }
8905
- if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
8906
- 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
8907
9284
  };
8908
- const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
8909
- return match === null ? {
8910
- requireGlobalPrincipal: !0
8911
- } : (parsed.hostname = `api.sanity.${match[1]}`, {
8912
- apiHost: parsed.origin,
8913
- requireGlobalPrincipal: !0
8914
- });
8915
- }
8916
-
8917
- async function fetchGrantsCached(requestFn, resourcePath) {
8918
- try {
8919
- return await fetchGrants({
8920
- client: {
8921
- request: requestFn
8922
- },
8923
- resourcePath: resourcePath
8924
- });
8925
- } catch (err) {
8926
- 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)}`);
8927
- return;
8928
- }
8929
9285
  }
8930
9286
 
8931
9287
  const REPLAY_SURFACE = {
@@ -9109,7 +9465,7 @@ async function resourceActorId(client) {
9109
9465
  async function evaluateInstance(args) {
9110
9466
  const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
9111
9467
  validateTag(tag);
9112
- const [access, instance] = await Promise.all([ resolveAccess(client, {
9468
+ const [access, instance, attributes] = await Promise.all([ resolveAccess(client, {
9113
9469
  ...args.grantsFromPath !== void 0 ? {
9114
9470
  grantsFromPath: args.grantsFromPath
9115
9471
  } : {}
@@ -9117,7 +9473,7 @@ async function evaluateInstance(args) {
9117
9473
  client: client,
9118
9474
  instanceId: instanceId,
9119
9475
  tag: tag
9120
- }) ]), {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({
9121
9477
  client: client,
9122
9478
  workflowResource: workflowResource,
9123
9479
  resourceClients: resourceClients
@@ -9142,6 +9498,9 @@ async function evaluateInstance(args) {
9142
9498
  } : {},
9143
9499
  ...grants !== void 0 ? {
9144
9500
  grants: grants
9501
+ } : {},
9502
+ ...attributes !== void 0 ? {
9503
+ attributes: attributes
9145
9504
  } : {}
9146
9505
  });
9147
9506
  }
@@ -9156,6 +9515,33 @@ function memoizedByName(render) {
9156
9515
  };
9157
9516
  }
9158
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
+
9159
9545
  function currentStageOf(instance, definition) {
9160
9546
  try {
9161
9547
  return findStage(definition, instance.currentStage);
@@ -9181,7 +9567,7 @@ async function explainSite(args) {
9181
9567
  }
9182
9568
 
9183
9569
  async function evaluateFromSnapshot(args) {
9184
- 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({
9185
9571
  instance: instance,
9186
9572
  definition: definition,
9187
9573
  snapshot: snapshot,
@@ -9198,22 +9584,14 @@ async function evaluateFromSnapshot(args) {
9198
9584
  }, anchorIdentity = lakePrincipalId({
9199
9585
  actor: actor,
9200
9586
  localPrincipalId: args.localPrincipalId
9201
- }), can = await advisoryCan({
9202
- instance: instance,
9203
- identity: anchorIdentity,
9204
- grants: grants
9205
- }), scope = await renderConditionScope(scopeSource, {
9206
- actor: actor,
9207
- vars: {
9208
- can: can
9209
- }
9210
- }), scopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
9211
- activityName: activityName,
9587
+ }), {scope: scope, scopeForActivity: scopeForActivity} = await callerBoundProjectionScopes({
9588
+ scopeSource: scopeSource,
9212
9589
  actor: actor,
9213
- vars: {
9214
- can: can
9215
- }
9216
- })), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
9590
+ instance: instance,
9591
+ grants: grants,
9592
+ attributes: attributes,
9593
+ identity: anchorIdentity
9594
+ }), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
9217
9595
  activityName: activityName
9218
9596
  })), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
9219
9597
  instance: instance,
@@ -9262,6 +9640,7 @@ async function evaluateFromSnapshot(args) {
9262
9640
  }
9263
9641
  const currentStage = {
9264
9642
  stage: stage,
9643
+ ...semanticsOf(stage),
9265
9644
  activities: activityEvaluations,
9266
9645
  transitions: transitionEvaluations,
9267
9646
  autonomy: stageAutonomy2
@@ -9278,6 +9657,7 @@ async function evaluateFromSnapshot(args) {
9278
9657
  return {
9279
9658
  instance: instance,
9280
9659
  definition: definition,
9660
+ ...semanticsOf(definition),
9281
9661
  actor: actor,
9282
9662
  currentStage: currentStage,
9283
9663
  pendingOnYou: pendingOnYou,
@@ -9433,6 +9813,7 @@ async function evaluateActivity(args) {
9433
9813
  }));
9434
9814
  return {
9435
9815
  activity: activity,
9816
+ ...semanticsOf(activity),
9436
9817
  status: status,
9437
9818
  kind: deriveActivityKind(activity),
9438
9819
  classification: deriveExecutorClassification(activity),
@@ -9603,9 +9984,13 @@ function fireableActionVerdict({args: args, insights: insights}) {
9603
9984
  function actionEvaluationIdentity(action) {
9604
9985
  return {
9605
9986
  action: action,
9606
- ...action.semantics !== void 0 ? {
9607
- semantics: action.semantics
9608
- } : {}
9987
+ ...semanticsOf(action)
9988
+ };
9989
+ }
9990
+
9991
+ function semanticsOf(node) {
9992
+ return node.semantics === void 0 ? {} : {
9993
+ semantics: node.semantics
9609
9994
  };
9610
9995
  }
9611
9996
 
@@ -10084,7 +10469,8 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
10084
10469
  }
10085
10470
 
10086
10471
  async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
10087
- 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,
10088
10474
  instance: ctx.instance,
10089
10475
  options: options
10090
10476
  }), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
@@ -10097,10 +10483,8 @@ async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
10097
10483
  ...actor !== void 0 ? {
10098
10484
  actor: actor
10099
10485
  } : {},
10100
- ...can !== void 0 ? {
10101
- vars: {
10102
- can: can
10103
- }
10486
+ ...vars !== void 0 ? {
10487
+ vars: vars
10104
10488
  } : {}
10105
10489
  }
10106
10490
  }) : site.effective === !0, reason = editDisabledReason({
@@ -10590,6 +10974,9 @@ function buildEngineCallOptions(args) {
10590
10974
  ...args.grants !== void 0 ? {
10591
10975
  grants: args.grants
10592
10976
  } : {},
10977
+ ...args.attributes !== void 0 ? {
10978
+ attributes: args.attributes
10979
+ } : {},
10593
10980
  ...args.clock !== void 0 ? {
10594
10981
  clock: args.clock
10595
10982
  } : {},
@@ -12348,7 +12735,7 @@ function createInstanceSession(args) {
12348
12735
  refSurface: evalScope.refSurface
12349
12736
  });
12350
12737
  }, evaluateWith = async ({held: held, guards: guards, self: self}) => {
12351
- 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({
12352
12739
  clientForGdr: evalScope.clientForGdr,
12353
12740
  instance: instance
12354
12741
  }), normalizedSelf = await normalizeInstanceIdentities({
@@ -12370,6 +12757,9 @@ function createInstanceSession(args) {
12370
12757
  } : {},
12371
12758
  ...grants !== void 0 ? {
12372
12759
  grants: grants
12760
+ } : {},
12761
+ ...attributes !== void 0 ? {
12762
+ attributes: attributes
12373
12763
  } : {}
12374
12764
  });
12375
12765
  }, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope}) => {
@@ -13065,7 +13455,7 @@ const HISTORY_DISPLAY = {
13065
13455
  },
13066
13456
  opApplied: {
13067
13457
  title: "Op applied",
13068
- 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."
13069
13459
  },
13070
13460
  fieldQueryDiscarded: {
13071
13461
  title: "Query result discarded",
@@ -13170,6 +13560,10 @@ const HISTORY_DISPLAY = {
13170
13560
  title: "Set field entry",
13171
13561
  description: "Overwrite a field entry's value with a resolved value expression."
13172
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
+ },
13173
13567
  "field.unset": {
13174
13568
  title: "Unset field entry",
13175
13569
  description: "Reset a field entry to its default (null for scalars, [] for array kinds)."
@@ -13178,6 +13572,14 @@ const HISTORY_DISPLAY = {
13178
13572
  title: "Append to field entry",
13179
13573
  description: "Push a resolved item onto an array-kind entry (array, assignees, doc.refs)."
13180
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
+ },
13181
13583
  "field.updateWhere": {
13182
13584
  title: "Update matching rows",
13183
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)."
@@ -13291,4 +13693,4 @@ function displayDescription(typeKey) {
13291
13693
  if (typeKey) return DISPLAY[typeKey]?.description;
13292
13694
  }
13293
13695
 
13294
- 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, 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, 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 };