@sanity/workflow-engine 0.32.0 → 0.34.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, findOpenStageEntry, findCurrentActivityEntry, andConditions, deriveActivityKind, CALLER_BOUND_VARS, START_REQUIREMENT_VARS, CONDITION_VARS, isSubjectEntry, isUnevaluable, ContractViolationError, isStartableDefinition, conditionFieldReadNames, isGdr, errorMessage, conditionParameterNames, START_FILTER_VARS, WorkflowError, gdrFromResource, selfGdr, isGdrUri, MUTATION_GUARD_ID_SPACES, mutationGuardActionIdSpace, LAKE_MUTATION_GUARD_ACTIONS, isBareDocumentId, toBareId, normalizeAssignmentMembers, isSingleDocRefKind, actorMatchesAssignment, assignmentMembers, resolvedChildStatus, sameResource, resourceFromParsed, tryParseGdr, isTerminalActivityStatus, FieldValueShapeError, validateFieldValue, validateFieldAppendItem, isAssignmentFieldEntry, isAlwaysArrayFieldKind, evaluateCondition, isRecord, isSingleDocRefEntry, choiceValueIssues, scalarValidationIssues, StoredFieldOpSchema, formatIssues, conditionSyntaxIssues, checkWorkflowInvariants, formatIssuePath, isGuardReadExpr, GUARD_ACTIONS_REQUIRED_MESSAGE, conditionEffectReads, EFFECTS_READ, datasetResourceParts, mutationGuardRequiresSplitEmission, MUTATION_GUARD_ACTIONS, assignmentKindAcceptsRoles, evaluatePredicates, WORKFLOW_DEFINITION_TYPE, tagScopeFilter, liveSubworkflows, isCascadeFired, classifyPrincipalId, directoryBridgeId, parseGdr, gdrRef, isInputSourced, parseFieldValue, VersionSpecificDatasetGdrError, toPhysicalGdr, isBareSeedId, isParseableInstant, NonEmptyString, tolerantEntries, FIELD_VALUE_KINDS, tolerantObject, ActorShape, IsoTimestamp, ACTIVITY_STATUSES, GdrShape, DRIVER_KINDS, FIELD_SCOPES, fieldValueSchemas, parsePersistedDoc, ACTOR_KINDS, InstanceNotFoundError, evaluateConditionOutcome, runGroq as runGroq$1, FIELD_READ, resourceGdr, condemnSubworkflow, resourceFromGdrUri, refTypeIssues, rejectedRefTypes, DOCUMENT_VALUE_PERMISSIONS, lakePrincipalId, firstCarriedGlobalId, driverKind, actorFulfillsRole, condemnedSubworkflows, EffectNotFoundError, isFilterScopedOut, deriveExecutorClassification, validateTag, activeAssignmentMembers, extractDocumentId, UNIVERSAL_ROLE_ALIAS_KEY, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, DefinitionInUseError, groupMembershipNames } from "./_chunks-es/invariants.js";
1
+ import { rethrowWithContext, findOpenStageEntry, findCurrentActivityEntry, andConditions, deriveActivityKind, CALLER_BOUND_VARS, START_REQUIREMENT_VARS, CONDITION_VARS, isSubjectEntry, isUnevaluable, ContractViolationError, isStartableDefinition, conditionFieldReadNames, isGdr, errorMessage, conditionParameterNames, START_FILTER_VARS, WorkflowError, gdrFromResource, selfGdr, isGdrUri, MUTATION_GUARD_ID_SPACES, mutationGuardActionIdSpace, LAKE_MUTATION_GUARD_ACTIONS, isBareDocumentId, toBareId, normalizeAssignmentMembers, isSingleDocRefKind, actorMatchesAssignment, assignmentMembers, resolvedChildStatus, sameResource, resourceFromParsed, tryParseGdr, isTerminalActivityStatus, FieldValueShapeError, validateFieldValue, validateFieldAppendItem, isAssignmentFieldEntry, isAlwaysArrayFieldKind, evaluateCondition, isRecord, isSingleDocRefEntry, choiceValueIssues, scalarValidationIssues, StoredFieldOpSchema, formatIssues, conditionSyntaxIssues, checkWorkflowInvariants, formatIssuePath, isGuardReadExpr, GUARD_ACTIONS_REQUIRED_MESSAGE, conditionEffectReads, EFFECTS_READ, datasetResourceParts, refKindAcceptsTypes, mutationGuardRequiresSplitEmission, MUTATION_GUARD_ACTIONS, assignmentKindAcceptsRoles, evaluatePredicates, WORKFLOW_DEFINITION_TYPE, tagScopeFilter, liveSubworkflows, isCascadeFired, classifyPrincipalId, directoryBridgeId, parseGdr, gdrRef, isInputSourced, parseFieldValue, VersionSpecificDatasetGdrError, toPhysicalGdr, isBareSeedId, isParseableInstant, NonEmptyString, tolerantEntries, FIELD_VALUE_KINDS, tolerantObject, ActorShape, IsoTimestamp, ACTIVITY_STATUSES, GdrShape, DRIVER_KINDS, FIELD_SCOPES, fieldValueSchemas, parsePersistedDoc, ACTOR_KINDS, InstanceNotFoundError, evaluateConditionOutcome, runGroq as runGroq$1, FIELD_READ, resourceGdr, condemnSubworkflow, resourceFromGdrUri, refTypeIssues, rejectedRefTypes, DOCUMENT_VALUE_PERMISSIONS, lakePrincipalId, firstCarriedGlobalId, driverKind, actorFulfillsRole, condemnedSubworkflows, EffectNotFoundError, isFilterScopedOut, deriveExecutorClassification, validateTag, activeAssignmentMembers, extractDocumentId, UNIVERSAL_ROLE_ALIAS_KEY, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, DefinitionInUseError, effectBackoffMs, groupMembershipNames } from "./_chunks-es/invariants.js";
2
2
 
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, assignmentMatch, assignmentState, assignmentStateCounts, clientConfigFromResource, gdrUri, identityMatchesAssignment, instanceAssignmentStateCounts, isNotesEntry, isTodoListEntry, isTodoListItem, openActivityAssignments, 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, assignmentMatch, assignmentState, assignmentStateCounts, clientConfigFromResource, gdrUri, identityMatchesAssignment, instanceAssignmentStateCounts, isNotesEntry, isTodoListEntry, isTodoListItem, openActivityAssignments, parseResourceGdr, readsRootDocument, refCanvas, refDashboard, refDataset, 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, _exhaustiveOptions, whatIfCondition, runGroq, formatRead, dedupeReads, MAX_COUNTERFACTUAL_INDEX } from "@sanity/groq-condition-describe";
6
6
 
@@ -8,7 +8,7 @@ import { MAX_COUNTERFACTUAL_INDEX as MAX_COUNTERFACTUAL_INDEX2, NEUTRAL_MARK, OU
8
8
 
9
9
  import { evaluate, parse } from "groq-js";
10
10
 
11
- import { getPublishedId, getDraftId } from "@sanity/id-utils";
11
+ import { getPublishedId, getDraftId, DocumentId } from "@sanity/id-utils";
12
12
 
13
13
  import * as v from "valibot";
14
14
 
@@ -69,6 +69,10 @@ function effectiveEditable(baseline, override) {
69
69
 
70
70
  const DEFAULT_EDIT_MODE = "set";
71
71
 
72
+ function _fieldTargetLabel(target) {
73
+ return [ target.scope, target.activity, target.field ].filter(Boolean).join(".");
74
+ }
75
+
72
76
  function fieldSites(definition, stage) {
73
77
  const sites = [];
74
78
  for (const entry of definition.fields ?? []) sites.push({
@@ -1045,6 +1049,7 @@ function describeSiteHeading(address, ctx) {
1045
1049
  }
1046
1050
 
1047
1051
  case "action":
1052
+ case "action-when":
1048
1053
  {
1049
1054
  const title = actionTitle(address, ctx), activity = activityTitle(address.activity, ctx);
1050
1055
  return phrase(id, {
@@ -1052,7 +1057,7 @@ function describeSiteHeading(address, ctx) {
1052
1057
  title: title,
1053
1058
  activity: activity
1054
1059
  },
1055
- text: `action ${quoted(title)} on ${quoted(activity)} is available when:`
1060
+ text: `action ${quoted(title)} on ${quoted(activity)} ${address.kind === "action" ? "is available" : "fires automatically"} when:`
1056
1061
  });
1057
1062
  }
1058
1063
 
@@ -1079,18 +1084,6 @@ function describeSiteHeading(address, ctx) {
1079
1084
  });
1080
1085
  }
1081
1086
 
1082
- case "action-when":
1083
- {
1084
- const title = actionTitle(address, ctx), activity = activityTitle(address.activity, ctx);
1085
- return phrase(id, {
1086
- params: {
1087
- title: title,
1088
- activity: activity
1089
- },
1090
- text: `action ${quoted(title)} on ${quoted(activity)} fires automatically when:`
1091
- });
1092
- }
1093
-
1094
1087
  case "editable-field":
1095
1088
  {
1096
1089
  const field = fieldTitleOf({
@@ -1134,6 +1127,7 @@ function describeSite(site, ctx) {
1134
1127
  }
1135
1128
 
1136
1129
  case "action":
1130
+ case "action-when":
1137
1131
  {
1138
1132
  const title = actionTitle(site, ctx), activity = activityTitle(site.activity, ctx);
1139
1133
  return phrase(id, {
@@ -1141,7 +1135,7 @@ function describeSite(site, ctx) {
1141
1135
  title: title,
1142
1136
  activity: activity
1143
1137
  },
1144
- text: `the ${quoted(title)} action on ${quoted(activity)}`
1138
+ text: `the ${quoted(title)} ${site.kind === "action" ? "action" : "trigger"} on ${quoted(activity)}`
1145
1139
  });
1146
1140
  }
1147
1141
 
@@ -1157,18 +1151,6 @@ function describeSite(site, ctx) {
1157
1151
  });
1158
1152
  }
1159
1153
 
1160
- case "action-when":
1161
- {
1162
- const title = actionTitle(site, ctx), activity = activityTitle(site.activity, ctx);
1163
- return phrase(id, {
1164
- params: {
1165
- title: title,
1166
- activity: activity
1167
- },
1168
- text: `the ${quoted(title)} trigger on ${quoted(activity)}`
1169
- });
1170
- }
1171
-
1172
1154
  case "activity-filter":
1173
1155
  {
1174
1156
  const activity = activityTitle(site.activity, ctx);
@@ -1226,10 +1208,10 @@ function unsatisfiedTransitionSummaries(evaluation) {
1226
1208
  definition: evaluation.definition
1227
1209
  };
1228
1210
  return evaluation.currentStage.transitions.filter(t => !t.whenSatisfied).flatMap(t => {
1229
- const summary = describeCondition(t.insight, ctx).summary;
1230
- return summary !== void 0 ? [ {
1211
+ const summary2 = describeCondition(t.insight, ctx).summary;
1212
+ return summary2 !== void 0 ? [ {
1231
1213
  transition: t.transition.name,
1232
- summary: summary
1214
+ summary: summary2
1233
1215
  } ] : [];
1234
1216
  });
1235
1217
  }
@@ -2859,8 +2841,8 @@ class CascadeLimitError extends WorkflowError {
2859
2841
 
2860
2842
  const FIELD_OP_TYPES = [ "field.set", "field.setIfMissing", "field.unset", "field.append", "field.inc", "field.dec", "field.updateWhere", "field.removeWhere" ];
2861
2843
 
2862
- function isFieldOp(summary) {
2863
- return FIELD_OP_TYPES.includes(summary.opType);
2844
+ function isFieldOp(summary2) {
2845
+ return FIELD_OP_TYPES.includes(summary2.opType);
2864
2846
  }
2865
2847
 
2866
2848
  function validateActionParams({action: action, activityName: activityName, callerParams: callerParams}) {
@@ -2939,7 +2921,7 @@ async function runOps(args) {
2939
2921
  if (ops === void 0 || ops.length === 0) return [];
2940
2922
  const opsFromDefinition = origin.effect === void 0 && origin.edit !== !0, summaries = [];
2941
2923
  for (const op of ops) {
2942
- const summary = await applyOp(op, {
2924
+ const summary2 = await applyOp(op, {
2943
2925
  mutation: mutation,
2944
2926
  stage: stage,
2945
2927
  activityName: origin.activity,
@@ -2953,9 +2935,9 @@ async function runOps(args) {
2953
2935
  memberRoles: args.memberRoles,
2954
2936
  roleAliases: args.roleAliases
2955
2937
  });
2956
- summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
2938
+ summaries.push(summary2), shouldRecordOpApplied(summary2) && mutation.history.push(opAppliedEntry({
2957
2939
  origin: origin,
2958
- summary: summary,
2940
+ summary: summary2,
2959
2941
  stage: stage,
2960
2942
  actor: actor,
2961
2943
  now: now
@@ -2964,12 +2946,12 @@ async function runOps(args) {
2964
2946
  return summaries;
2965
2947
  }
2966
2948
 
2967
- function shouldRecordOpApplied(summary) {
2968
- return summary.opType !== "field.setIfMissing" || summary.resolved !== void 0;
2949
+ function shouldRecordOpApplied(summary2) {
2950
+ return summary2.opType !== "field.setIfMissing" || summary2.resolved !== void 0;
2969
2951
  }
2970
2952
 
2971
2953
  function opAppliedEntry(args) {
2972
- const {origin: origin, summary: summary, stage: stage, actor: actor, now: now} = args;
2954
+ const {origin: origin, summary: summary2, stage: stage, actor: actor, now: now} = args;
2973
2955
  return {
2974
2956
  _key: randomKey(),
2975
2957
  _type: "opApplied",
@@ -2987,12 +2969,12 @@ function opAppliedEntry(args) {
2987
2969
  ...origin.effect !== void 0 ? {
2988
2970
  effect: origin.effect
2989
2971
  } : {},
2990
- opType: summary.opType,
2991
- ...summary.target !== void 0 ? {
2992
- target: summary.target
2972
+ opType: summary2.opType,
2973
+ ...summary2.target !== void 0 ? {
2974
+ target: summary2.target
2993
2975
  } : {},
2994
- ...summary.resolved !== void 0 ? {
2995
- resolved: summary.resolved
2976
+ ...summary2.resolved !== void 0 ? {
2977
+ resolved: summary2.resolved
2996
2978
  } : {},
2997
2979
  ...actor !== void 0 ? {
2998
2980
  actor: actor
@@ -3768,7 +3750,13 @@ function siblingConfig(target) {
3768
3750
  };
3769
3751
  }
3770
3752
 
3771
- const wallClock = () => /* @__PURE__ */ (new Date).toISOString();
3753
+ const wallClock = () => /* @__PURE__ */ (new Date).toISOString(), tick = ms => new Promise(resolve => {
3754
+ setTimeout(resolve, ms);
3755
+ }), wallSleeper = async ms => {
3756
+ let left = ms;
3757
+ for (;left > 2147483647; ) await tick(2147483647), left -= 2147483647;
3758
+ await tick(left);
3759
+ };
3772
3760
 
3773
3761
  function addMs(instant, ms) {
3774
3762
  return new Date(Date.parse(instant) + ms).toISOString();
@@ -3778,7 +3766,7 @@ function hasPassed(instant, now) {
3778
3766
  return Date.parse(instant) <= Date.parse(now);
3779
3767
  }
3780
3768
 
3781
- const DATA_MODEL_VERSION = 9, DATA_MODEL_MIN_READER = 4, DATA_MODEL_MAX_READER = 9, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/workflows/prerelease";
3769
+ const DATA_MODEL_VERSION = 10, DATA_MODEL_MIN_READER = 4, DATA_MODEL_MAX_READER = 10, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/workflows/prerelease";
3782
3770
 
3783
3771
  class ReaderModelAcknowledgementError extends WorkflowError {
3784
3772
  code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
@@ -3934,6 +3922,22 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
3934
3922
  compatibility: "reader-floor",
3935
3923
  applicability: "detectable",
3936
3924
  summary: "Singular assignee fields use member lists with at most one user and any number of roles."
3925
+ }), Object.freeze({
3926
+ id: "required-content-references",
3927
+ introducedInModel: 10,
3928
+ minReaderModel: 10,
3929
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3930
+ compatibility: "reader-floor",
3931
+ applicability: "detectable",
3932
+ summary: "Required content references must remain readable after initialization before actions or transitions advance."
3933
+ }), Object.freeze({
3934
+ id: "effect-retry-policy",
3935
+ introducedInModel: 10,
3936
+ minReaderModel: 10,
3937
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3938
+ compatibility: "reader-floor",
3939
+ applicability: "detectable",
3940
+ summary: "An effect node declares a bounded retry policy the engine enforces on every runtime."
3937
3941
  }) ]);
3938
3942
 
3939
3943
  function recordOf(value) {
@@ -4065,6 +4069,10 @@ function hasSingularAssigneeLists(document) {
4065
4069
  return typeof snapshot?.modelVersion == "number" && isAssignmentListModel(snapshot.modelVersion) && persistedFieldEntries(document).some(entry => entryHasKind(entry, "assignee"));
4066
4070
  }
4067
4071
 
4072
+ function hasEffectRetryPolicy(document) {
4073
+ return persistedDefinitionTree(document)?.actions.some(action => recordsAt(action, "effects").some(effect => recordOf(effect.retry) !== void 0)) ?? !1;
4074
+ }
4075
+
4068
4076
  function isMutationGuardAction(action) {
4069
4077
  return typeof action == "string" && MUTATION_GUARD_ACTIONS.some(candidate => candidate === action);
4070
4078
  }
@@ -4076,6 +4084,10 @@ function hasSplitGuardIdSpaces(document) {
4076
4084
  })) ?? !1;
4077
4085
  }
4078
4086
 
4087
+ function hasRequiredContentReferences(document) {
4088
+ return persistedDefinitionTree(document)?.roots.some(root => recordsAt(root, "fields").some(field => field.required === !0 && typeof field.type == "string" && refKindAcceptsTypes(field.type))) ?? !1;
4089
+ }
4090
+
4079
4091
  const featureDetectors = {
4080
4092
  "governed-model-stamps": () => !0,
4081
4093
  "subject-field-kind": document => hasFieldKind(document, "subject"),
@@ -4090,6 +4102,8 @@ const featureDetectors = {
4090
4102
  "role-constrained-assignment-fields": hasRoleConstrainedAssignments,
4091
4103
  "singular-assignee-lists": hasSingularAssigneeLists,
4092
4104
  "split-guard-id-spaces": hasSplitGuardIdSpaces,
4105
+ "required-content-references": hasRequiredContentReferences,
4106
+ "effect-retry-policy": hasEffectRetryPolicy,
4093
4107
  "node-semantics": hasNodeSemantics,
4094
4108
  "field-patch-ops": document => hasPersistedOpType(document, [ "field.inc", "field.dec", "field.setIfMissing" ]),
4095
4109
  "attributes-condition-var": () => !0
@@ -4326,9 +4340,13 @@ function abortReason(instance) {
4326
4340
  }
4327
4341
 
4328
4342
  function diagnoseInputFromEvaluation(evaluation) {
4343
+ if (evaluation.missingDocuments?.length && evaluation.blockingMissingDocuments === void 0) throw new Error("Missing blocking document evidence in workflow evaluation");
4329
4344
  const stage = openStage(evaluation.instance);
4330
4345
  return {
4331
4346
  instance: evaluation.instance,
4347
+ ...evaluation.missingDocuments !== void 0 ? {
4348
+ missingDocuments: evaluation.blockingMissingDocuments ?? []
4349
+ } : {},
4332
4350
  activities: evaluation.currentStage.activities,
4333
4351
  transitions: evaluation.currentStage.transitions,
4334
4352
  assignees: Object.fromEntries(evaluation.currentStage.activities.map(t => [ t.activity.name, assigneesOf(stage, t.activity.name) ]))
@@ -4447,7 +4465,7 @@ function diagnoseInstance(input) {
4447
4465
  at: instance.completedAt,
4448
4466
  ...liveChildrenField(instance)
4449
4467
  };
4450
- const cause = stuckFromDocumentState(input) ?? noTransitionFiresCause(input);
4468
+ const cause = stuckFromDocumentState(input) ?? missingDocumentCause(input.missingDocuments) ?? noTransitionFiresCause(input);
4451
4469
  return cause !== void 0 ? {
4452
4470
  state: "stuck",
4453
4471
  cause: cause
@@ -4456,10 +4474,27 @@ function diagnoseInstance(input) {
4456
4474
  };
4457
4475
  }
4458
4476
 
4477
+ function missingDocumentCause(documents = []) {
4478
+ return documents.length > 0 ? {
4479
+ kind: "document-missing",
4480
+ documents: documents
4481
+ } : void 0;
4482
+ }
4483
+
4484
+ function _additionalMissingDocuments(diagnosis, documents) {
4485
+ return diagnosis.state === "stuck" && diagnosis.cause.kind !== "document-missing" ? documents ?? [] : [];
4486
+ }
4487
+
4459
4488
  const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
4460
4489
 
4461
4490
  function remediationsForCause(cause) {
4462
4491
  switch (cause.kind) {
4492
+ case "document-missing":
4493
+ return [ {
4494
+ verb: "abort",
4495
+ rationale: "Required content cannot be read. Investigate the referenced documents, or abort the instance if it is no longer needed."
4496
+ } ];
4497
+
4463
4498
  case "failed-effect":
4464
4499
  return [ {
4465
4500
  verb: "retry-effect",
@@ -4554,12 +4589,12 @@ function joinCacheFor(client) {
4554
4589
  }
4555
4590
 
4556
4591
  function isClientProjectMember(value) {
4557
- return isRecord(value) && typeof value.id == "string";
4592
+ return isRecord(value) && typeof value.id == "string" && (value.isRobot === void 0 || typeof value.isRobot == "boolean");
4558
4593
  }
4559
4594
 
4560
- async function requestProjectMembers(request, projectId) {
4595
+ async function _requestProjectMembers(request, projectId) {
4561
4596
  const project = await request({
4562
- uri: `/projects/${encodeURIComponent(projectId)}`
4597
+ url: `/projects/${encodeURIComponent(projectId)}`
4563
4598
  }), members = isRecord(project) ? project.members : void 0;
4564
4599
  if (!Array.isArray(members) || !members.every(isClientProjectMember)) throw new Error(`Project member directory response is invalid for project "${projectId}"`);
4565
4600
  return members;
@@ -4567,7 +4602,7 @@ async function requestProjectMembers(request, projectId) {
4567
4602
 
4568
4603
  async function requestProjectUsers(args) {
4569
4604
  const {request: request, projectId: projectId, memberIds: memberIds} = args, response = await request({
4570
- uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
4605
+ url: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
4571
4606
  }), rows = Array.isArray(response) ? response : [ response ];
4572
4607
  if (!rows.every(isClientProjectUser)) throw new Error(`Project user directory response is invalid for project "${projectId}"`);
4573
4608
  const requested = new Set(memberIds);
@@ -4575,7 +4610,7 @@ async function requestProjectUsers(args) {
4575
4610
  }
4576
4611
 
4577
4612
  async function requestProjectMemberDirectory(args) {
4578
- const {request: request, projectId: projectId} = args, members = await requestProjectMembers(request, projectId), memberIds = members.map(member => member.id).filter(id => classifyPrincipalId(id).namespace === "project");
4613
+ const {request: request, projectId: projectId} = args, members = await _requestProjectMembers(request, projectId), memberIds = members.map(member => member.id).filter(id => classifyPrincipalId(id).namespace === "project");
4579
4614
  if (memberIds.length === 0) return {
4580
4615
  members: members,
4581
4616
  globalUsers: []
@@ -4650,7 +4685,7 @@ function clientProjectUserDirectory(client, projectId) {
4650
4685
  });
4651
4686
  try {
4652
4687
  const response = await client.request({
4653
- uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
4688
+ url: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
4654
4689
  }), candidate = Array.isArray(response) ? response[0] : response;
4655
4690
  return candidate == null ? {
4656
4691
  status: "missing"
@@ -4762,8 +4797,30 @@ function collectWatchRefs(instance) {
4762
4797
  }
4763
4798
 
4764
4799
  function collectSubjectRefs(instance) {
4765
- const stage = findOpenStageEntry(instance), activityFields = stage?.activities.map(activity => activity.fields) ?? [];
4766
- return [ ...entryDocRefs(instance.fields), ...entryDocRefs(stage?.fields), ...activityFields.flatMap(entryDocRefs), ...entryReleaseRefs(instance.fields), ...entryReleaseRefs(stage?.fields), ...activityFields.flatMap(entryReleaseRefs) ];
4800
+ const entries = activeFieldEntries(instance).map(({entry: entry}) => entry);
4801
+ return [ ...entryDocRefs(entries), ...entryReleaseRefs(entries) ];
4802
+ }
4803
+
4804
+ function activeFieldEntries(instance) {
4805
+ const stage = findOpenStageEntry(instance);
4806
+ return [ ...scopedEntries(instance.fields, {
4807
+ scope: "workflow"
4808
+ }), ...scopedEntries(stage?.fields, {
4809
+ scope: "stage"
4810
+ }), ...(stage?.activities ?? []).flatMap(activity => scopedEntries(activity.fields, {
4811
+ scope: "activity",
4812
+ activity: activity.name
4813
+ })) ];
4814
+ }
4815
+
4816
+ function scopedEntries(entries, scope) {
4817
+ return (entries ?? []).map(entry => ({
4818
+ target: {
4819
+ ...scope,
4820
+ field: entry.name
4821
+ },
4822
+ entry: entry
4823
+ }));
4767
4824
  }
4768
4825
 
4769
4826
  function foreignSubjectRefs(instance) {
@@ -4864,6 +4921,10 @@ function entrySubjectRefs(entries) {
4864
4921
  return fieldEntries(entries).flatMap(entry => (typeof entry._type == "string" && isSingleDocRefKind(entry._type) || entry._type === "release.ref") && isGdr(entry.value) ? [ entry.value ] : []);
4865
4922
  }
4866
4923
 
4924
+ function missingEntryDocRefs(entries, knownIds) {
4925
+ return entryDocRefs(entries).filter(reference => !knownIds.has(reference.id));
4926
+ }
4927
+
4867
4928
  function fieldEntries(entries) {
4868
4929
  return Array.isArray(entries) ? entries.filter(entry => !!entry && typeof entry == "object") : [];
4869
4930
  }
@@ -6134,7 +6195,7 @@ async function resolveThroughDirectory(args) {
6134
6195
  if (safeMisses.length === 0 || client.request === void 0) return out;
6135
6196
  try {
6136
6197
  const response = await client.request({
6137
- uri: `/projects/${encodeURIComponent(projectId)}/users/${safeMisses.map(encodeURIComponent).join(",")}`,
6198
+ url: `/projects/${encodeURIComponent(projectId)}/users/${safeMisses.map(encodeURIComponent).join(",")}`,
6138
6199
  tag: REQUEST_TAG.accessResolveActor
6139
6200
  });
6140
6201
  ingestDirectoryRows({
@@ -6334,6 +6395,12 @@ function memoizedBy(compute) {
6334
6395
  };
6335
6396
  }
6336
6397
 
6398
+ function chunks(values, size) {
6399
+ return Array.from({
6400
+ length: Math.ceil(values.length / size)
6401
+ }, (_, index) => values.slice(index * size, (index + 1) * size));
6402
+ }
6403
+
6337
6404
  async function hydrateSnapshot(args) {
6338
6405
  const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
6339
6406
  loaded.push({
@@ -6444,12 +6511,6 @@ function groupReads(reads) {
6444
6511
  return [ ...byClient.values() ].flatMap(groups => [ ...groups.values() ]);
6445
6512
  }
6446
6513
 
6447
- function chunks(values, size) {
6448
- return Array.from({
6449
- length: Math.ceil(values.length / size)
6450
- }, (_, index) => values.slice(index * size, (index + 1) * size));
6451
- }
6452
-
6453
6514
  function collectEntryDocUris(resolvedFieldEntries) {
6454
6515
  return entryDocRefs(resolvedFieldEntries).map(ref => ref.id);
6455
6516
  }
@@ -7669,6 +7730,29 @@ async function refreshStageGuards({ctx: ctx, mutation: mutation, stageName: stag
7669
7730
  });
7670
7731
  }
7671
7732
 
7733
+ function missingRequiredDocuments({instance: instance, definition: definition, snapshot: snapshot}) {
7734
+ return (definition.fields ?? []).filter(field => field.required === !0 && refKindAcceptsTypes(field.type)).flatMap(field => {
7735
+ const entry = instance.fields.find(candidate => candidate.name === field.name && candidate._type === field.type);
7736
+ return missingEntryDocRefs(entry === void 0 ? [] : [ entry ], snapshot.knownIds).map(reference => ({
7737
+ target: {
7738
+ scope: "workflow",
7739
+ field: field.name
7740
+ },
7741
+ reference: reference
7742
+ }));
7743
+ });
7744
+ }
7745
+
7746
+ function requiredDocumentRequirements(args) {
7747
+ return [ ...new Set(missingRequiredDocuments(args).map(({target: target}) => target.field)) ].map(field => {
7748
+ const title = args.definition.fields?.find(entry => entry.name === field)?.title ?? field;
7749
+ return {
7750
+ name: `field:${field}`,
7751
+ title: `Documents selected for “${title}” must be readable`
7752
+ };
7753
+ });
7754
+ }
7755
+
7672
7756
  async function discoverItems(args) {
7673
7757
  const {client: client, groq: groq, params: params, perspective: perspective} = args;
7674
7758
  return client.fetch(groq, paramsForLake(params), {
@@ -8244,7 +8328,7 @@ async function persistStageMove({ctx: ctx, mutation: mutation, exitedStage: exit
8244
8328
  }
8245
8329
 
8246
8330
  async function pickTransition(ctx, stage) {
8247
- for (const candidate of stage.transitions ?? []) {
8331
+ if (!(missingRequiredDocuments(ctx).length > 0)) for (const candidate of stage.transitions ?? []) {
8248
8332
  const outcome = await ctxEvaluateConditionOutcome({
8249
8333
  ctx: ctx,
8250
8334
  condition: candidate.when
@@ -8346,7 +8430,7 @@ const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ ne
8346
8430
 
8347
8431
  async function resolveAccess(taggedClient, args = {}) {
8348
8432
  const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
8349
- 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).");
8433
+ if (requestFn === void 0) throw new ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({url: '/users/me'})`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
8350
8434
  const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
8351
8435
  client: client,
8352
8436
  requestFn: requestFn,
@@ -8415,20 +8499,32 @@ function cachedByKey(args) {
8415
8499
  }
8416
8500
 
8417
8501
  async function fetchActor(client, requestFn) {
8418
- 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;
8502
+ const resourceUser = await fetchCurrentUser(requestFn, "the workflow resource host"), resourceId = usableId(resourceUser), resourceGlobalId = firstCarriedGlobalId([ resourceId ]) ?? directoryBridgeId(resourceUser?.sanityUserId);
8503
+ if (resourceGlobalId !== void 0) return identityFromUsers({
8504
+ id: resourceGlobalId,
8505
+ resourceUser: resourceUser
8506
+ });
8507
+ const globalUser = await fetchGlobalUser(client), globalHostId = usableId(globalUser.user), carriedId = firstCarriedGlobalId([ globalHostId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
8419
8508
  if (sessionId === void 0) return;
8420
8509
  const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
8421
8510
  client: client,
8422
8511
  sessionId: sessionId,
8423
8512
  resourceId: resourceId
8424
8513
  }) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
8425
- refuseProjectScopedActor({
8514
+ return refuseProjectScopedActor({
8426
8515
  id: id,
8427
8516
  globalUser: globalUser,
8428
8517
  globalHostId: globalHostId,
8429
8518
  bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
8519
+ }), identityFromUsers({
8520
+ id: id,
8521
+ resourceUser: resourceUser,
8522
+ globalUser: globalUser.user
8430
8523
  });
8431
- const roleNames = roleNamesFor(resourceUser, globalUser);
8524
+ }
8525
+
8526
+ function identityFromUsers(args) {
8527
+ const {id: id, resourceUser: resourceUser, globalUser: globalUser} = args, resourceId = usableId(resourceUser), roleNames = roleNamesFor(resourceUser, globalUser);
8432
8528
  return {
8433
8529
  actor: {
8434
8530
  kind: "person",
@@ -8444,7 +8540,7 @@ async function fetchActor(client, requestFn) {
8444
8540
  }
8445
8541
 
8446
8542
  function roleNamesFor(resourceUser, globalUser) {
8447
- return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8543
+ return (resourceUser?.roles?.length ? resourceUser : globalUser)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8448
8544
  }
8449
8545
 
8450
8546
  const NO_BRIDGE = {
@@ -8508,11 +8604,11 @@ function usableId(user) {
8508
8604
  async function fetchCurrentUser(requestFn, hostDescription) {
8509
8605
  try {
8510
8606
  return await requestFn({
8511
- uri: "/users/me",
8607
+ url: "/users/me",
8512
8608
  tag: REQUEST_TAG.accessResolveActor
8513
8609
  });
8514
8610
  } catch (err) {
8515
- 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.`, {
8611
+ throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({url: '/users/me'})\`. Check the token/connectivity.`, {
8516
8612
  cause: err
8517
8613
  });
8518
8614
  }
@@ -8529,7 +8625,7 @@ async function fetchGlobalUser(client) {
8529
8625
  };
8530
8626
  try {
8531
8627
  const user = await sibling.request({
8532
- uri: "/users/me",
8628
+ url: "/users/me",
8533
8629
  tag: REQUEST_TAG.accessResolveActor
8534
8630
  }), id = usableId(user);
8535
8631
  return sibling.requireGlobalPrincipal && id !== void 0 && classifyPrincipalId(id).namespace === "project" ? {
@@ -8652,7 +8748,7 @@ async function resolveOrganizationId(args) {
8652
8748
  load: async () => {
8653
8749
  try {
8654
8750
  const project = await requestFn({
8655
- uri: `/projects/${encodeURIComponent(projectId)}`,
8751
+ url: `/projects/${encodeURIComponent(projectId)}`,
8656
8752
  tag: REQUEST_TAG.accessResolveOrg
8657
8753
  });
8658
8754
  if (!isRecord(project)) return;
@@ -8677,15 +8773,17 @@ function httpStatusOf(err) {
8677
8773
  return typeof status == "number" ? status : void 0;
8678
8774
  }
8679
8775
 
8776
+ function attributesRequestOf(client) {
8777
+ const version = client.config?.().apiVersion, request = typeof client.withConfig == "function" || version === void 0 || version === ENGINE_API_VERSION ? lazyRequest(pinApiVersion(client)) : void 0;
8778
+ return request === void 0 && console.warn("workflow: skipped org attributes fetch; the client cannot issue API-version-pinned requests. Advisory $attributes stays undefined (conditions referencing it fail closed)."),
8779
+ request;
8780
+ }
8781
+
8680
8782
  async function fetchAttributesCached(args) {
8681
- const {client: client, orgId: orgId} = args, sibling = globalHostRequestOf(client);
8682
- if ("reason" in sibling) {
8683
- console.warn(`workflow: skipped org attributes fetch (${sibling.reason}); advisory $attributes stays undefined (conditions referencing it fail closed).`);
8684
- return;
8685
- }
8686
- try {
8687
- const response = await sibling.request({
8688
- uri: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
8783
+ const {client: client, orgId: orgId} = args, request = attributesRequestOf(client);
8784
+ if (request !== void 0) try {
8785
+ const response = await request({
8786
+ url: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
8689
8787
  tag: REQUEST_TAG.accessAttributes
8690
8788
  }), envelope = isRecord(response) ? response : void 0;
8691
8789
  if (envelope?.hasMore === !0) {
@@ -8799,6 +8897,15 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
8799
8897
  actionName: actionName,
8800
8898
  status: entry?.status
8801
8899
  });
8900
+ const unmetRequirements = requiredDocumentRequirements(ctx);
8901
+ if (unmetRequirements.length > 0) throw new ActionDisabledError({
8902
+ activity: activityName,
8903
+ action: actionName,
8904
+ reason: {
8905
+ kind: "requirements-unmet",
8906
+ unmetRequirements: unmetRequirements
8907
+ }
8908
+ });
8802
8909
  const params = validateActionParams({
8803
8910
  action: action,
8804
8911
  activityName: activityName,
@@ -8955,13 +9062,13 @@ async function runTriggeredActions({ctx: ctx, mutation: mutation, stage: stage})
8955
9062
  async function runActivityTriggers({ctx: ctx, mutation: mutation, activity: activity}) {
8956
9063
  let fires = 0, ranFieldOps = !1;
8957
9064
  for (const action of activity.actions ?? []) {
8958
- if (!isCascadeFired(action)) continue;
8959
9065
  const entry = currentActivities(mutation).find(e => e.name === activity.name);
8960
9066
  if (entry === void 0 || entry.status !== "active") break;
8961
- if ((entry.firedActions ?? []).includes(action.name) || !await triggerIsLive({
9067
+ if (!await triggerIsLive({
8962
9068
  ctx: ctx,
8963
9069
  activity: activity,
8964
- action: action
9070
+ action: action,
9071
+ entry: entry
8965
9072
  })) continue;
8966
9073
  const result = await fireTriggeredAction({
8967
9074
  ctx: ctx,
@@ -8978,8 +9085,12 @@ async function runActivityTriggers({ctx: ctx, mutation: mutation, activity: acti
8978
9085
  };
8979
9086
  }
8980
9087
 
8981
- async function triggerIsLive({ctx: ctx, activity: activity, action: action}) {
8982
- if (!tokenMayExecute({
9088
+ function isUnfiredTrigger(action, entry) {
9089
+ return isCascadeFired(action) && !(entry.firedActions ?? []).includes(action.name);
9090
+ }
9091
+
9092
+ async function triggerIsLive({ctx: ctx, activity: activity, action: action, entry: entry}) {
9093
+ if (!isUnfiredTrigger(action, entry) || missingRequiredDocuments(ctx).length > 0 || !tokenMayExecute({
8983
9094
  actor: ctx.actor,
8984
9095
  action: action,
8985
9096
  ctx: ctx
@@ -10083,7 +10194,7 @@ function staleClaimReason(args) {
10083
10194
  if (isClaimExpired(claim, args.now)) return "lease-expired";
10084
10195
  }
10085
10196
 
10086
- function renewClaimLease(args) {
10197
+ function renewClaimLease$1(args) {
10087
10198
  const {mutation: mutation, effectKey: effectKey, now: now, leaseMs: leaseMs} = args;
10088
10199
  mutation.pendingEffects = mutation.pendingEffects.map(entry => entry._key === effectKey && entry.claim !== void 0 ? {
10089
10200
  ...entry,
@@ -10120,7 +10231,7 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
10120
10231
  mutation: mutation,
10121
10232
  record: requestRecord,
10122
10233
  now: ctx.now
10123
- }), renewClaimLease({
10234
+ }), renewClaimLease$1({
10124
10235
  mutation: mutation,
10125
10236
  effectKey: effectKey,
10126
10237
  now: ctx.now,
@@ -10209,6 +10320,100 @@ async function commitResetActivity({ctx: ctx, activity: activity, to: to, reques
10209
10320
  };
10210
10321
  }
10211
10322
 
10323
+ const AvailabilityResponse = v.object({
10324
+ documents: v.array(v.object({
10325
+ _id: v.string()
10326
+ })),
10327
+ omitted: v.array(v.object({
10328
+ id: v.string(),
10329
+ reason: v.picklist([ "existence", "permission" ])
10330
+ }))
10331
+ }), AVAILABILITY_BATCH_SIZE = 100, AVAILABILITY_CONCURRENCY = 4, pendingReads = /* @__PURE__ */ new WeakMap;
10332
+
10333
+ function groupsFor(documents, clientForGdr) {
10334
+ const groups = /* @__PURE__ */ new Map;
10335
+ for (const {reference: reference} of documents) {
10336
+ const parsed = parseGdr(reference.id), resource = resourceFromParsed(parsed), key = resourceGdr(resource), group = groups.get(key) ?? {
10337
+ client: clientForGdr(parsed),
10338
+ resource: resource,
10339
+ documents: /* @__PURE__ */ new Map
10340
+ };
10341
+ group.documents.set(reference.id, parsed.documentId), groups.set(key, group);
10342
+ }
10343
+ return [ ...groups.values() ];
10344
+ }
10345
+
10346
+ async function readGroup(group) {
10347
+ let response;
10348
+ try {
10349
+ const url = documentUrl(group);
10350
+ url !== void 0 && group.client.request !== void 0 ? response = await readResponse(group.client, url) : logUnavailable({
10351
+ resource: group.resource,
10352
+ reason: "unsupported-client"
10353
+ });
10354
+ } catch (error) {
10355
+ logUnavailable({
10356
+ resource: group.resource,
10357
+ reason: v.isValiError(error) ? "invalid-response" : "request-failed",
10358
+ error: error
10359
+ });
10360
+ }
10361
+ return [ ...group.documents ].map(([uri, id]) => [ uri, availabilityOf(response, id) ]);
10362
+ }
10363
+
10364
+ function logUnavailable({resource: resource, reason: reason, error: error}) {
10365
+ const statusCode = typeof error == "object" && error !== null && "statusCode" in error ? error.statusCode : void 0;
10366
+ console.warn("[workflows] Document availability could not be confirmed.", {
10367
+ resource: resourceGdr(resource),
10368
+ reason: reason,
10369
+ ...typeof statusCode == "number" ? {
10370
+ statusCode: statusCode
10371
+ } : {}
10372
+ });
10373
+ }
10374
+
10375
+ function availabilityOf(response, id) {
10376
+ if (response === void 0) return "unreadable";
10377
+ const omissions = response.omitted.filter(entry => getPublishedId(DocumentId(entry.id)) === id);
10378
+ return omissions.some(entry => entry.reason === "permission") ? "unreadable" : response.documents.some(doc => getPublishedId(DocumentId(doc._id)) === id) ? "outside-perspective" : omissions.some(entry => entry.id === id && entry.reason === "existence") ? "deleted" : "unreadable";
10379
+ }
10380
+
10381
+ function documentUrl(group) {
10382
+ const ids = [ ...new Set(group.documents.values()) ].sort().map(encodeURIComponent).join(",");
10383
+ let url;
10384
+ if ("getDataUrl" in group.client && group.client.getDataUrl !== void 0) url = group.client.getDataUrl("doc", ids); else {
10385
+ if (group.resource.type !== "dataset") return;
10386
+ const {dataset: dataset} = datasetResourceParts(group.resource.id);
10387
+ url = `/data/doc/${dataset}/${ids}`;
10388
+ }
10389
+ return `${url}?includeAllVersions=true`;
10390
+ }
10391
+
10392
+ function readResponse(client, url) {
10393
+ const identity = unwrapRequestTag(client), pending = pendingReads.get(identity) ?? /* @__PURE__ */ new Map;
10394
+ pendingReads.set(identity, pending);
10395
+ const existing = pending.get(url);
10396
+ if (existing !== void 0) return existing;
10397
+ const result = client.request({
10398
+ url: url
10399
+ }).then(response => v.parse(AvailabilityResponse, response)).finally(() => pending.delete(url));
10400
+ return pending.set(url, result), result;
10401
+ }
10402
+
10403
+ function documentAvailabilityReader(args) {
10404
+ return async documents => {
10405
+ const result = /* @__PURE__ */ new Map, groups = groupsFor(documents, args.clientForGdr).flatMap(group => chunks([ ...group.documents ], AVAILABILITY_BATCH_SIZE).map(entries => ({
10406
+ ...group,
10407
+ documents: new Map(entries)
10408
+ })));
10409
+ for (const wave of chunks(groups, AVAILABILITY_CONCURRENCY)) {
10410
+ const rows = await Promise.all(wave.map(readGroup));
10411
+ for (const [uri, availability] of rows.flat()) result.set(uri, availability);
10412
+ }
10413
+ return result;
10414
+ };
10415
+ }
10416
+
10212
10417
  const REPLAY_SURFACE = {
10213
10418
  allows: () => !0,
10214
10419
  description: "any resource (in-memory replay; the committing surface enforces)"
@@ -10360,6 +10565,80 @@ function fabricatable(assignment) {
10360
10565
  return assignment.target.path.every(segment => typeof segment != "number" || segment <= MAX_COUNTERFACTUAL_INDEX);
10361
10566
  }
10362
10567
 
10568
+ function missingDocumentsOf({instance: instance, snapshot: snapshot, definition: definition}) {
10569
+ const stage = findStageNode({
10570
+ definition: definition,
10571
+ stageName: instance.currentStage
10572
+ });
10573
+ return activeFieldEntries(instance).flatMap(({target: target, entry: entry}) => {
10574
+ const declarations = {
10575
+ workflow: definition?.fields,
10576
+ stage: stage?.fields,
10577
+ activity: stage?.activities?.find(activity => activity.name === target.activity)?.fields
10578
+ }, title = entry.title ?? declarations[target.scope ?? "workflow"]?.find(field => field.name === target.field)?.title;
10579
+ return missingEntryDocRefs([ entry ], snapshot.knownIds).map(reference => ({
10580
+ target: target,
10581
+ reference: reference,
10582
+ ...title !== void 0 ? {
10583
+ title: title
10584
+ } : {}
10585
+ }));
10586
+ });
10587
+ }
10588
+
10589
+ function blockingConditions(evaluation) {
10590
+ const transitions = evaluation.currentStage.transitions.some(entry => entry.whenSatisfied) ? [] : evaluation.currentStage.transitions;
10591
+ return [ ...evaluation.currentStage.activities.filter(entry => entry.status === "active" && (entry.activity.actions ?? []).length > 0).flatMap(entry => (entry.unmetRequirements ?? []).map(requirement => ({
10592
+ insight: entry.requirementInsights?.[requirement.name],
10593
+ activity: entry.activity.name
10594
+ }))), ...transitions.map(entry => ({
10595
+ insight: entry.insight
10596
+ })) ];
10597
+ }
10598
+
10599
+ function readsDocumentContent({entry: entry, read: read, atom: atom}) {
10600
+ return atomReadsDataset(atom) ? !0 : isSingleDocRefKind(entry._type) && read.path.length > 1 && read.path[1] !== "_id" && read.path[1] !== "_type";
10601
+ }
10602
+
10603
+ function contentTargets({atoms: atoms, fields: fields, activity: activity}) {
10604
+ return atoms.flatMap(atom => atom.reads.flatMap(read => {
10605
+ if (read.variable !== "fields") return [];
10606
+ const field = fields.findLast(({entry: entry, target: target}) => entry.name === read.path[0] && (target.scope !== "activity" || target.activity === activity));
10607
+ return field !== void 0 && readsDocumentContent({
10608
+ entry: field.entry,
10609
+ read: read,
10610
+ atom: atom
10611
+ }) ? [ _fieldTargetLabel(field.target) ] : [];
10612
+ }));
10613
+ }
10614
+
10615
+ async function blockingAtoms(condition, args) {
10616
+ const atoms = condition.insight?.blockedBy.map(({atom: atom}) => atom) ?? [], names = [ ...new Set(atoms.flatMap(atom => atom.reads).filter(read => read.path.length === 0 && args.definition.predicates?.[read.variable] !== void 0).map(read => read.variable)) ];
10617
+ if (names.length === 0) return atoms;
10618
+ const site = args.sites.find(entry => entry.insight === condition.insight);
10619
+ if (site === void 0) throw new Error("Missing evaluated scope for a blocking condition");
10620
+ const dependencies = await Promise.all(names.map(async name => {
10621
+ const predicate = args.definition.predicates?.[name];
10622
+ if (predicate === void 0) throw new Error(`Missing predicate "${name}"`);
10623
+ return (await explainCondition({
10624
+ condition: site.params[name] === !0 ? `!(${predicate})` : predicate,
10625
+ dataset: args.snapshot.docs,
10626
+ params: site.params
10627
+ })).blockedBy.map(({atom: atom}) => atom);
10628
+ }));
10629
+ return [ ...atoms, ...dependencies.flat() ];
10630
+ }
10631
+
10632
+ async function blockingMissingDocuments(args) {
10633
+ if (!args.missingDocuments?.length) return [];
10634
+ const fields = activeFieldEntries(args.instance), targets = (await Promise.all(blockingConditions(args).map(async condition => contentTargets({
10635
+ atoms: await blockingAtoms(condition, args),
10636
+ fields: fields,
10637
+ activity: condition.activity
10638
+ })))).flat(), blocked = /* @__PURE__ */ new Set([ ...targets, ...missingRequiredDocuments(args).map(({target: target}) => _fieldTargetLabel(target)) ]);
10639
+ return args.missingDocuments.filter(({target: target}) => blocked.has(_fieldTargetLabel(target)));
10640
+ }
10641
+
10363
10642
  async function subjectResourceGrants(args) {
10364
10643
  const {clientForGdr: clientForGdr, instance: instance} = args, clients = /* @__PURE__ */ new Map;
10365
10644
  for (const {parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
@@ -10422,6 +10701,9 @@ async function evaluateInstance(args) {
10422
10701
  guards: guards,
10423
10702
  now: now,
10424
10703
  resourceGrants: resourceGrants,
10704
+ documentAvailability: documentAvailabilityReader({
10705
+ clientForGdr: clientForGdr
10706
+ }),
10425
10707
  guardDereference: clientGuardDereference(client),
10426
10708
  ...localPrincipalId !== void 0 ? {
10427
10709
  localPrincipalId: localPrincipalId
@@ -10529,7 +10811,11 @@ async function evaluateFromSnapshot(args) {
10529
10811
  }), subjectPermissionReason = subjectDenials.length > 0 ? {
10530
10812
  kind: "subject-permission-denied",
10531
10813
  denied: subjectDenials
10532
- } : void 0, sites = [], activityEvaluations = [];
10814
+ } : void 0, sites = [], activityEvaluations = [], requiredDocuments = requiredDocumentRequirements({
10815
+ instance: instance,
10816
+ definition: definition,
10817
+ snapshot: snapshot
10818
+ });
10533
10819
  for (const activity of stage.activities ?? []) activityEvaluations.push(await evaluateActivity({
10534
10820
  activity: activity,
10535
10821
  statusEntry: currentActivityEntries.find(t => t.name === activity.name),
@@ -10540,36 +10826,23 @@ async function evaluateFromSnapshot(args) {
10540
10826
  stageHasExits: !isTerminalStage(stage),
10541
10827
  guardDenial: guardDenial,
10542
10828
  subjectPermissionReason: subjectPermissionReason,
10829
+ requiredDocuments: requiredDocuments,
10543
10830
  sites: sites,
10544
10831
  autonomy: activityAutonomyOf(stageAutonomy2, activity.name),
10545
10832
  fireConsequence: fireConsequence
10546
10833
  }));
10547
- const cascadeParams = await renderConditionScope(scopeSource), transitionEvaluations = [];
10548
- for (const transition of stage.transitions ?? []) {
10549
- const insight = await explainSite({
10550
- site: {
10551
- kind: "transition",
10552
- transition: transition.name
10553
- },
10554
- condition: transition.when,
10555
- params: cascadeParams,
10556
- snapshot: snapshot,
10557
- sites: sites
10558
- });
10559
- transitionEvaluations.push({
10560
- transition: transition,
10561
- whenSatisfied: insight.outcome === "satisfied",
10562
- unevaluable: insight.outcome === "unevaluable",
10563
- insight: insight
10564
- });
10565
- }
10566
- const currentStage = {
10834
+ const cascadeParams = await renderConditionScope(scopeSource), transitionEvaluations = await evaluateTransitions({
10835
+ stage: stage,
10836
+ cascadeParams: cascadeParams,
10837
+ snapshot: snapshot,
10838
+ sites: sites
10839
+ }), currentStage = {
10567
10840
  stage: stage,
10568
10841
  ...semanticsOf(stage),
10569
10842
  activities: activityEvaluations,
10570
10843
  transitions: transitionEvaluations,
10571
10844
  autonomy: stageAutonomy2
10572
- }, pendingOnYou = activityEvaluations.filter(t => t.pendingOnActor), canInteract = activityEvaluations.some(t => t.actions.some(a => a.allowed)), editGuardDenial = guardDenial?.kind === "mutation-guard-denied" ? guardDenial : void 0, editableFields = await evaluateEditableFields({
10845
+ }, missingDocuments = await readMissingDocuments(args), pendingOnYou = activityEvaluations.filter(t => t.pendingOnActor), canInteract = activityEvaluations.some(t => t.actions.some(a => a.allowed)), editGuardDenial = guardDenial?.kind === "mutation-guard-denied" ? guardDenial : void 0, editableFields = await evaluateEditableFields({
10573
10846
  instance: instance,
10574
10847
  definition: definition,
10575
10848
  stage: stage,
@@ -10596,6 +10869,17 @@ async function evaluateFromSnapshot(args) {
10596
10869
  sites: sites,
10597
10870
  snapshot: snapshot
10598
10871
  }),
10872
+ ...missingDocuments.length > 0 ? {
10873
+ missingDocuments: missingDocuments,
10874
+ blockingMissingDocuments: await blockingMissingDocuments({
10875
+ instance: instance,
10876
+ definition: definition,
10877
+ currentStage: currentStage,
10878
+ missingDocuments: missingDocuments,
10879
+ snapshot: snapshot,
10880
+ sites: sites
10881
+ })
10882
+ } : {},
10599
10883
  autonomy: autonomy,
10600
10884
  ...nextEvaluationAt !== void 0 ? {
10601
10885
  nextEvaluationAt: nextEvaluationAt
@@ -10603,6 +10887,42 @@ async function evaluateFromSnapshot(args) {
10603
10887
  };
10604
10888
  }
10605
10889
 
10890
+ async function readMissingDocuments(args) {
10891
+ const missingDocuments = missingDocumentsOf(args);
10892
+ if (args.documentAvailability === void 0 || missingDocuments.length === 0) return missingDocuments;
10893
+ const availability = await args.documentAvailability(missingDocuments);
10894
+ return missingDocuments.map(document => {
10895
+ const verdict = availability.get(document.reference.id);
10896
+ return verdict === void 0 ? document : {
10897
+ ...document,
10898
+ availability: verdict
10899
+ };
10900
+ });
10901
+ }
10902
+
10903
+ async function evaluateTransitions(args) {
10904
+ const {stage: stage, cascadeParams: cascadeParams, snapshot: snapshot, sites: sites} = args, evaluations = [];
10905
+ for (const transition of stage.transitions ?? []) {
10906
+ const insight = await explainSite({
10907
+ site: {
10908
+ kind: "transition",
10909
+ transition: transition.name
10910
+ },
10911
+ condition: transition.when,
10912
+ params: cascadeParams,
10913
+ snapshot: snapshot,
10914
+ sites: sites
10915
+ });
10916
+ evaluations.push({
10917
+ transition: transition,
10918
+ whenSatisfied: insight.outcome === "satisfied",
10919
+ unevaluable: insight.outcome === "unevaluable",
10920
+ insight: insight
10921
+ });
10922
+ }
10923
+ return evaluations;
10924
+ }
10925
+
10606
10926
  const AUTONOMY_CACHE = /* @__PURE__ */ new WeakMap;
10607
10927
 
10608
10928
  function autonomyOf(definition) {
@@ -10613,54 +10933,56 @@ function autonomyOf(definition) {
10613
10933
  }
10614
10934
 
10615
10935
  async function evaluateEditableFields(args) {
10616
- const {instance: instance, definition: definition, stage: stage, snapshot: snapshot, scope: scope, scopeForActivity: scopeForActivity, guardDenial: guardDenial, sites: sites} = args, fields = [];
10617
- for (const site of editableFieldsInStage(definition, stage)) {
10618
- const window = fieldWindowOpen(instance, site), insight = await editPredicateInsight({
10619
- site: site,
10620
- snapshot: snapshot,
10621
- scope: scope,
10622
- scopeForActivity: scopeForActivity,
10623
- sites: sites
10624
- }), predicateSatisfied = insight === void 0 || insight.outcome === "satisfied", reason = editDisabledReason({
10625
- effective: site.effective,
10626
- instance: instance,
10627
- window: window,
10628
- guardDenial: guardDenial,
10629
- predicateSatisfied: predicateSatisfied
10630
- }), value = readFieldValue(instance, site);
10631
- fields.push({
10632
- scope: site.scope,
10633
- ...site.activity !== void 0 ? {
10634
- activity: site.activity
10635
- } : {},
10636
- name: site.name,
10637
- type: site.type,
10638
- ...site.title !== void 0 ? {
10639
- title: site.title
10640
- } : {},
10641
- ...site.validation !== void 0 ? {
10642
- validation: site.validation
10643
- } : {},
10644
- ...site.roles !== void 0 ? {
10645
- roles: site.roles,
10646
- ...definition.roleAliases !== void 0 ? {
10647
- roleAliases: definition.roleAliases
10648
- } : {}
10649
- } : {},
10650
- value: value,
10651
- editable: reason === void 0,
10652
- ...reason !== void 0 ? {
10653
- disabledReason: reason
10654
- } : {},
10655
- ...fieldProvenance(instance, site.ref),
10656
- ...insight !== void 0 ? {
10657
- insight: insight
10658
- } : {}
10659
- });
10660
- }
10936
+ const fields = [];
10937
+ for (const site of editableFieldsInStage(args.definition, args.stage)) fields.push(await evaluateEditableField(args, site));
10661
10938
  return fields;
10662
10939
  }
10663
10940
 
10941
+ async function evaluateEditableField(args, site) {
10942
+ const {instance: instance, definition: definition, snapshot: snapshot, scope: scope, scopeForActivity: scopeForActivity, guardDenial: guardDenial, sites: sites} = args, window = fieldWindowOpen(instance, site), insight = await editPredicateInsight({
10943
+ site: site,
10944
+ snapshot: snapshot,
10945
+ scope: scope,
10946
+ scopeForActivity: scopeForActivity,
10947
+ sites: sites
10948
+ }), predicateSatisfied = insight === void 0 || insight.outcome === "satisfied", reason = editDisabledReason({
10949
+ effective: site.effective,
10950
+ instance: instance,
10951
+ window: window,
10952
+ guardDenial: guardDenial,
10953
+ predicateSatisfied: predicateSatisfied
10954
+ });
10955
+ return {
10956
+ scope: site.scope,
10957
+ ...site.activity !== void 0 ? {
10958
+ activity: site.activity
10959
+ } : {},
10960
+ name: site.name,
10961
+ type: site.type,
10962
+ ...site.title !== void 0 ? {
10963
+ title: site.title
10964
+ } : {},
10965
+ ...site.validation !== void 0 ? {
10966
+ validation: site.validation
10967
+ } : {},
10968
+ ...site.roles !== void 0 ? {
10969
+ roles: site.roles,
10970
+ ...definition.roleAliases !== void 0 ? {
10971
+ roleAliases: definition.roleAliases
10972
+ } : {}
10973
+ } : {},
10974
+ value: readFieldValue(instance, site),
10975
+ editable: reason === void 0,
10976
+ ...reason !== void 0 ? {
10977
+ disabledReason: reason
10978
+ } : {},
10979
+ ...fieldProvenance(instance, site.ref),
10980
+ ...insight !== void 0 ? {
10981
+ insight: insight
10982
+ } : {}
10983
+ };
10984
+ }
10985
+
10664
10986
  async function editPredicateInsight(args) {
10665
10987
  const {site: site, snapshot: snapshot, scope: scope, scopeForActivity: scopeForActivity, sites: sites} = args;
10666
10988
  if (typeof site.effective != "string") return;
@@ -10684,14 +11006,10 @@ async function editPredicateInsight(args) {
10684
11006
  async function forecastSubjectDenials(args) {
10685
11007
  const {instance: instance, snapshot: snapshot, resourceGrants: resourceGrants} = args;
10686
11008
  if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
10687
- const denials = [], seen = /* @__PURE__ */ new Set;
10688
- for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
10689
- if (seen.has(ref.id)) continue;
10690
- seen.add(ref.id);
10691
- const access = resourceGrants.get(resourceGdr(resource));
10692
- if (access === void 0) continue;
10693
- const doc = snapshot.docs.find(d => d._id === ref.id);
10694
- doc !== void 0 && await subjectUpdateAllowed({
11009
+ const denials = [], subjects = new Map(foreignSubjectRefs(instance).map(subject => [ subject.ref.id, subject ]));
11010
+ for (const {ref: ref, parsed: parsed, resource: resource} of subjects.values()) {
11011
+ const access = resourceGrants.get(resourceGdr(resource)), doc = snapshot.docs.find(d => d._id === ref.id);
11012
+ access === void 0 || doc === void 0 || await subjectUpdateAllowed({
10695
11013
  doc: doc,
10696
11014
  parsed: parsed,
10697
11015
  grants: access.grants,
@@ -10724,13 +11042,13 @@ async function subjectUpdateAllowed(args) {
10724
11042
  }
10725
11043
 
10726
11044
  async function evaluateActivity(args) {
10727
- const {activity: activity, statusEntry: statusEntry, instance: instance, snapshot: snapshot, activityScope: activityScope, cascadeActivityScope: cascadeActivityScope, stageHasExits: stageHasExits, guardDenial: guardDenial, subjectPermissionReason: subjectPermissionReason, sites: sites, autonomy: autonomy, fireConsequence: fireConsequence} = args, status = statusEntry?.status ?? "skipped", assigned = activityScope.assigned === !0, {unmetRequirements: unmetRequirements, ...conditionInsights} = await explainActivityConditions({
11045
+ const {activity: activity, statusEntry: statusEntry, instance: instance, snapshot: snapshot, activityScope: activityScope, cascadeActivityScope: cascadeActivityScope, stageHasExits: stageHasExits, guardDenial: guardDenial, subjectPermissionReason: subjectPermissionReason, requiredDocuments: requiredDocuments, sites: sites, autonomy: autonomy, fireConsequence: fireConsequence} = args, status = statusEntry?.status ?? "skipped", assigned = activityScope.assigned === !0, {unmetRequirements: activityRequirements, ...conditionInsights} = await explainActivityConditions({
10728
11046
  activity: activity,
10729
11047
  activityScope: activityScope,
10730
11048
  cascadeActivityScope: cascadeActivityScope,
10731
11049
  snapshot: snapshot,
10732
11050
  sites: sites
10733
- }), requirementsReason = unmetRequirements.length > 0 ? {
11051
+ }), unmetRequirements = [ ...requiredDocuments, ...activityRequirements ], requirementsReason = unmetRequirements.length > 0 ? {
10734
11052
  kind: "requirements-unmet",
10735
11053
  unmetRequirements: unmetRequirements
10736
11054
  } : void 0, actions = [];
@@ -11106,6 +11424,46 @@ function claimReleasedEntry(args) {
11106
11424
  };
11107
11425
  }
11108
11426
 
11427
+ const RENEW_MAX_ATTEMPTS = 3;
11428
+
11429
+ async function claimOf(args) {
11430
+ const {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey} = args, instance = await reload({
11431
+ client: client,
11432
+ instanceId: instanceId,
11433
+ tag: tag
11434
+ });
11435
+ return {
11436
+ instance: instance,
11437
+ claim: instance.pendingEffects.find(e => e._key === effectKey)?.claim
11438
+ };
11439
+ }
11440
+
11441
+ async function claimStillHeld(args) {
11442
+ const {claimToken: claimToken, ...where} = args, {claim: claim} = await claimOf(where);
11443
+ return claim?.claimToken === claimToken;
11444
+ }
11445
+
11446
+ async function renewClaimLease(args) {
11447
+ const {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, claimToken: claimToken, holdMs: holdMs, clock: clock} = args;
11448
+ for (let attempt = 1; attempt <= RENEW_MAX_ATTEMPTS; attempt++) {
11449
+ const {instance: instance, claim: claim} = await claimOf({
11450
+ client: client,
11451
+ tag: tag,
11452
+ instanceId: instanceId,
11453
+ effectKey: effectKey
11454
+ });
11455
+ if (claim?.claimToken !== claimToken) return;
11456
+ const until = addMs(clock(), holdMs);
11457
+ try {
11458
+ return await client.patch(instance._id).ifRevisionId(instance._rev).set({
11459
+ [`pendingEffects[_key=="${effectKey}"].claim.leaseExpiresAt`]: until
11460
+ }).commit(SYNC_COMMIT), until;
11461
+ } catch (error) {
11462
+ if (!isRevisionConflict(error)) throw error;
11463
+ }
11464
+ }
11465
+ }
11466
+
11109
11467
  const SWEEP_MAX_ATTEMPTS = 5;
11110
11468
 
11111
11469
  async function sweepStaleClaims(args) {
@@ -11153,7 +11511,7 @@ function isProjectRole(value) {
11153
11511
 
11154
11512
  async function projectRoleNames(request, projectId) {
11155
11513
  const result = await request({
11156
- uri: `/projects/${encodeURIComponent(projectId)}/roles`
11514
+ url: `/projects/${encodeURIComponent(projectId)}/roles`
11157
11515
  });
11158
11516
  if (!Array.isArray(result) || !result.every(isProjectRole)) throw new Error(`Project role catalog response is invalid for project "${projectId}"`);
11159
11517
  return new Set(result.map(role => role.name));
@@ -11349,7 +11707,7 @@ async function validateDefinitionRoles(args) {
11349
11707
  const references = args.definitions.flatMap(definitionRoleReferences);
11350
11708
  if (references.length === 0) /* @__PURE__ */ return new Map;
11351
11709
  if (args.client.request === void 0) throw new Error("workflow.deployDefinitions: definitions reference project roles, but the client cannot read the project role catalog");
11352
- const projectId = roleCatalogProjectId(args.client, args.workflowResource), [known, members] = await Promise.all([ projectRoleNames(args.client.request, projectId), requestProjectMembers(args.client.request, projectId) ]), unknown = references.filter(reference => !known.has(reference.role));
11710
+ const projectId = roleCatalogProjectId(args.client, args.workflowResource), [known, members] = await Promise.all([ projectRoleNames(args.client.request, projectId), _requestProjectMembers(args.client.request, projectId) ]), unknown = references.filter(reference => !known.has(reference.role));
11353
11711
  if (unknown.length > 0) {
11354
11712
  const lines = unknown.map(({definition: definition, path: path, role: role}) => ` - ${definition}: ${path} references unknown role "${role}"`);
11355
11713
  throw new Error(`workflow.deployDefinitions: unknown project roles for project "${projectId}":\n${lines.join(`\n`)}`);
@@ -11479,7 +11837,7 @@ function refsOf(def) {
11479
11837
  }
11480
11838
 
11481
11839
  function hashDefinitionContent(def) {
11482
- const canonical = stableStringify(def);
11840
+ const canonical = stableStringify(withoutAuthoringRuntime(def));
11483
11841
  let hash = 0xcbf29ce484222325n;
11484
11842
  for (let i = 0; i < canonical.length; i++) hash ^= BigInt(canonical.charCodeAt(i)),
11485
11843
  hash = hash * 0x100000001b3n & 0xffffffffffffffffn;
@@ -11492,7 +11850,7 @@ function planDefinitionDeploy({def: def, latest: latest, target: target}) {
11492
11850
  definition: def,
11493
11851
  workflowResource: target.workflowResource
11494
11852
  });
11495
- const expanded = expandResourceAliases(def, target.resourceAliases), contentHash = hashDefinitionContent(expanded), unchanged = latest !== void 0 && latest.contentHash === contentHash, version = unchanged ? latest.version : (latest?.version ?? 0) + 1, docId = definitionDocId({
11853
+ const expanded = withoutAuthoringRuntime(expandResourceAliases(def, target.resourceAliases)), contentHash = hashDefinitionContent(expanded), unchanged = latest !== void 0 && latest.contentHash === contentHash, version = unchanged ? latest.version : (latest?.version ?? 0) + 1, docId = definitionDocId({
11496
11854
  tag: target.tag,
11497
11855
  definition: expanded.name,
11498
11856
  version: version
@@ -11549,10 +11907,17 @@ function isDocumentEnvelopeKey(key) {
11549
11907
  return key.startsWith("_") || DEPLOY_STAMPED_KEYS.has(key);
11550
11908
  }
11551
11909
 
11910
+ const AUTHORING_RUNTIME_KEY = "runtime";
11911
+
11912
+ function withoutAuthoringRuntime(def) {
11913
+ const content = Object.entries(def).filter(([key]) => key !== AUTHORING_RUNTIME_KEY);
11914
+ return Object.fromEntries(content);
11915
+ }
11916
+
11552
11917
  function parseDefinitionInput(def, caller) {
11553
11918
  const label = labelFor(caller, def);
11554
11919
  if (def._type !== void 0 && def._type !== WORKFLOW_DEFINITION_TYPE) throw new Error(`${label}: expected a workflow definition or a "${WORKFLOW_DEFINITION_TYPE}" document, got _type "${String(def._type)}"`);
11555
- const content = Object.fromEntries(Object.entries(def).filter(([key]) => !isDocumentEnvelopeKey(key)));
11920
+ const content = Object.fromEntries(Object.entries(withoutAuthoringRuntime(def)).filter(([key]) => !isDocumentEnvelopeKey(key)));
11556
11921
  return parseStoredDefinition(content, label);
11557
11922
  }
11558
11923
 
@@ -13472,7 +13837,7 @@ function pendingEntry(args) {
13472
13837
  }
13473
13838
 
13474
13839
  function createEffectCommitQueue(args) {
13475
- const {effectKey: effectKey, claimToken: claimToken, commit: commit} = args, pending = [];
13840
+ const {effectKey: effectKey, claimToken: claimToken, attempt: attempt, commit: commit} = args, pending = [];
13476
13841
  let admitted = 0, dead, closed = !1, tail = Promise.resolve();
13477
13842
  function assertOpen() {
13478
13843
  if (dead !== void 0) throw dead;
@@ -13527,7 +13892,7 @@ function createEffectCommitQueue(args) {
13527
13892
  value: entry.latestValue
13528
13893
  }
13529
13894
  } ],
13530
- idempotencyKey: `effect:${effectKey}:${claimToken}:progress:${coalesceKey}:${admitted}`,
13895
+ idempotencyKey: `effect:${effectKey}:${claimToken}:${attempt}:progress:${coalesceKey}:${admitted}`,
13531
13896
  coalesceKey: coalesceKey,
13532
13897
  latestValue: value
13533
13898
  });
@@ -13537,6 +13902,29 @@ function createEffectCommitQueue(args) {
13537
13902
  };
13538
13903
  }
13539
13904
 
13905
+ function effectRetryPolicy(definition, effectName) {
13906
+ return findEffect(definition, effectName)?.retry;
13907
+ }
13908
+
13909
+ function retryWindowClosed(policy, elapsedMs) {
13910
+ return policy.expiryMs !== void 0 && elapsedMs >= policy.expiryMs;
13911
+ }
13912
+
13913
+ function nextRetryDelayMs(policy, at) {
13914
+ if (at.attempt >= policy.attempts) return;
13915
+ const delay = effectBackoffMs(policy, at.attempt);
13916
+ return retryWindowClosed(policy, at.elapsedMs + delay) ? void 0 : delay;
13917
+ }
13918
+
13919
+ function retryFailedDetail(args) {
13920
+ const window = args.windowClosed ? ", retry window expired" : "";
13921
+ return `failed after ${args.at.attempt} of ${args.attempts} attempts${window}: ${args.error.message}`;
13922
+ }
13923
+
13924
+ function retrySucceededDetail(args) {
13925
+ if (args.at.attempt !== 1) return `succeeded on attempt ${args.at.attempt} of ${args.attempts}`;
13926
+ }
13927
+
13540
13928
  class MissingHandlerError extends WorkflowError {
13541
13929
  info;
13542
13930
  constructor(args) {
@@ -13619,7 +14007,7 @@ function isCancelledCompletion(data) {
13619
14007
  }
13620
14008
 
13621
14009
  async function drainEffectsInternal(args) {
13622
- const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, handlers: handlers, missingHandler: missingHandler, logger: logger, handlerClient: rawHandlerClient, handlerResourceClients: rawHandlerResourceClients} = args, cascadeTelemetry = drainCascadeTelemetry(args.telemetry), {client: client, resourceClients: resourceClients} = taggedScope(args, REQUEST_TAG.drain), leaseMs = args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS, clock = args.clock ?? wallClock, handlerClient = effectHandlerClient(rawHandlerClient), handlerResourceClients = effectHandlerResolver(rawHandlerResourceClients), routeGdr = buildClientForGdr({
14010
+ const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, handlers: handlers, missingHandler: missingHandler, logger: logger, handlerClient: rawHandlerClient, handlerResourceClients: rawHandlerResourceClients} = args, cascadeTelemetry = drainCascadeTelemetry(args.telemetry), {client: client, resourceClients: resourceClients} = taggedScope(args, REQUEST_TAG.drain), leaseMs = args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS, clock = args.clock ?? wallClock, sleep = args.sleep ?? wallSleeper, handlerClient = effectHandlerClient(rawHandlerClient), handlerResourceClients = effectHandlerResolver(rawHandlerResourceClients), routeGdr = buildClientForGdr({
13623
14011
  client: handlerClient,
13624
14012
  workflowResource: workflowResource,
13625
14013
  resourceClients: handlerResourceClients
@@ -13645,6 +14033,7 @@ async function drainEffectsInternal(args) {
13645
14033
  log: log,
13646
14034
  leaseMs: leaseMs,
13647
14035
  clock: clock,
14036
+ sleep: sleep,
13648
14037
  ...executionContext !== void 0 ? {
13649
14038
  executionContext: executionContext
13650
14039
  } : {},
@@ -13652,14 +14041,14 @@ async function drainEffectsInternal(args) {
13652
14041
  drainerActor: drainerActor,
13653
14042
  clientFor: clientFor,
13654
14043
  buckets: buckets,
13655
- skippedKeys: /* @__PURE__ */ new Set
14044
+ handledKeys: /* @__PURE__ */ new Set
13656
14045
  };
13657
14046
  for (;await drainOneCandidate(pass); ) ;
13658
14047
  return buckets;
13659
14048
  }
13660
14049
 
13661
14050
  async function drainOneCandidate(pass) {
13662
- const {client: client, tag: tag, instanceId: instanceId, buckets: buckets, skippedKeys: skippedKeys} = pass, now = pass.clock(), before = await reload({
14051
+ const {client: client, tag: tag, instanceId: instanceId, buckets: buckets, handledKeys: handledKeys} = pass, now = pass.clock(), before = await reload({
13663
14052
  client: client,
13664
14053
  instanceId: instanceId,
13665
14054
  tag: tag
@@ -13668,7 +14057,7 @@ async function drainOneCandidate(pass) {
13668
14057
  const candidate = findClaimableCandidate({
13669
14058
  instance: before,
13670
14059
  now: now,
13671
- skippedKeys: skippedKeys
14060
+ handledKeys: handledKeys
13672
14061
  });
13673
14062
  if (candidate === void 0) return !1;
13674
14063
  const handler = pass.handlers[candidate.name];
@@ -13677,7 +14066,7 @@ async function drainOneCandidate(pass) {
13677
14066
  candidate: candidate,
13678
14067
  instanceId: instanceId,
13679
14068
  log: pass.log
13680
- }), buckets.skipped.push(candidate), skippedKeys.add(candidate._key), !0;
14069
+ }), buckets.skipped.push(candidate), handledKeys.add(candidate._key), !0;
13681
14070
  const claimed = await claimPendingEffect({
13682
14071
  client: client,
13683
14072
  instance: before,
@@ -13690,11 +14079,15 @@ async function drainOneCandidate(pass) {
13690
14079
  } : {}
13691
14080
  });
13692
14081
  if (claimed === void 0) return !0;
13693
- const outcome = await dispatchAndReport({
14082
+ const retry = effectRetryPolicy(parseDefinitionSnapshot(before), candidate.name), outcome = await dispatchAndReport({
13694
14083
  handler: handler,
13695
14084
  candidate: candidate,
13696
14085
  claimToken: claimed.claimToken,
14086
+ ...retry !== void 0 ? {
14087
+ retry: retry
14088
+ } : {},
13697
14089
  leaseMs: pass.leaseMs,
14090
+ sleep: pass.sleep,
13698
14091
  client: client,
13699
14092
  handlerClient: pass.handlerClient,
13700
14093
  tag: tag,
@@ -13712,50 +14105,80 @@ async function drainOneCandidate(pass) {
13712
14105
  telemetry: pass.telemetry,
13713
14106
  clock: pass.clock
13714
14107
  });
13715
- return buckets[outcome].push(candidate), !0;
14108
+ return buckets[outcome].push(candidate), outcome === "lost" && handledKeys.add(candidate._key),
14109
+ !0;
13716
14110
  }
13717
14111
 
13718
- function findClaimableCandidate({instance: instance, now: now, skippedKeys: skippedKeys}) {
13719
- return instance.pendingEffects.find(e => (e.claim === void 0 || isClaimExpired(e.claim, now)) && !skippedKeys.has(e._key));
14112
+ function findClaimableCandidate({instance: instance, now: now, handledKeys: handledKeys}) {
14113
+ return instance.pendingEffects.find(e => (e.claim === void 0 || isClaimExpired(e.claim, now)) && !handledKeys.has(e._key));
13720
14114
  }
13721
14115
 
13722
14116
  async function dispatchAndReport(args) {
13723
- const {handler: handler, candidate: candidate, claimToken: claimToken, leaseMs: leaseMs, client: client, handlerClient: handlerClient, tag: tag, workflowResource: workflowResource, resourceClients: resourceClients, instanceId: instanceId, clientFor: clientFor, logger: logger, log: log, executionContext: executionContext, telemetry: telemetry, clock: clock} = args, commitQueue = createEffectCommitQueue({
13724
- effectKey: candidate._key,
13725
- claimToken: claimToken,
13726
- commit: async req => {
13727
- await workflow.commitEffectOps({
13728
- client: client,
13729
- tag: tag,
13730
- workflowResource: workflowResource,
13731
- ...resourceClients !== void 0 ? {
13732
- resourceClients: resourceClients
13733
- } : {},
13734
- ...executionContext !== void 0 ? {
13735
- executionContext: executionContext
13736
- } : {},
13737
- ...telemetry !== void 0 ? {
13738
- telemetry: telemetry
13739
- } : {},
13740
- instanceId: instanceId,
13741
- effectKey: candidate._key,
13742
- claimToken: claimToken,
13743
- ops: req.ops,
13744
- idempotencyKey: req.idempotencyKey,
13745
- leaseMs: leaseMs,
13746
- clock: clock
13747
- });
13748
- }
13749
- }), {outputs: outputs, ops: ops, dispatchError: dispatchError} = await dispatchEffect({
14117
+ const {handler: handler, candidate: candidate, claimToken: claimToken, retry: retry, leaseMs: leaseMs, sleep: sleep, client: client, handlerClient: handlerClient, tag: tag, workflowResource: workflowResource, resourceClients: resourceClients, instanceId: instanceId, clientFor: clientFor, logger: logger, log: log, executionContext: executionContext, telemetry: telemetry, clock: clock} = args, attemptOnce = attempt => dispatchEffect({
13750
14118
  handler: handler,
13751
14119
  candidate: candidate,
13752
- queue: commitQueue,
14120
+ queue: createEffectCommitQueue({
14121
+ effectKey: candidate._key,
14122
+ claimToken: claimToken,
14123
+ attempt: attempt,
14124
+ commit: async req => {
14125
+ await workflow.commitEffectOps({
14126
+ client: client,
14127
+ tag: tag,
14128
+ workflowResource: workflowResource,
14129
+ ...resourceClients !== void 0 ? {
14130
+ resourceClients: resourceClients
14131
+ } : {},
14132
+ ...executionContext !== void 0 ? {
14133
+ executionContext: executionContext
14134
+ } : {},
14135
+ ...telemetry !== void 0 ? {
14136
+ telemetry: telemetry
14137
+ } : {},
14138
+ instanceId: instanceId,
14139
+ effectKey: candidate._key,
14140
+ claimToken: claimToken,
14141
+ ops: req.ops,
14142
+ idempotencyKey: req.idempotencyKey,
14143
+ leaseMs: leaseMs,
14144
+ clock: clock
14145
+ });
14146
+ }
14147
+ }),
13753
14148
  ctx: {
13754
14149
  client: handlerClient,
13755
14150
  clientFor: clientFor,
13756
14151
  instanceId: instanceId,
13757
14152
  logger: logger
13758
14153
  }
14154
+ }), claimed = {
14155
+ client: client,
14156
+ tag: tag,
14157
+ instanceId: instanceId,
14158
+ effectKey: candidate._key,
14159
+ claimToken: claimToken
14160
+ }, run = await runRetryPolicy({
14161
+ attemptOnce: attemptOnce,
14162
+ ...retry !== void 0 ? {
14163
+ retry: retry
14164
+ } : {},
14165
+ clock: clock,
14166
+ sleep: sleep,
14167
+ holdThrough: holdMs => renewClaimLease({
14168
+ ...claimed,
14169
+ holdMs: holdMs,
14170
+ clock: clock
14171
+ }),
14172
+ stillHeld: () => claimStillHeld(claimed),
14173
+ leaseMs: leaseMs
14174
+ });
14175
+ if (run.abandoned !== void 0) return log.warn(run.abandoned === "lease" ? `Effect "${candidate.name}" could not hold its claim between retry attempts — the run stopped with attempts left` : `Effect "${candidate.name}" was settled by another party during a retry backoff — the run stopped without dispatching again`, {
14176
+ effectKey: candidate._key,
14177
+ instanceId: instanceId
14178
+ }), "lost";
14179
+ const {outputs: outputs, ops: ops, dispatchError: dispatchError} = run.dispatch, detail = retry === void 0 ? void 0 : completionDetail({
14180
+ run: run,
14181
+ retry: retry
13759
14182
  });
13760
14183
  try {
13761
14184
  await reportEffectOutcome({
@@ -13776,6 +14199,9 @@ async function dispatchAndReport(args) {
13776
14199
  outputs: outputs,
13777
14200
  ops: ops,
13778
14201
  dispatchError: dispatchError,
14202
+ ...detail !== void 0 ? {
14203
+ detail: detail
14204
+ } : {},
13779
14205
  clock: clock
13780
14206
  });
13781
14207
  } catch (error) {
@@ -13788,6 +14214,71 @@ async function dispatchAndReport(args) {
13788
14214
  return dispatchError === void 0 ? "drained" : "failed";
13789
14215
  }
13790
14216
 
14217
+ async function runRetryPolicy(args) {
14218
+ const {attemptOnce: attemptOnce, retry: retry, clock: clock} = args, startedAt = Date.parse(clock()), elapsed = () => Date.parse(clock()) - startedAt;
14219
+ let attempt = 1, dispatch = await attemptOnce(attempt);
14220
+ for (;dispatch.dispatchError !== void 0 && retry !== void 0; ) {
14221
+ const at = {
14222
+ attempt: attempt,
14223
+ elapsedMs: elapsed()
14224
+ }, stop = await waitForNextAttempt({
14225
+ retry: retry,
14226
+ at: at,
14227
+ elapsed: elapsed,
14228
+ pace: args
14229
+ });
14230
+ if (stop !== void 0) return {
14231
+ ...stop,
14232
+ dispatch: dispatch,
14233
+ at: at
14234
+ };
14235
+ attempt += 1, dispatch = await attemptOnce(attempt);
14236
+ }
14237
+ return {
14238
+ dispatch: dispatch,
14239
+ at: {
14240
+ attempt: attempt,
14241
+ elapsedMs: elapsed()
14242
+ },
14243
+ windowClosed: !1
14244
+ };
14245
+ }
14246
+
14247
+ async function waitForNextAttempt(args) {
14248
+ const {retry: retry, at: at, elapsed: elapsed} = args, {clock: clock, sleep: sleep, holdThrough: holdThrough, stillHeld: stillHeld, leaseMs: leaseMs} = args.pace, delay = nextRetryDelayMs(retry, at);
14249
+ if (delay === void 0) return {
14250
+ windowClosed: at.attempt < retry.attempts
14251
+ };
14252
+ const heldUntil = await holdThrough(delay + leaseMs);
14253
+ if (heldUntil === void 0 || hasPassed(heldUntil, addMs(clock(), delay))) return {
14254
+ windowClosed: !1,
14255
+ abandoned: "lease"
14256
+ };
14257
+ if (retryWindowClosed(retry, elapsed() + delay)) return {
14258
+ windowClosed: !0
14259
+ };
14260
+ if (await sleep(delay), !await stillHeld()) return {
14261
+ windowClosed: !1,
14262
+ abandoned: "settled"
14263
+ };
14264
+ if (retryWindowClosed(retry, elapsed())) return {
14265
+ windowClosed: !0
14266
+ };
14267
+ }
14268
+
14269
+ function completionDetail(args) {
14270
+ const {run: run, retry: retry} = args, {dispatchError: dispatchError} = run.dispatch;
14271
+ return dispatchError === void 0 ? retrySucceededDetail({
14272
+ at: run.at,
14273
+ attempts: retry.attempts
14274
+ }) : retryFailedDetail({
14275
+ at: run.at,
14276
+ attempts: retry.attempts,
14277
+ error: dispatchError,
14278
+ windowClosed: run.windowClosed
14279
+ });
14280
+ }
14281
+
13791
14282
  async function reportEffectOutcome(args) {
13792
14283
  const {outputs: outputs, ops: ops, dispatchError: dispatchError, resourceClients: resourceClients, ...rest} = args;
13793
14284
  await workflow.completeEffect({
@@ -14078,6 +14569,9 @@ function createInstanceSession(args) {
14078
14569
  definition: definitionOf(),
14079
14570
  actor: actor,
14080
14571
  snapshot: snapshotFrom(held, normalizedSelf),
14572
+ documentAvailability: documentAvailabilityReader({
14573
+ clientForGdr: evalScope.clientForGdr
14574
+ }),
14081
14575
  guards: guards,
14082
14576
  resourceGrants: resourceGrants,
14083
14577
  guardDereference: clientGuardDereference(evalScope.client),
@@ -14491,6 +14985,9 @@ function createEngine(args) {
14491
14985
  telemetry: telemetry,
14492
14986
  ...args.effects?.leaseMs !== void 0 ? {
14493
14987
  leaseMs: args.effects.leaseMs
14988
+ } : {},
14989
+ ...args.sleep !== void 0 ? {
14990
+ sleep: args.sleep
14494
14991
  } : {}
14495
14992
  }), drained = result.drained;
14496
14993
  return (drained.length > 0 || emptyDrainDue()) && telemetry.log(WorkflowEffectsDrained, {
@@ -14512,27 +15009,43 @@ function createEngine(args) {
14512
15009
  const CONSENT_TAG = "telemetry.consent", BATCH_TAG = "telemetry.batch";
14513
15010
 
14514
15011
  function createTelemetryIntake(args) {
14515
- const {client: client, projectId: projectId, denied: denied = !1} = args;
15012
+ const {client: client, projectId: projectId, denied: denied = !1, context: context} = args;
14516
15013
  let cachedConsent;
14517
15014
  return {
14518
15015
  resolveConsent: async () => denied ? {
14519
15016
  status: "denied"
14520
15017
  } : (cachedConsent !== void 0 || (cachedConsent = await client.request({
14521
- uri: "/intake/telemetry-status",
15018
+ url: "/intake/telemetry-status",
14522
15019
  tag: CONSENT_TAG
14523
15020
  })), cachedConsent),
14524
15021
  sendEvents: batch => client.request({
14525
- uri: "/intake/batch",
15022
+ url: "/intake/batch",
14526
15023
  method: "POST",
14527
15024
  body: {
14528
15025
  projectId: projectId,
14529
- batch: batch
15026
+ batch: context === void 0 ? batch : batch.map(event => withContext(event, context))
14530
15027
  },
14531
15028
  tag: BATCH_TAG
14532
15029
  })
14533
15030
  };
14534
15031
  }
14535
15032
 
15033
+ function withContext(event, context) {
15034
+ if (!isRecord(event)) return event;
15035
+ const existing = isRecord(event.context) ? event.context : {};
15036
+ return {
15037
+ ...event,
15038
+ context: {
15039
+ ...existing,
15040
+ ...context
15041
+ }
15042
+ };
15043
+ }
15044
+
15045
+ function _resolveTelemetryEnvironment(nodeEnv, fallback) {
15046
+ return nodeEnv === "production" ? "production" : nodeEnv === "development" || nodeEnv === "test" ? "development" : fallback;
15047
+ }
15048
+
14536
15049
  function isTelemetryEnvDenied(env) {
14537
15050
  return isTrueish(env.CI) || isTrueish(env.DO_NOT_TRACK);
14538
15051
  }
@@ -14555,6 +15068,16 @@ function isTrueish(value) {
14555
15068
  return normalized !== "0" && normalized !== "false";
14556
15069
  }
14557
15070
 
15071
+ function summary(documents, deleted) {
15072
+ if (documents.length === 0) return "";
15073
+ const titles = [ ...new Set(documents.map(document => document.title ?? document.target.field)) ].map(title => `“${title}”`).join(", ");
15074
+ return documents.length === 1 ? `A document selected for ${titles} ${deleted ? "has been deleted" : "can’t be read by this workflow"}` : `${documents.length} documents selected for ${titles} ${deleted ? "have been deleted" : "can’t be read by this workflow"}`;
15075
+ }
15076
+
15077
+ function _missingDocumentsSummary(documents) {
15078
+ return [ summary(documents.filter(document => document.availability === "deleted"), !0), summary(documents.filter(document => document.availability !== "deleted"), !1) ].filter(Boolean).join(". ");
15079
+ }
15080
+
14558
15081
  function groupSitesOf(definition) {
14559
15082
  const sites = [], workflow2 = declarationIndex({
14560
15083
  groups: definition.groups,
@@ -15042,4 +15565,4 @@ function displayDescription(typeKey) {
15042
15565
  if (typeKey) return DISPLAY[typeKey]?.description;
15043
15566
  }
15044
15567
 
15045
- export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, ANONYMOUS_IDENTITY, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCascadeError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MAX_READER, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DECISION_SEMANTICS, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DOCUMENT_VALUE_PERMISSIONS, 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, WorkflowInstancePreviewSchema, WorkflowInstanceSchema, WorkflowInstanceStarted, WorkflowInstanceTicked, WorkflowStageSet, WorkflowStageTransitioned, WorkflowStateDivergedError, abortReason, acceptsDocumentType, aclPathForResource, actionDisabledDetail, actionRendering, actionVerdict, activeAssignmentMembers, activityAutonomyOf, actorFulfillsRole, actorMatchesAssignment, analyzeCondition2 as analyzeCondition, applicableDefinitions, assertReadableModel, assertReaderModelAcknowledgement, assignmentMatch, assignmentMembers, assignmentPrefilter, assignmentState, assignmentStateCounts, atomReadsDataset2 as atomReadsDataset, autonomySummary, availableActions, buildInitialFields, buildSnapshot, checklistLines, classifyPrincipalId, clientConfigFromResource, clientGuardDereference, clientProjectUserDirectory, compileGuards, computeDiffEntries, conditionFieldReadNames, conditionSitesOf, contentDocQuery, contentDraftFallback, contentReleaseName, contextMap, createEngine, createTelemetryIntake, datasetResourceParts, defaultLoggerFactory, definitionDeployedData, definitionLookupGroq, definitionRoleNames, 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, formatRead2 as formatRead, gdrFromResource, gdrRef, gdrUri, groupMembershipNames, groupSitesOf, guardMatches, guardsForDefinition, guardsForInstance, guardsForResource, guillemets2 as guillemets, hasSingleSubjectRequirement, hashDefinitionContent, humanize2 as humanize, identityMatchesAssignment, inFlightFilter, initialFieldIssues, instanceAssignmentStateCounts, instanceChangesQuery, instanceDocId, instanceGuardQuery, instancePreviewsQuery, 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, openActivityAssignments, parentRef, parseDefinitionInput, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseGdr, parseGuardDocument, parseInstanceDocument, parseInstancePreviewDocument, parseResourceGdr, processShellUserProperties, projectStartSliceRow, projectToWatchRef, quoted2 as quoted, readInstanceDoc, readInstancePreviewDoc, readsRaw, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refsOf, rejectedRefTypes, releaseDocId, releaseRef, remediationsFor, requiredDefinitionReaderModel, requiredModelFeatures, requiredReaderModel, resolveAccess, resolveActor, resolveClientActor, resolveFieldEntry$1 as resolveFieldEntry, resolveUserAttributes, resourceAliasesToMap, resourceFromParsed, resourceGdr, retractStageGuards, sameResource, scalarValidationIssues, schemaTreeShape, sentenceCase, silentLogger, singleSubjectRequirementRefused, snapshotGuardDereference, 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 };
15568
+ export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, ANONYMOUS_IDENTITY, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCascadeError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MAX_READER, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DECISION_SEMANTICS, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DOCUMENT_VALUE_PERMISSIONS, 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, WorkflowInstancePreviewSchema, WorkflowInstanceSchema, WorkflowInstanceStarted, WorkflowInstanceTicked, WorkflowStageSet, WorkflowStageTransitioned, WorkflowStateDivergedError, _additionalMissingDocuments, _fieldTargetLabel, _missingDocumentsSummary, _requestProjectMembers, _resolveTelemetryEnvironment, abortReason, acceptsDocumentType, aclPathForResource, actionDisabledDetail, actionRendering, actionVerdict, activeAssignmentMembers, activityAutonomyOf, actorFulfillsRole, actorMatchesAssignment, analyzeCondition2 as analyzeCondition, applicableDefinitions, assertReadableModel, assertReaderModelAcknowledgement, assignmentMatch, assignmentMembers, assignmentPrefilter, assignmentState, assignmentStateCounts, atomReadsDataset2 as atomReadsDataset, autonomySummary, availableActions, buildInitialFields, buildSnapshot, checklistLines, classifyPrincipalId, clientConfigFromResource, clientGuardDereference, clientProjectUserDirectory, compileGuards, computeDiffEntries, conditionFieldReadNames, conditionSitesOf, contentDocQuery, contentDraftFallback, contentReleaseName, contextMap, createEngine, createTelemetryIntake, datasetResourceParts, defaultLoggerFactory, definitionDeployedData, definitionLookupGroq, definitionRoleNames, 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, effectSites, entryDocRefs, errorMessage, evaluateFromSnapshot, evaluateMutationGuard, evaluateStartFilter, expandResourceAliases, explainCondition2 as explainCondition, explainStartRequirement, extractDocumentId, fieldTreeShape, findActivityNode, findCurrentActivityEntry, findOpenStageEntry, findStageNode, formatRead2 as formatRead, gdrFromResource, gdrRef, gdrUri, groupMembershipNames, groupSitesOf, guardMatches, guardsForDefinition, guardsForInstance, guardsForResource, guillemets2 as guillemets, hasSingleSubjectRequirement, hashDefinitionContent, humanize2 as humanize, identityMatchesAssignment, inFlightFilter, initialFieldIssues, instanceAssignmentStateCounts, instanceChangesQuery, instanceDocId, instanceGuardQuery, instancePreviewsQuery, 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, openActivityAssignments, parentRef, parseDefinitionInput, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseGdr, parseGuardDocument, parseInstanceDocument, parseInstancePreviewDocument, parseResourceGdr, processShellUserProperties, projectStartSliceRow, projectToWatchRef, quoted2 as quoted, readInstanceDoc, readInstancePreviewDoc, readsRaw, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refsOf, rejectedRefTypes, releaseDocId, releaseRef, remediationsFor, requiredDefinitionReaderModel, requiredModelFeatures, requiredReaderModel, resolveAccess, resolveActor, resolveClientActor, resolveFieldEntry$1 as resolveFieldEntry, resolveUserAttributes, resourceAliasesToMap, resourceFromParsed, resourceGdr, retractStageGuards, sameResource, scalarValidationIssues, schemaTreeShape, sentenceCase, silentLogger, singleSubjectRequirementRefused, snapshotGuardDereference, 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 };