@sanity/workflow-engine 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -144,6 +144,9 @@ function resolveFieldSite(site, stage) {
144
144
  ...site.entry.validation !== void 0 ? {
145
145
  validation: site.entry.validation
146
146
  } : {},
147
+ ...site.entry.roles !== void 0 ? {
148
+ roles: site.entry.roles
149
+ } : {},
147
150
  ref: {
148
151
  scope: site.scope,
149
152
  field: site.entry.name
@@ -280,58 +283,58 @@ function resolveTelemetry(telemetry) {
280
283
  }
281
284
 
282
285
  const HIGH_FREQUENCY_SAMPLE_MS = 6e4, WorkflowDefinitionDeployed = defineWorkflowEvent({
283
- name: "Editorial Workflows Definition Deployed",
286
+ name: "Workflows Definition Deployed",
284
287
  version: 1,
285
288
  description: "A definition went through a deploy — status distinguishes a newly minted version from an unchanged redeploy"
286
289
  }), WorkflowInstanceStarted = defineWorkflowEvent({
287
- name: "Editorial Workflows Instance Started",
290
+ name: "Workflows Instance Started",
288
291
  version: 1,
289
292
  description: "A workflow instance was started from a deployed definition"
290
293
  }), WorkflowStageTransitioned = defineWorkflowEvent({
291
- name: "Editorial Workflows Stage Transitioned",
294
+ name: "Workflows Stage Transitioned",
292
295
  version: 1,
293
296
  description: "A committed stage move — one event per hop, cascades included, whichever verb drove it. Unsampled: funnel and dwell reads need complete counts, and volume is bounded by actual movement"
294
297
  }), WorkflowActionFired = defineWorkflowEvent({
295
- name: "Editorial Workflows Action Fired",
298
+ name: "Workflows Action Fired",
296
299
  version: 1,
297
300
  description: "An action was fired against an activity"
298
301
  }), WorkflowFieldEdited = defineWorkflowEvent({
299
- name: "Editorial Workflows Field Edited",
302
+ name: "Workflows Field Edited",
300
303
  version: 1,
301
304
  description: "A declared-editable field was edited through the generic edit seam",
302
305
  maxSampleRate: HIGH_FREQUENCY_SAMPLE_MS
303
306
  }), WorkflowInstanceTicked = defineWorkflowEvent({
304
- name: "Editorial Workflows Instance Ticked",
307
+ name: "Workflows Instance Ticked",
305
308
  version: 1,
306
309
  description: "An instance was re-evaluated for auto-transitions and due waits",
307
310
  maxSampleRate: HIGH_FREQUENCY_SAMPLE_MS
308
311
  }), WorkflowEffectsDrained = defineWorkflowEvent({
309
- name: "Editorial Workflows Effects Drained",
312
+ name: "Workflows Effects Drained",
310
313
  version: 1,
311
314
  description: "A drain pass ran — drainedCount/drainedEffects report the successful dispatches. Unsampled when non-empty (outcome counts must be complete; volume is bounded by real effect work); empty polls are machine-cadence noise, throttled engine-side to at most one per minute"
312
315
  }), WorkflowEffectStateReported = defineWorkflowEvent({
313
- name: "Editorial Workflows Effect State Reported",
316
+ name: "Workflows Effect State Reported",
314
317
  version: 1,
315
318
  description: "A running effect handler committed mid-dispatch field state through commitEffectOps. Sampled (high-frequency by design — a dispatch may report many times): an adoption and usage signal, not an exact per-run report count",
316
319
  maxSampleRate: HIGH_FREQUENCY_SAMPLE_MS
317
320
  }), WorkflowEffectCompleted = defineWorkflowEvent({
318
- name: "Editorial Workflows Effect Completed",
321
+ name: "Workflows Effect Completed",
319
322
  version: 1,
320
- description: "An effect outcome was recorded — reported directly through completeEffect, or cancelled by the abort verb (external runtimes; engine-drained effects surface via Editorial Workflows Effects Drained instead — each outcome counts once)"
323
+ description: "An effect outcome was recorded — reported directly through completeEffect, or cancelled by the abort verb (external runtimes; engine-drained effects surface via Workflows Effects Drained instead — each outcome counts once)"
321
324
  }), WorkflowInstanceAborted = defineWorkflowEvent({
322
- name: "Editorial Workflows Instance Aborted",
325
+ name: "Workflows Instance Aborted",
323
326
  version: 1,
324
327
  description: "The abort admin override was invoked (changed: false = instance already terminal)"
325
328
  }), WorkflowStageSet = defineWorkflowEvent({
326
- name: "Editorial Workflows Stage Set",
329
+ name: "Workflows Stage Set",
327
330
  version: 1,
328
331
  description: "The set-stage admin override was invoked (changed: false = already at the target stage)"
329
332
  }), WorkflowActivityReset = defineWorkflowEvent({
330
- name: "Editorial Workflows Activity Reset",
333
+ name: "Workflows Activity Reset",
331
334
  version: 1,
332
335
  description: "The reset-activity admin override was invoked (changed: false = already at the target status, or the instance was terminal)"
333
336
  }), WorkflowDefinitionDeleted = defineWorkflowEvent({
334
- name: "Editorial Workflows Definition Deleted",
337
+ name: "Workflows Definition Deleted",
335
338
  version: 1,
336
339
  description: "A deployed definition (or one version of it) was removed via the admin verb"
337
340
  });
@@ -449,438 +452,131 @@ function fieldEditedData(args) {
449
452
  };
450
453
  }
451
454
 
452
- const DATA_MODEL_VERSION = 7, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
455
+ function effectSites(def) {
456
+ const sites = [];
457
+ for (const stage of def.stages ?? []) for (const activity of stage.activities ?? []) for (const action of activity.actions ?? []) for (const effect of action.effects ?? []) sites.push({
458
+ effect: effect,
459
+ location: `stage[${stage.name}].activity[${activity.name}].action[${action.name}].effects`
460
+ });
461
+ return sites;
462
+ }
453
463
 
454
- class ReaderModelAcknowledgementError extends invariants.WorkflowError {
455
- code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
456
- expectedMinReaderModel;
457
- engineMinReaderModel=DATA_MODEL_MIN_READER;
458
- engineModelVersion=DATA_MODEL_VERSION;
459
- documentationUrl=READER_MODEL_ROLLOUT_URL;
460
- constructor(expectedMinReaderModel, context = "Deployment") {
461
- const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
462
- super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}.\nDo not change the acknowledgement yet: accepting ${DATA_MODEL_MIN_READER} authorizes this engine to write documents that older readers will refuse.\nUpgrade every Studio, CLI, MCP server, Function, and other runtime that reads engine-owned documents; verify that rollout in every environment sharing the workflow resource; then change the literal in deployment configuration and deploy the writer.\nRollout guide: ${READER_MODEL_ROLLOUT_URL}`),
463
- this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
464
- }
464
+ function findEffect(def, name) {
465
+ return effectSites(def).find(site => site.effect.name === name)?.effect;
465
466
  }
466
467
 
467
- function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
468
- if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
468
+ function rolesGateOf(atom) {
469
+ const node = groqConditionDescribe.atomNode(atom);
470
+ if (atom.negated || node.type !== "OpCall" || node.op !== ">" || node.right.type !== "Value" || node.right.value !== 0) return;
471
+ const count = node.left;
472
+ if (!(count.type !== "FuncCall" || count.name !== "count" || count.args.length !== 1)) return rolesFilterList(count.args[0]);
469
473
  }
470
474
 
471
- const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
472
- id: "governed-model-stamps",
473
- introducedInModel: 1,
474
- minReaderModel: 0,
475
- documentTypes: Object.freeze([ "definition", "instance" ]),
476
- compatibility: "additive",
477
- applicability: "unconditional",
478
- summary: "Definition and instance documents carry model provenance and reader-floor stamps."
479
- }), Object.freeze({
480
- id: "subject-field-kind",
481
- introducedInModel: 2,
482
- minReaderModel: 0,
483
- documentTypes: Object.freeze([ "definition", "instance" ]),
484
- compatibility: "additive",
485
- applicability: "detectable",
486
- summary: "A workflow-level subject field identifies the document a workflow is about."
487
- }), Object.freeze({
488
- id: "typed-scalar-choice-lists",
489
- introducedInModel: 2,
490
- minReaderModel: 2,
491
- documentTypes: Object.freeze([ "definition", "instance" ]),
492
- compatibility: "reader-floor",
493
- applicability: "detectable",
494
- summary: "Scalar fields may constrain writes to a persisted typed choice list."
495
- }), Object.freeze({
496
- id: "action-semantics",
497
- introducedInModel: 2,
498
- minReaderModel: 0,
499
- documentTypes: Object.freeze([ "definition" ]),
500
- compatibility: "additive",
501
- applicability: "detectable",
502
- summary: "Ordinary actions may carry advisory workflow semantics."
503
- }), Object.freeze({
504
- id: "inclusive-scalar-bounds",
505
- introducedInModel: 2,
506
- minReaderModel: 2,
507
- documentTypes: Object.freeze([ "definition", "instance" ]),
508
- compatibility: "reader-floor",
509
- applicability: "detectable",
510
- summary: "String, text, and number values may carry persisted inclusive bounds."
511
- }), Object.freeze({
512
- id: "progress-field-kind",
513
- introducedInModel: 3,
514
- minReaderModel: 0,
515
- documentTypes: Object.freeze([ "definition", "instance" ]),
516
- compatibility: "additive",
517
- applicability: "detectable",
518
- summary: "A progress field kind carries application-defined 0–100 completion."
519
- }), Object.freeze({
520
- id: "effect-claim-tokens",
521
- introducedInModel: 3,
522
- minReaderModel: 0,
523
- documentTypes: Object.freeze([ "instance" ]),
524
- compatibility: "additive",
525
- applicability: "detectable",
526
- summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
527
- }), Object.freeze({
528
- id: "classified-principal-ids",
529
- introducedInModel: 4,
530
- minReaderModel: 4,
531
- documentTypes: Object.freeze([ "instance" ]),
532
- compatibility: "reader-floor",
533
- applicability: "unconditional",
534
- summary: "Principal ids are namespace-classified: actor and assignee writes carry the account-global user id only, and readers resolve legacy project-scoped ids through the prefix classifier at the instance read funnel."
535
- }), Object.freeze({
536
- id: "readiness-requirements",
537
- introducedInModel: 4,
538
- minReaderModel: 4,
539
- documentTypes: Object.freeze([ "definition" ]),
540
- compatibility: "reader-floor",
541
- applicability: "detectable",
542
- summary: "Start and activity readiness use named polymorphic requirement arrays."
543
- }), Object.freeze({
544
- id: "due-date-field-kinds",
545
- introducedInModel: 5,
546
- minReaderModel: 0,
547
- documentTypes: Object.freeze([ "definition", "instance" ]),
548
- compatibility: "additive",
549
- applicability: "detectable",
550
- summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
551
- }), Object.freeze({
552
- id: "node-semantics",
553
- introducedInModel: 6,
554
- minReaderModel: 0,
555
- documentTypes: Object.freeze([ "definition" ]),
556
- compatibility: "additive",
557
- applicability: "detectable",
558
- summary: "Workflow, stage, activity, and action nodes may carry signal or custom advisory semantics."
559
- }), Object.freeze({
560
- id: "field-patch-ops",
561
- introducedInModel: 6,
562
- minReaderModel: 0,
563
- documentTypes: Object.freeze([ "definition", "instance" ]),
564
- compatibility: "additive",
565
- applicability: "detectable",
566
- summary: "Field ops may increment, decrement, or initialize a missing field value."
567
- }), Object.freeze({
568
- id: "attributes-condition-var",
569
- introducedInModel: 7,
570
- minReaderModel: 0,
571
- documentTypes: Object.freeze([ "definition" ]),
572
- compatibility: "additive",
573
- applicability: "unconditional",
574
- summary: "Caller-bound $attributes condition variable binds the acting token's org-level User Attributes (advisory; absent when unavailable)."
575
- }) ]);
475
+ function rolesFilterList(node) {
476
+ if (node.type !== "Filter") return;
477
+ const base = node.base;
478
+ if (!(base.type === "AccessAttribute" && base.name === "roles" && base.base?.type === "Parameter" && base.base.name === "actor")) return;
479
+ const expr = node.expr;
480
+ if (expr.type !== "OpCall" || expr.op !== "in" || expr.left.type !== "This" || expr.right.type !== "Array") return;
481
+ const roles = expr.right.elements.flatMap(element => !element.isSplat && element.value.type === "Value" && typeof element.value.value == "string" ? [ element.value.value ] : []);
482
+ if (roles.length === expr.right.elements.length) return roles;
483
+ }
576
484
 
577
- function recordOf(value) {
578
- return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
485
+ function deriveWorkflowAutonomy(definition, options = {}) {
486
+ return workflowAutonomy({
487
+ definition: definition,
488
+ children: options.children ?? /* @__PURE__ */ new Map,
489
+ lineage: /* @__PURE__ */ new Set
490
+ });
579
491
  }
580
492
 
581
- function recordsAt(record, key) {
582
- const value = record[key];
583
- return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
493
+ function stageAutonomyOf(autonomy, stageName) {
494
+ const stage = autonomy.stages.find(candidate => candidate.stage === stageName);
495
+ if (stage === void 0) throw new Error(`Autonomy rollup is missing stage "${stageName}"`);
496
+ return stage;
584
497
  }
585
498
 
586
- function nestedFieldEntries(entries) {
587
- return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
499
+ function activityAutonomyOf(stageAutonomy2, activityName) {
500
+ const answer = stageAutonomy2.activities[activityName];
501
+ if (answer === void 0) throw new Error(`Autonomy rollup is missing activity "${activityName}" in stage "${stageAutonomy2.stage}"`);
502
+ return answer;
588
503
  }
589
504
 
590
- function parsedDefinitionSnapshot(root) {
591
- if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
592
- _id: typeof root._id == "string" ? root._id : "<unknown instance>",
593
- definitionSnapshot: root.definitionSnapshot
594
- }));
505
+ const AUTONOMOUS = {
506
+ completesWithoutCaller: "yes",
507
+ waitsOn: []
508
+ }, UNDECIDABLE = {
509
+ completesWithoutCaller: "conditional",
510
+ waitsOn: []
511
+ }, CALLER = {
512
+ completesWithoutCaller: "no",
513
+ waitsOn: []
514
+ }, VERDICT_RANK = {
515
+ yes: 0,
516
+ conditional: 1,
517
+ no: 2
518
+ };
519
+
520
+ function allOf(deps) {
521
+ return {
522
+ completesWithoutCaller: deps.map(dep => dep.completesWithoutCaller).reduce((worst, verdict) => VERDICT_RANK[verdict] > VERDICT_RANK[worst] ? verdict : worst, "yes"),
523
+ waitsOn: mergeWaits(deps)
524
+ };
595
525
  }
596
526
 
597
- function persistedDefinitionTree(document) {
598
- const root = recordOf(document);
599
- if (root === void 0) return;
600
- const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], {stages: stages, activities: activities, actions: actions} = definitionDescendants(roots);
527
+ function anyOf(deps) {
528
+ const [first, ...rest] = deps;
529
+ if (first === void 0) throw new Error("anyOf needs at least one route — callers guard empties");
601
530
  return {
602
- roots: roots,
603
- stages: stages,
604
- activities: activities,
605
- actions: actions
531
+ completesWithoutCaller: rest.every(dep => dep.completesWithoutCaller === first.completesWithoutCaller) ? first.completesWithoutCaller : "conditional",
532
+ waitsOn: mergeWaits(deps)
606
533
  };
607
534
  }
608
535
 
609
- function persistedFieldEntries(document) {
610
- const tree = persistedDefinitionTree(document);
611
- if (tree === void 0) return [];
612
- const {roots: roots, stages: stages, activities: activities, actions: actions} = tree, effects = actions.flatMap(action => recordsAt(action, "effects"));
613
- return nestedFieldEntries([ ...roots.flatMap(candidate => recordsAt(candidate, "fields")), ...stages.flatMap(stage => recordsAt(stage, "fields")), ...activities.flatMap(activity => recordsAt(activity, "fields")), ...actions.flatMap(action => recordsAt(action, "params")), ...effects.flatMap(effect => recordsAt(effect, "outputs")) ]);
536
+ function mergeWaits(deps) {
537
+ return groqConditionDescribe.dedupeBy(deps.flatMap(dep => dep.waitsOn), wait => JSON.stringify(wait));
614
538
  }
615
539
 
616
- function definitionDescendants(roots) {
617
- const stages = roots.flatMap(root => recordsAt(root, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions"));
540
+ function analysisCtx(args) {
541
+ const memo = /* @__PURE__ */ new Map, visiting = /* @__PURE__ */ new Set;
618
542
  return {
619
- stages: stages,
620
- activities: activities,
621
- actions: actions
543
+ ...args,
544
+ memoized: (key, compute) => {
545
+ const hit = memo.get(key);
546
+ if (hit !== void 0) return hit;
547
+ if (visiting.has(key)) return UNDECIDABLE;
548
+ visiting.add(key);
549
+ try {
550
+ const answer = compute();
551
+ return memo.set(key, answer), answer;
552
+ } finally {
553
+ visiting.delete(key);
554
+ }
555
+ }
622
556
  };
623
557
  }
624
558
 
625
- function hasChoiceList(document) {
626
- return persistedFieldEntries(document).some(entry => {
627
- const options = recordOf(entry.options);
628
- return options !== void 0 && Array.isArray(options.list);
629
- });
630
- }
631
-
632
- function hasFieldKind(document, kind) {
633
- return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
559
+ function workflowAutonomy(args) {
560
+ const ctx = analysisCtx({
561
+ definition: args.definition,
562
+ children: args.children,
563
+ lineage: /* @__PURE__ */ new Set([ ...args.lineage, args.definition.name ])
564
+ }), stages = ctx.definition.stages.map(stage => stageAutonomy(stage, ctx));
565
+ return {
566
+ ...allOf(stages),
567
+ stages: stages
568
+ };
634
569
  }
635
570
 
636
- function definitionNodes(document) {
637
- const root = recordOf(document);
638
- if (root !== void 0) return {
639
- root: root,
640
- ...definitionDescendants([ root ])
641
- };
642
- }
643
-
644
- function hasActionSemantics(document) {
645
- return definitionNodes(document)?.actions.some(hasSemantics) ?? !1;
646
- }
647
-
648
- function hasNodeSemantics(document) {
649
- const nodes = definitionNodes(document);
650
- return nodes === void 0 ? !1 : [ nodes.root, ...nodes.stages, ...nodes.activities ].some(hasSemantics) ? !0 : nodes.actions.some(action => hasSemantics(action) && action.semantics.some(isNodeSemanticValue));
651
- }
652
-
653
- function isNodeSemanticValue(semantic) {
654
- return typeof semantic == "string" && (semantic.startsWith("signal.") || semantic.startsWith("custom."));
655
- }
656
-
657
- function hasSemantics(node) {
658
- return Array.isArray(node.semantics);
659
- }
660
-
661
- function hasPersistedOpType(document, types) {
662
- const tree = persistedDefinitionTree(document);
663
- return tree === void 0 ? !1 : tree.actions.flatMap(action => recordsAt(action, "ops")).some(op => typeof op.type == "string" && types.includes(op.type)) ? !0 : tree.roots.some(root => recordsAt(root, "history").some(entry => entry._type === "opApplied" && typeof entry.opType == "string" && types.includes(entry.opType)));
664
- }
665
-
666
- function hasScalarValidation(document) {
667
- return persistedFieldEntries(document).some(entry => {
668
- const validation = recordOf(entry.validation);
669
- return typeof validation?.min == "number" || typeof validation?.max == "number";
670
- });
671
- }
672
-
673
- function hasClaimTokens(document) {
674
- const root = recordOf(document);
675
- return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
676
- const claim = recordOf(entry.claim);
677
- return claim !== void 0 && typeof claim.claimToken == "string";
678
- });
679
- }
680
-
681
- function hasReadinessRequirements(document) {
682
- const root = recordOf(document);
683
- return root === void 0 ? !1 : Array.isArray(recordOf(root.start)?.requirements) ? !0 : recordsAt(root, "stages").some(stage => recordsAt(stage, "activities").some(activity => Array.isArray(activity.requirements)));
684
- }
685
-
686
- const featureDetectors = {
687
- "governed-model-stamps": () => !0,
688
- "subject-field-kind": document => hasFieldKind(document, "subject"),
689
- "typed-scalar-choice-lists": hasChoiceList,
690
- "action-semantics": hasActionSemantics,
691
- "inclusive-scalar-bounds": hasScalarValidation,
692
- "progress-field-kind": document => hasFieldKind(document, "progress"),
693
- "effect-claim-tokens": hasClaimTokens,
694
- "classified-principal-ids": () => !0,
695
- "readiness-requirements": hasReadinessRequirements,
696
- "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime"),
697
- "node-semantics": hasNodeSemantics,
698
- "field-patch-ops": document => hasPersistedOpType(document, [ "field.inc", "field.dec", "field.setIfMissing" ]),
699
- "attributes-condition-var": () => !0
700
- };
701
-
702
- function requiredModelFeatures(documentType, document) {
703
- return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
704
- }
705
-
706
- function requiredReaderModel(documentType, document) {
707
- return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
708
- }
709
-
710
- function modelStampFor(args) {
711
- return {
712
- modelVersion: DATA_MODEL_VERSION,
713
- minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
714
- };
715
- }
716
-
717
- function fieldTreeShape(value) {
718
- if (Array.isArray(value)) return value.map(fieldTreeShape);
719
- if (value === null) return "null";
720
- if (typeof value == "object") {
721
- const record = value;
722
- return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
723
- }
724
- return typeof value;
725
- }
726
-
727
- function modelVersionOf(doc) {
728
- const stamp = doc.modelVersion;
729
- return typeof stamp == "number" ? stamp : 0;
730
- }
731
-
732
- function minReaderModelOf(doc) {
733
- const floor = doc.minReaderModel;
734
- return typeof floor == "number" ? floor : modelVersionOf(doc);
735
- }
736
-
737
- class ModelVersionAheadError extends invariants.WorkflowError {
738
- documentId;
739
- documentModelVersion;
740
- requiredReaderModel;
741
- engineModelVersion;
742
- constructor(args) {
743
- super("model-version-ahead", `Document "${args.documentId}" was written by engine data model ${args.documentModelVersion} and requires a reader at model ${args.requiredReaderModel} or newer; this engine reads up to model ${DATA_MODEL_VERSION}. Upgrade @sanity/workflow-engine to a version that understands it.`),
744
- this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
745
- this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
746
- }
747
- }
748
-
749
- function assertReadableModel(doc) {
750
- const documentReaderModel = minReaderModelOf(doc);
751
- if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
752
- documentId: doc._id,
753
- documentModelVersion: modelVersionOf(doc),
754
- requiredReaderModel: documentReaderModel
755
- });
756
- return doc;
757
- }
758
-
759
- function effectSites(def) {
760
- const sites = [];
761
- for (const stage of def.stages ?? []) for (const activity of stage.activities ?? []) for (const action of activity.actions ?? []) for (const effect of action.effects ?? []) sites.push({
762
- effect: effect,
763
- location: `stage[${stage.name}].activity[${activity.name}].action[${action.name}].effects`
764
- });
765
- return sites;
766
- }
767
-
768
- function findEffect(def, name) {
769
- return effectSites(def).find(site => site.effect.name === name)?.effect;
770
- }
771
-
772
- function rolesGateOf(atom) {
773
- const node = groqConditionDescribe.atomNode(atom);
774
- if (atom.negated || node.type !== "OpCall" || node.op !== ">" || node.right.type !== "Value" || node.right.value !== 0) return;
775
- const count = node.left;
776
- if (!(count.type !== "FuncCall" || count.name !== "count" || count.args.length !== 1)) return rolesFilterList(count.args[0]);
777
- }
778
-
779
- function rolesFilterList(node) {
780
- if (node.type !== "Filter") return;
781
- const base = node.base;
782
- if (!(base.type === "AccessAttribute" && base.name === "roles" && base.base?.type === "Parameter" && base.base.name === "actor")) return;
783
- const expr = node.expr;
784
- if (expr.type !== "OpCall" || expr.op !== "in" || expr.left.type !== "This" || expr.right.type !== "Array") return;
785
- const roles = expr.right.elements.flatMap(element => !element.isSplat && element.value.type === "Value" && typeof element.value.value == "string" ? [ element.value.value ] : []);
786
- if (roles.length === expr.right.elements.length) return roles;
787
- }
788
-
789
- function deriveWorkflowAutonomy(definition, options = {}) {
790
- return workflowAutonomy({
791
- definition: definition,
792
- children: options.children ?? /* @__PURE__ */ new Map,
793
- lineage: /* @__PURE__ */ new Set
794
- });
795
- }
796
-
797
- function stageAutonomyOf(autonomy, stageName) {
798
- const stage = autonomy.stages.find(candidate => candidate.stage === stageName);
799
- if (stage === void 0) throw new Error(`Autonomy rollup is missing stage "${stageName}"`);
800
- return stage;
801
- }
802
-
803
- function activityAutonomyOf(stageAutonomy2, activityName) {
804
- const answer = stageAutonomy2.activities[activityName];
805
- if (answer === void 0) throw new Error(`Autonomy rollup is missing activity "${activityName}" in stage "${stageAutonomy2.stage}"`);
806
- return answer;
807
- }
808
-
809
- const AUTONOMOUS = {
810
- completesWithoutCaller: "yes",
811
- waitsOn: []
812
- }, UNDECIDABLE = {
813
- completesWithoutCaller: "conditional",
814
- waitsOn: []
815
- }, CALLER = {
816
- completesWithoutCaller: "no",
817
- waitsOn: []
818
- }, VERDICT_RANK = {
819
- yes: 0,
820
- conditional: 1,
821
- no: 2
822
- };
823
-
824
- function allOf(deps) {
825
- return {
826
- completesWithoutCaller: deps.map(dep => dep.completesWithoutCaller).reduce((worst, verdict) => VERDICT_RANK[verdict] > VERDICT_RANK[worst] ? verdict : worst, "yes"),
827
- waitsOn: mergeWaits(deps)
828
- };
829
- }
830
-
831
- function anyOf(deps) {
832
- const [first, ...rest] = deps;
833
- if (first === void 0) throw new Error("anyOf needs at least one route — callers guard empties");
834
- return {
835
- completesWithoutCaller: rest.every(dep => dep.completesWithoutCaller === first.completesWithoutCaller) ? first.completesWithoutCaller : "conditional",
836
- waitsOn: mergeWaits(deps)
837
- };
838
- }
839
-
840
- function mergeWaits(deps) {
841
- return groqConditionDescribe.dedupeBy(deps.flatMap(dep => dep.waitsOn), wait => JSON.stringify(wait));
842
- }
843
-
844
- function analysisCtx(args) {
845
- const memo = /* @__PURE__ */ new Map, visiting = /* @__PURE__ */ new Set;
846
- return {
847
- ...args,
848
- memoized: (key, compute) => {
849
- const hit = memo.get(key);
850
- if (hit !== void 0) return hit;
851
- if (visiting.has(key)) return UNDECIDABLE;
852
- visiting.add(key);
853
- try {
854
- const answer = compute();
855
- return memo.set(key, answer), answer;
856
- } finally {
857
- visiting.delete(key);
858
- }
859
- }
860
- };
861
- }
862
-
863
- function workflowAutonomy(args) {
864
- const ctx = analysisCtx({
865
- definition: args.definition,
866
- children: args.children,
867
- lineage: /* @__PURE__ */ new Set([ ...args.lineage, args.definition.name ])
868
- }), stages = ctx.definition.stages.map(stage => stageAutonomy(stage, ctx));
869
- return {
870
- ...allOf(stages),
871
- stages: stages
872
- };
873
- }
874
-
875
- function stageAutonomy(stage, ctx) {
876
- const activities = Object.fromEntries((stage.activities ?? []).map(activity => [ activity.name, activityCompletion({
877
- stage: stage,
878
- activity: activity
879
- }, ctx) ]));
880
- return {
881
- ...stageProgress(stage, ctx),
882
- stage: stage.name,
883
- activities: activities
571
+ function stageAutonomy(stage, ctx) {
572
+ const activities = Object.fromEntries((stage.activities ?? []).map(activity => [ activity.name, activityCompletion({
573
+ stage: stage,
574
+ activity: activity
575
+ }, ctx) ]));
576
+ return {
577
+ ...stageProgress(stage, ctx),
578
+ stage: stage.name,
579
+ activities: activities
884
580
  };
885
581
  }
886
582
 
@@ -2171,10 +1867,6 @@ function derefBase(ref, snapshot) {
2171
1867
  };
2172
1868
  }
2173
1869
 
2174
- function isRecord(value) {
2175
- return typeof value == "object" && value !== null && !Array.isArray(value);
2176
- }
2177
-
2178
1870
  function buildParams(args) {
2179
1871
  const {instance: instance, now: now, snapshot: snapshot, extra: extra} = args, currentActivities2 = findOpenStageEntry(instance)?.activities ?? [];
2180
1872
  return {
@@ -2711,38 +2403,7 @@ function isFieldOp(summary) {
2711
2403
 
2712
2404
  function validateActionParams({action: action, activityName: activityName, callerParams: callerParams}) {
2713
2405
  const declared = action.params ?? [], params = callerParams ?? {}, issues = [];
2714
- for (const decl of declared) {
2715
- const value = params[decl.name], present = decl.name in params && value !== void 0 && value !== null;
2716
- if (decl.required === !0 && !present) {
2717
- issues.push({
2718
- param: decl.name,
2719
- reason: "required but missing"
2720
- });
2721
- continue;
2722
- }
2723
- if (!present) continue;
2724
- if (!checkParamType(value, decl)) {
2725
- issues.push({
2726
- param: decl.name,
2727
- reason: `expected type=${decl.type}, got ${typeof value}`
2728
- });
2729
- continue;
2730
- }
2731
- const choiceIssues = invariants.choiceValueIssues(decl.options, value);
2732
- choiceIssues !== void 0 && issues.push({
2733
- param: decl.name,
2734
- reason: choiceIssues.join("; ")
2735
- });
2736
- const validationIssues = invariants.scalarValidationIssues({
2737
- entryType: decl.type,
2738
- validation: decl.validation,
2739
- value: value
2740
- });
2741
- validationIssues !== void 0 && issues.push({
2742
- param: decl.name,
2743
- reason: validationIssues.join("; ")
2744
- });
2745
- }
2406
+ for (const decl of declared) issues.push(...declaredParamIssues(decl, params));
2746
2407
  if (issues.length > 0) throw new ActionParamsInvalidError({
2747
2408
  action: action.name,
2748
2409
  activity: activityName,
@@ -2751,8 +2412,32 @@ function validateActionParams({action: action, activityName: activityName, calle
2751
2412
  return params;
2752
2413
  }
2753
2414
 
2754
- function hasStringField(value, field) {
2755
- return typeof value == "object" && value !== null && field in value && typeof value[field] == "string";
2415
+ function declaredParamIssues(decl, params) {
2416
+ const value = params[decl.name];
2417
+ if (!(decl.name in params && value !== void 0 && value !== null)) return decl.required === !0 ? [ {
2418
+ param: decl.name,
2419
+ reason: "required but missing"
2420
+ } ] : [];
2421
+ if (!checkParamType(value, decl)) return [ {
2422
+ param: decl.name,
2423
+ reason: `expected type=${decl.type}, got ${typeof value}`
2424
+ } ];
2425
+ const choiceIssues = invariants.choiceValueIssues(decl.options, value), validationIssues = invariants.scalarValidationIssues({
2426
+ entryType: decl.type,
2427
+ validation: decl.validation,
2428
+ value: value
2429
+ });
2430
+ return [ ...choiceIssues === void 0 ? [] : [ {
2431
+ param: decl.name,
2432
+ reason: choiceIssues.join("; ")
2433
+ } ], ...validationIssues === void 0 ? [] : [ {
2434
+ param: decl.name,
2435
+ reason: validationIssues.join("; ")
2436
+ } ] ];
2437
+ }
2438
+
2439
+ function hasStringField(value, field) {
2440
+ return typeof value == "object" && value !== null && field in value && typeof value[field] == "string";
2756
2441
  }
2757
2442
 
2758
2443
  function checkParamType(value, decl) {
@@ -2802,7 +2487,9 @@ async function runOps(args) {
2802
2487
  now: now,
2803
2488
  snapshot: snapshot,
2804
2489
  refSurface: refSurface,
2805
- opsFromDefinition: opsFromDefinition
2490
+ opsFromDefinition: opsFromDefinition,
2491
+ memberRoles: args.memberRoles,
2492
+ roleAliases: args.roleAliases
2806
2493
  });
2807
2494
  summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
2808
2495
  origin: origin,
@@ -2923,7 +2610,12 @@ function applyFieldSet(op, ctx) {
2923
2610
  entryType: entry._type,
2924
2611
  entryName: entry.name,
2925
2612
  value: value,
2926
- ...entryShape(entry)
2613
+ ...entryShape(entry),
2614
+ memberRoles: ctx.memberRoles,
2615
+ roleAliases: ctx.roleAliases,
2616
+ ...entry._type === "assignees" || entry._type === "object" || entry._type === "array" ? {
2617
+ previousValue: entry.value
2618
+ } : {}
2927
2619
  });
2928
2620
  return assertRuntimeRefsWithinSurface({
2929
2621
  entryType: entry._type,
@@ -3020,7 +2712,17 @@ function entryShape(entry) {
3020
2712
  of: entry.of
3021
2713
  } : invariants.isSingleDocRefEntry(entry) || entry._type === "doc.refs" ? entry.types !== void 0 ? {
3022
2714
  types: entry.types
3023
- } : {} : {
2715
+ } : {} : invariants.isAssignmentFieldEntry(entry) ? assignmentEntryShape(entry) : scalarEntryShape(entry);
2716
+ }
2717
+
2718
+ function assignmentEntryShape(entry) {
2719
+ return entry.roles !== void 0 ? {
2720
+ roles: entry.roles
2721
+ } : {};
2722
+ }
2723
+
2724
+ function scalarEntryShape(entry) {
2725
+ return {
3024
2726
  ...entry.options !== void 0 ? {
3025
2727
  options: entry.options
3026
2728
  } : {},
@@ -3069,7 +2771,10 @@ function applyFieldAppend(op, ctx) {
3069
2771
  entryName: entry.name,
3070
2772
  item: item,
3071
2773
  types: entry._type === "doc.refs" ? entry.types : void 0,
3072
- of: entry._type === "array" ? entry.of : void 0
2774
+ of: entry._type === "array" ? entry.of : void 0,
2775
+ roles: entry._type === "assignees" ? entry.roles : void 0,
2776
+ memberRoles: ctx.memberRoles,
2777
+ roleAliases: ctx.roleAliases
3073
2778
  });
3074
2779
  assertRuntimeRefsWithinSurface({
3075
2780
  entryType: entry._type === "doc.refs" ? "doc.ref" : "object",
@@ -3090,7 +2795,7 @@ function applyFieldAppend(op, ctx) {
3090
2795
  }
3091
2796
 
3092
2797
  function withRowKey(item) {
3093
- return isRecord(item) && !("_key" in item) ? {
2798
+ return invariants.isRecord(item) && !("_key" in item) ? {
3094
2799
  _key: randomKey(),
3095
2800
  ...item
3096
2801
  } : item;
@@ -3117,6 +2822,13 @@ async function applyFieldUpdateWhere(op, ctx) {
3117
2822
  merge: mergeRecord,
3118
2823
  entry: entry,
3119
2824
  op: op
2825
+ }), invariants.validateFieldValue({
2826
+ entryType: "array",
2827
+ entryName: entry.name,
2828
+ value: [ mergeRecord ],
2829
+ of: entry.of,
2830
+ memberRoles: ctx.memberRoles,
2831
+ roleAliases: ctx.roleAliases
3120
2832
  });
3121
2833
  const matches = await rowMatches({
3122
2834
  where: op.where,
@@ -3233,18 +2945,6 @@ function subSlot(target, field) {
3233
2945
  function resolveOpValue(args) {
3234
2946
  const {src: src, ctx: ctx, target: target} = args;
3235
2947
  switch (src.type) {
3236
- case "literal":
3237
- case "param":
3238
- case "actor":
3239
- case "now":
3240
- return resolveStaticValueExpr(src, ctx);
3241
-
3242
- case "self":
3243
- return ctx.self;
3244
-
3245
- case "stage":
3246
- return ctx.stage;
3247
-
3248
2948
  case "fieldRead":
3249
2949
  {
3250
2950
  const entry = readEntryFromMutation(ctx, src);
@@ -3274,6 +2974,25 @@ function resolveOpValue(args) {
3274
2974
  }
3275
2975
  return out;
3276
2976
  }
2977
+
2978
+ default:
2979
+ return resolveAtomicOpValue(src, ctx);
2980
+ }
2981
+ }
2982
+
2983
+ function resolveAtomicOpValue(src, ctx) {
2984
+ switch (src.type) {
2985
+ case "literal":
2986
+ case "param":
2987
+ case "actor":
2988
+ case "now":
2989
+ return resolveStaticValueExpr(src, ctx);
2990
+
2991
+ case "self":
2992
+ return ctx.self;
2993
+
2994
+ case "stage":
2995
+ return ctx.stage;
3277
2996
  }
3278
2997
  }
3279
2998
 
@@ -3724,88 +3443,429 @@ async function assertInstanceWriteAllowed(args) {
3724
3443
  });
3725
3444
  }
3726
3445
 
3727
- async function renderConditionScope(source, opts) {
3728
- const {instance: instance, definition: definition, snapshot: snapshot, now: now} = source, base = buildParams({
3729
- instance: instance,
3730
- now: now,
3731
- snapshot: snapshot
3732
- }), fields = {
3733
- ...base.fields,
3734
- ...scopedFieldOverlay({
3735
- instance: instance,
3736
- snapshot: snapshot,
3737
- activityName: opts?.activityName
3738
- })
3739
- }, params = {
3740
- ...base,
3741
- fields: fields,
3742
- actor: opts?.actor,
3743
- assigned: opts?.activityName !== void 0 ? assignedFor({
3744
- instance: instance,
3745
- activityName: opts.activityName,
3746
- actor: opts?.actor,
3747
- roleAliases: definition.roleAliases
3748
- }) : !1,
3749
- ...opts?.vars
3750
- };
3751
- return {
3752
- ...await invariants.evaluatePredicates({
3753
- predicates: definition.predicates,
3754
- snapshot: snapshot,
3755
- params: params
3756
- }),
3757
- ...params
3758
- };
3759
- }
3446
+ const DATA_MODEL_VERSION = 8, DATA_MODEL_MIN_READER = 4, DATA_MODEL_MAX_READER = 8, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
3760
3447
 
3761
- function definitionLookupGroq(explicit) {
3762
- const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && name == $definition && ${invariants.tagScopeFilter()}`;
3763
- return explicit ? `*[${scoped} && version == $version][0]` : `*[${scoped}] | order(version desc)[0]`;
3448
+ class ReaderModelAcknowledgementError extends invariants.WorkflowError {
3449
+ code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
3450
+ expectedMinReaderModel;
3451
+ requiredMinReaderModel;
3452
+ engineMinReaderModel=DATA_MODEL_MIN_READER;
3453
+ engineMaxReaderModel=DATA_MODEL_MAX_READER;
3454
+ engineModelVersion=DATA_MODEL_VERSION;
3455
+ documentationUrl=READER_MODEL_ROLLOUT_URL;
3456
+ constructor(expectedMinReaderModel, options = {}) {
3457
+ const {context: context = "Deployment", requiredMinReaderModel: requiredMinReaderModel = DATA_MODEL_MIN_READER} = options, expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
3458
+ super("reader-model-acknowledgement", `${context} acknowledges reader model ${expected}; the submitted definitions require at least ${requiredMinReaderModel}, and this writer supports acknowledgements through ${DATA_MODEL_MAX_READER}.\nUse a reviewed numeric literal in that range. Before raising it, ensure every runtime sharing the workflow resource can read the required model.\nRollout guide: ${READER_MODEL_ROLLOUT_URL}`),
3459
+ this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel,
3460
+ this.requiredMinReaderModel = requiredMinReaderModel;
3461
+ }
3764
3462
  }
3765
3463
 
3766
- function definitionsListGroq(versionOrder) {
3767
- return `*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}] | order(name asc, version ${versionOrder})`;
3464
+ function assertReaderModelAcknowledgement(expectedMinReaderModel, options) {
3465
+ const {context: context, requiredMinReaderModel: requiredMinReaderModel} = options;
3466
+ if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel < requiredMinReaderModel || expectedMinReaderModel > DATA_MODEL_MAX_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, {
3467
+ requiredMinReaderModel: requiredMinReaderModel,
3468
+ ...context !== void 0 ? {
3469
+ context: context
3470
+ } : {}
3471
+ });
3768
3472
  }
3769
3473
 
3770
- function latestDefinitionsGroq() {
3771
- const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}`;
3772
- return `*[${scoped} && version == math::max(*[${scoped} && name == ^.name].version)] | order(name asc)`;
3773
- }
3474
+ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
3475
+ id: "governed-model-stamps",
3476
+ introducedInModel: 1,
3477
+ minReaderModel: 0,
3478
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3479
+ compatibility: "additive",
3480
+ applicability: "unconditional",
3481
+ summary: "Definition and instance documents carry model provenance and reader-floor stamps."
3482
+ }), Object.freeze({
3483
+ id: "subject-field-kind",
3484
+ introducedInModel: 2,
3485
+ minReaderModel: 0,
3486
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3487
+ compatibility: "additive",
3488
+ applicability: "detectable",
3489
+ summary: "A workflow-level subject field identifies the document a workflow is about."
3490
+ }), Object.freeze({
3491
+ id: "typed-scalar-choice-lists",
3492
+ introducedInModel: 2,
3493
+ minReaderModel: 2,
3494
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3495
+ compatibility: "reader-floor",
3496
+ applicability: "detectable",
3497
+ summary: "Scalar fields may constrain writes to a persisted typed choice list."
3498
+ }), Object.freeze({
3499
+ id: "action-semantics",
3500
+ introducedInModel: 2,
3501
+ minReaderModel: 0,
3502
+ documentTypes: Object.freeze([ "definition" ]),
3503
+ compatibility: "additive",
3504
+ applicability: "detectable",
3505
+ summary: "Ordinary actions may carry advisory workflow semantics."
3506
+ }), Object.freeze({
3507
+ id: "inclusive-scalar-bounds",
3508
+ introducedInModel: 2,
3509
+ minReaderModel: 2,
3510
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3511
+ compatibility: "reader-floor",
3512
+ applicability: "detectable",
3513
+ summary: "String, text, and number values may carry persisted inclusive bounds."
3514
+ }), Object.freeze({
3515
+ id: "progress-field-kind",
3516
+ introducedInModel: 3,
3517
+ minReaderModel: 0,
3518
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3519
+ compatibility: "additive",
3520
+ applicability: "detectable",
3521
+ summary: "A progress field kind carries application-defined 0–100 completion."
3522
+ }), Object.freeze({
3523
+ id: "effect-claim-tokens",
3524
+ introducedInModel: 3,
3525
+ minReaderModel: 0,
3526
+ documentTypes: Object.freeze([ "instance" ]),
3527
+ compatibility: "additive",
3528
+ applicability: "detectable",
3529
+ summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
3530
+ }), Object.freeze({
3531
+ id: "classified-principal-ids",
3532
+ introducedInModel: 4,
3533
+ minReaderModel: 4,
3534
+ documentTypes: Object.freeze([ "instance" ]),
3535
+ compatibility: "reader-floor",
3536
+ applicability: "unconditional",
3537
+ summary: "Principal ids are namespace-classified: actor and assignee writes carry the account-global user id only, and readers resolve legacy project-scoped ids through the prefix classifier at the instance read funnel."
3538
+ }), Object.freeze({
3539
+ id: "readiness-requirements",
3540
+ introducedInModel: 4,
3541
+ minReaderModel: 4,
3542
+ documentTypes: Object.freeze([ "definition" ]),
3543
+ compatibility: "reader-floor",
3544
+ applicability: "detectable",
3545
+ summary: "Start and activity readiness use named polymorphic requirement arrays."
3546
+ }), Object.freeze({
3547
+ id: "due-date-field-kinds",
3548
+ introducedInModel: 5,
3549
+ minReaderModel: 0,
3550
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3551
+ compatibility: "additive",
3552
+ applicability: "detectable",
3553
+ summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
3554
+ }), Object.freeze({
3555
+ id: "node-semantics",
3556
+ introducedInModel: 6,
3557
+ minReaderModel: 0,
3558
+ documentTypes: Object.freeze([ "definition" ]),
3559
+ compatibility: "additive",
3560
+ applicability: "detectable",
3561
+ summary: "Workflow, stage, activity, and action nodes may carry signal or custom advisory semantics."
3562
+ }), Object.freeze({
3563
+ id: "field-patch-ops",
3564
+ introducedInModel: 6,
3565
+ minReaderModel: 0,
3566
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3567
+ compatibility: "additive",
3568
+ applicability: "detectable",
3569
+ summary: "Field ops may increment, decrement, or initialize a missing field value."
3570
+ }), Object.freeze({
3571
+ id: "attributes-condition-var",
3572
+ introducedInModel: 7,
3573
+ minReaderModel: 0,
3574
+ documentTypes: Object.freeze([ "definition" ]),
3575
+ compatibility: "additive",
3576
+ applicability: "unconditional",
3577
+ summary: "Caller-bound $attributes condition variable binds the acting token's org-level User Attributes (advisory; absent when unavailable)."
3578
+ }), Object.freeze({
3579
+ id: "role-constrained-assignment-fields",
3580
+ introducedInModel: 8,
3581
+ minReaderModel: 8,
3582
+ documentTypes: Object.freeze([ "definition", "instance" ]),
3583
+ compatibility: "reader-floor",
3584
+ applicability: "detectable",
3585
+ summary: "Assignee fields may restrict newly assigned users and collective roles by role."
3586
+ }) ]);
3774
3587
 
3775
- function deployedTagsGroq() {
3776
- return `array::unique(*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}"].tag) | order(@ asc)`;
3588
+ function recordOf(value) {
3589
+ return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
3777
3590
  }
3778
3591
 
3779
- function definitionTagsGroq() {
3780
- return `array::unique(*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && name == $definition].tag) | order(@ asc)`;
3592
+ function recordsAt(record, key) {
3593
+ const value = record[key];
3594
+ return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
3781
3595
  }
3782
3596
 
3783
- function latestDeployedDefinitions(rows) {
3784
- const byName = /* @__PURE__ */ new Map;
3785
- for (const row of rows) {
3786
- const held = byName.get(row.name);
3787
- (held === void 0 || row.version > held.version) && byName.set(row.name, row);
3788
- }
3789
- return [ ...byName.values() ];
3597
+ function nestedFieldEntries(entries) {
3598
+ return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
3790
3599
  }
3791
3600
 
3792
- function findStageNode(args) {
3793
- return args.definition?.stages.find(entry => entry.name === args.stageName);
3601
+ function parsedDefinitionSnapshot(root) {
3602
+ if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
3603
+ _id: typeof root._id == "string" ? root._id : "<unknown instance>",
3604
+ definitionSnapshot: root.definitionSnapshot
3605
+ }));
3794
3606
  }
3795
3607
 
3796
- function findActivityNode(args) {
3797
- return findStageNode(args)?.activities?.find(entry => entry.name === args.activityName);
3608
+ function persistedDefinitionTree(document) {
3609
+ const root = recordOf(document);
3610
+ if (root === void 0) return;
3611
+ const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], {stages: stages, activities: activities, actions: actions} = definitionDescendants(roots);
3612
+ return {
3613
+ roots: roots,
3614
+ stages: stages,
3615
+ activities: activities,
3616
+ actions: actions
3617
+ };
3798
3618
  }
3799
3619
 
3800
- function liveChildrenField(instance) {
3801
- const live = liveSubworkflows(instance).length;
3802
- return live > 0 ? {
3803
- liveChildren: live
3804
- } : {};
3620
+ function persistedFieldEntries(document) {
3621
+ const tree = persistedDefinitionTree(document);
3622
+ if (tree === void 0) return [];
3623
+ const {roots: roots, stages: stages, activities: activities, actions: actions} = tree, effects = actions.flatMap(action => recordsAt(action, "effects"));
3624
+ return nestedFieldEntries([ ...roots.flatMap(candidate => recordsAt(candidate, "fields")), ...stages.flatMap(stage => recordsAt(stage, "fields")), ...activities.flatMap(activity => recordsAt(activity, "fields")), ...actions.flatMap(action => recordsAt(action, "params")), ...effects.flatMap(effect => recordsAt(effect, "outputs")) ]);
3805
3625
  }
3806
3626
 
3807
- function abortReason(instance) {
3808
- return instance.history.find(h => h._type === "aborted")?.reason;
3627
+ function definitionDescendants(roots) {
3628
+ const stages = roots.flatMap(root => recordsAt(root, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions"));
3629
+ return {
3630
+ stages: stages,
3631
+ activities: activities,
3632
+ actions: actions
3633
+ };
3634
+ }
3635
+
3636
+ function hasChoiceList(document) {
3637
+ return persistedFieldEntries(document).some(entry => {
3638
+ const options = recordOf(entry.options);
3639
+ return options !== void 0 && Array.isArray(options.list);
3640
+ });
3641
+ }
3642
+
3643
+ function entryHasKind(entry, kind) {
3644
+ return entryKindMatches(entry, candidate => candidate === kind);
3645
+ }
3646
+
3647
+ function entryKindMatches(entry, accepts) {
3648
+ return [ entry.type, entry._type ].some(kind => typeof kind == "string" && accepts(kind));
3649
+ }
3650
+
3651
+ function hasFieldKind(document, kind) {
3652
+ return persistedFieldEntries(document).some(entry => entryHasKind(entry, kind));
3653
+ }
3654
+
3655
+ function definitionNodes(document) {
3656
+ const root = recordOf(document);
3657
+ if (root !== void 0) return {
3658
+ root: root,
3659
+ ...definitionDescendants([ root ])
3660
+ };
3661
+ }
3662
+
3663
+ function hasActionSemantics(document) {
3664
+ return definitionNodes(document)?.actions.some(hasSemantics) ?? !1;
3665
+ }
3666
+
3667
+ function hasNodeSemantics(document) {
3668
+ const nodes = definitionNodes(document);
3669
+ return nodes === void 0 ? !1 : [ nodes.root, ...nodes.stages, ...nodes.activities ].some(hasSemantics) ? !0 : nodes.actions.some(action => hasSemantics(action) && action.semantics.some(isNodeSemanticValue));
3670
+ }
3671
+
3672
+ function isNodeSemanticValue(semantic) {
3673
+ return typeof semantic == "string" && (semantic.startsWith("signal.") || semantic.startsWith("custom."));
3674
+ }
3675
+
3676
+ function hasSemantics(node) {
3677
+ return Array.isArray(node.semantics);
3678
+ }
3679
+
3680
+ function hasPersistedOpType(document, types) {
3681
+ const tree = persistedDefinitionTree(document);
3682
+ return tree === void 0 ? !1 : tree.actions.flatMap(action => recordsAt(action, "ops")).some(op => typeof op.type == "string" && types.includes(op.type)) ? !0 : tree.roots.some(root => recordsAt(root, "history").some(entry => entry._type === "opApplied" && typeof entry.opType == "string" && types.includes(entry.opType)));
3683
+ }
3684
+
3685
+ function hasScalarValidation(document) {
3686
+ return persistedFieldEntries(document).some(entry => {
3687
+ const validation = recordOf(entry.validation);
3688
+ return typeof validation?.min == "number" || typeof validation?.max == "number";
3689
+ });
3690
+ }
3691
+
3692
+ function hasClaimTokens(document) {
3693
+ const root = recordOf(document);
3694
+ return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
3695
+ const claim = recordOf(entry.claim);
3696
+ return claim !== void 0 && typeof claim.claimToken == "string";
3697
+ });
3698
+ }
3699
+
3700
+ function hasReadinessRequirements(document) {
3701
+ const root = recordOf(document);
3702
+ return root === void 0 ? !1 : Array.isArray(recordOf(root.start)?.requirements) ? !0 : recordsAt(root, "stages").some(stage => recordsAt(stage, "activities").some(activity => Array.isArray(activity.requirements)));
3703
+ }
3704
+
3705
+ function hasRoleConstrainedAssignments(document) {
3706
+ return persistedFieldEntries(document).some(entry => entryKindMatches(entry, invariants.assignmentKindAcceptsRoles) && Array.isArray(entry.roles) && entry.roles.length > 0);
3707
+ }
3708
+
3709
+ const featureDetectors = {
3710
+ "governed-model-stamps": () => !0,
3711
+ "subject-field-kind": document => hasFieldKind(document, "subject"),
3712
+ "typed-scalar-choice-lists": hasChoiceList,
3713
+ "action-semantics": hasActionSemantics,
3714
+ "inclusive-scalar-bounds": hasScalarValidation,
3715
+ "progress-field-kind": document => hasFieldKind(document, "progress"),
3716
+ "effect-claim-tokens": hasClaimTokens,
3717
+ "classified-principal-ids": () => !0,
3718
+ "readiness-requirements": hasReadinessRequirements,
3719
+ "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime"),
3720
+ "role-constrained-assignment-fields": hasRoleConstrainedAssignments,
3721
+ "node-semantics": hasNodeSemantics,
3722
+ "field-patch-ops": document => hasPersistedOpType(document, [ "field.inc", "field.dec", "field.setIfMissing" ]),
3723
+ "attributes-condition-var": () => !0
3724
+ };
3725
+
3726
+ function requiredModelFeatures(documentType, document) {
3727
+ return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
3728
+ }
3729
+
3730
+ function requiredReaderModel(documentType, document) {
3731
+ return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
3732
+ }
3733
+
3734
+ function requiredDefinitionReaderModel(definitions) {
3735
+ return Math.max(DATA_MODEL_MIN_READER, ...definitions.map(definition => requiredReaderModel("definition", definition)));
3736
+ }
3737
+
3738
+ function modelStampFor(args) {
3739
+ return {
3740
+ modelVersion: DATA_MODEL_VERSION,
3741
+ minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
3742
+ };
3743
+ }
3744
+
3745
+ function fieldTreeShape(value) {
3746
+ if (Array.isArray(value)) return value.map(fieldTreeShape);
3747
+ if (value === null) return "null";
3748
+ if (typeof value == "object") {
3749
+ const record = value;
3750
+ return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
3751
+ }
3752
+ return typeof value;
3753
+ }
3754
+
3755
+ function modelVersionOf(doc) {
3756
+ const stamp = doc.modelVersion;
3757
+ return typeof stamp == "number" ? stamp : 0;
3758
+ }
3759
+
3760
+ function minReaderModelOf(doc) {
3761
+ const floor = doc.minReaderModel;
3762
+ return typeof floor == "number" ? floor : modelVersionOf(doc);
3763
+ }
3764
+
3765
+ class ModelVersionAheadError extends invariants.WorkflowError {
3766
+ documentId;
3767
+ documentModelVersion;
3768
+ requiredReaderModel;
3769
+ engineModelVersion;
3770
+ constructor(args) {
3771
+ super("model-version-ahead", `Document "${args.documentId}" was written by engine data model ${args.documentModelVersion} and requires a reader at model ${args.requiredReaderModel} or newer; this engine reads up to model ${DATA_MODEL_VERSION}. Upgrade @sanity/workflow-engine to a version that understands it.`),
3772
+ this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
3773
+ this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
3774
+ }
3775
+ }
3776
+
3777
+ function assertReadableModel(doc) {
3778
+ const documentReaderModel = minReaderModelOf(doc);
3779
+ if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
3780
+ documentId: doc._id,
3781
+ documentModelVersion: modelVersionOf(doc),
3782
+ requiredReaderModel: documentReaderModel
3783
+ });
3784
+ return doc;
3785
+ }
3786
+
3787
+ async function renderConditionScope(source, opts) {
3788
+ const {instance: instance, definition: definition, snapshot: snapshot, now: now} = source, base = buildParams({
3789
+ instance: instance,
3790
+ now: now,
3791
+ snapshot: snapshot
3792
+ }), fields = {
3793
+ ...base.fields,
3794
+ ...scopedFieldOverlay({
3795
+ instance: instance,
3796
+ snapshot: snapshot,
3797
+ activityName: opts?.activityName
3798
+ })
3799
+ }, params = {
3800
+ ...base,
3801
+ fields: fields,
3802
+ actor: opts?.actor,
3803
+ assigned: opts?.activityName !== void 0 ? assignedFor({
3804
+ instance: instance,
3805
+ activityName: opts.activityName,
3806
+ actor: opts?.actor,
3807
+ roleAliases: definition.roleAliases
3808
+ }) : !1,
3809
+ ...opts?.vars
3810
+ };
3811
+ return {
3812
+ ...await invariants.evaluatePredicates({
3813
+ predicates: definition.predicates,
3814
+ snapshot: snapshot,
3815
+ params: params
3816
+ }),
3817
+ ...params
3818
+ };
3819
+ }
3820
+
3821
+ function definitionLookupGroq(explicit) {
3822
+ const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && name == $definition && ${invariants.tagScopeFilter()}`;
3823
+ return explicit ? `*[${scoped} && version == $version][0]` : `*[${scoped}] | order(version desc)[0]`;
3824
+ }
3825
+
3826
+ function definitionsListGroq(versionOrder) {
3827
+ return `*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}] | order(name asc, version ${versionOrder})`;
3828
+ }
3829
+
3830
+ function latestDefinitionsGroq() {
3831
+ const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}`;
3832
+ return `*[${scoped} && version == math::max(*[${scoped} && name == ^.name].version)] | order(name asc)`;
3833
+ }
3834
+
3835
+ function deployedTagsGroq() {
3836
+ return `array::unique(*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}"].tag) | order(@ asc)`;
3837
+ }
3838
+
3839
+ function definitionTagsGroq() {
3840
+ return `array::unique(*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && name == $definition].tag) | order(@ asc)`;
3841
+ }
3842
+
3843
+ function latestDeployedDefinitions(rows) {
3844
+ const byName = /* @__PURE__ */ new Map;
3845
+ for (const row of rows) {
3846
+ const held = byName.get(row.name);
3847
+ (held === void 0 || row.version > held.version) && byName.set(row.name, row);
3848
+ }
3849
+ return [ ...byName.values() ];
3850
+ }
3851
+
3852
+ function findStageNode(args) {
3853
+ return args.definition?.stages.find(entry => entry.name === args.stageName);
3854
+ }
3855
+
3856
+ function findActivityNode(args) {
3857
+ return findStageNode(args)?.activities?.find(entry => entry.name === args.activityName);
3858
+ }
3859
+
3860
+ function liveChildrenField(instance) {
3861
+ const live = liveSubworkflows(instance).length;
3862
+ return live > 0 ? {
3863
+ liveChildren: live
3864
+ } : {};
3865
+ }
3866
+
3867
+ function abortReason(instance) {
3868
+ return instance.history.find(h => h._type === "aborted")?.reason;
3809
3869
  }
3810
3870
 
3811
3871
  function diagnoseInputFromEvaluation(evaluation) {
@@ -3933,60 +3993,260 @@ function diagnoseInstance(input) {
3933
3993
  };
3934
3994
  }
3935
3995
 
3936
- const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
3937
-
3938
- function remediationsForCause(cause) {
3939
- switch (cause.kind) {
3940
- case "failed-effect":
3941
- return [ {
3942
- verb: "retry-effect",
3943
- rationale: "Re-run the failed effect once the upstream system is healthy."
3944
- }, {
3945
- verb: "abort",
3946
- rationale: "Abort the instance if it can no longer recover."
3947
- } ];
3948
-
3949
- case "hung-effect":
3950
- return [ {
3951
- verb: "drain-effects",
3952
- rationale: "Re-run the effect drainer — the runtime that registered the effect handlers — to re-pick the claimed effect."
3953
- }, {
3954
- verb: "abort",
3955
- rationale: "Abort the instance if the effect never drains."
3956
- } ];
3957
-
3958
- case "failed-activity":
3959
- return [ {
3960
- verb: "reset-activity",
3961
- rationale: "Reset or skip the failed activity."
3962
- }, {
3963
- verb: "set-stage",
3964
- rationale: "Move the instance past the failed activity to the intended next stage."
3965
- } ];
3966
-
3967
- case "no-transition-fires":
3968
- return [ {
3969
- verb: "set-stage",
3970
- rationale: "Move the instance to the intended next stage to force it forward."
3971
- } ];
3972
-
3973
- case "transition-unevaluable":
3974
- return [];
3975
- }
3996
+ const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
3997
+
3998
+ function remediationsForCause(cause) {
3999
+ switch (cause.kind) {
4000
+ case "failed-effect":
4001
+ return [ {
4002
+ verb: "retry-effect",
4003
+ rationale: "Re-run the failed effect once the upstream system is healthy."
4004
+ }, {
4005
+ verb: "abort",
4006
+ rationale: "Abort the instance if it can no longer recover."
4007
+ } ];
4008
+
4009
+ case "hung-effect":
4010
+ return [ {
4011
+ verb: "drain-effects",
4012
+ rationale: "Re-run the effect drainer — the runtime that registered the effect handlers — to re-pick the claimed effect."
4013
+ }, {
4014
+ verb: "abort",
4015
+ rationale: "Abort the instance if the effect never drains."
4016
+ } ];
4017
+
4018
+ case "failed-activity":
4019
+ return [ {
4020
+ verb: "reset-activity",
4021
+ rationale: "Reset or skip the failed activity."
4022
+ }, {
4023
+ verb: "set-stage",
4024
+ rationale: "Move the instance past the failed activity to the intended next stage."
4025
+ } ];
4026
+
4027
+ case "no-transition-fires":
4028
+ return [ {
4029
+ verb: "set-stage",
4030
+ rationale: "Move the instance to the intended next stage to force it forward."
4031
+ } ];
4032
+
4033
+ case "transition-unevaluable":
4034
+ return [];
4035
+ }
4036
+ }
4037
+
4038
+ function remediationsFor(diagnosis) {
4039
+ return diagnosis.state !== "stuck" ? [] : remediationsForCause(diagnosis.cause).map(seed => ({
4040
+ ...seed,
4041
+ available: RUNNABLE_VERBS.has(seed.verb)
4042
+ }));
4043
+ }
4044
+
4045
+ function isClaimExpired(claim, now) {
4046
+ return claim.leaseExpiresAt === void 0 || hasPassed(claim.leaseExpiresAt, now);
4047
+ }
4048
+
4049
+ const EFFECT_RUN_STATUSES = [ "done", "failed", "cancelled" ];
4050
+
4051
+ function userLoginProvider(user) {
4052
+ return user?.provider ?? user?.loginProvider;
4053
+ }
4054
+
4055
+ function optionalString(value) {
4056
+ return value === void 0 || typeof value == "string";
4057
+ }
4058
+
4059
+ function isClientProjectUser(value) {
4060
+ return invariants.isRecord(value) && typeof value.id == "string" && optionalString(value.sanityUserId) && optionalString(value.displayName) && optionalString(value.email) && (value.imageUrl === null || optionalString(value.imageUrl)) && optionalString(value.provider) && optionalString(value.loginProvider);
4061
+ }
4062
+
4063
+ function objectProperty(value, property) {
4064
+ if (!invariants.isRecord(value)) return;
4065
+ const propertyValue = value[property];
4066
+ return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
4067
+ }
4068
+
4069
+ function stringProperty(value, property) {
4070
+ const propertyValue = Reflect.get(value, property);
4071
+ return typeof propertyValue == "string" ? propertyValue : void 0;
4072
+ }
4073
+
4074
+ function apiErrorType(error) {
4075
+ const response = objectProperty(error, "response"), body = objectProperty(response, "body");
4076
+ if (!body) return;
4077
+ const nestedError = objectProperty(body, "error");
4078
+ return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
4079
+ }
4080
+
4081
+ function isProjectUserNotFoundError(error) {
4082
+ return apiErrorType(error) === "projectUserNotFoundError";
4083
+ }
4084
+
4085
+ const memberJoinCache = /* @__PURE__ */ new WeakMap;
4086
+
4087
+ function joinCacheFor(client) {
4088
+ let cache = memberJoinCache.get(client);
4089
+ return cache === void 0 && (cache = /* @__PURE__ */ new Map, memberJoinCache.set(client, cache)),
4090
+ cache;
4091
+ }
4092
+
4093
+ function isClientProjectMember(value) {
4094
+ return invariants.isRecord(value) && typeof value.id == "string";
4095
+ }
4096
+
4097
+ async function requestProjectMembers(request, projectId) {
4098
+ const project = await request({
4099
+ uri: `/projects/${encodeURIComponent(projectId)}`
4100
+ }), members = invariants.isRecord(project) ? project.members : void 0;
4101
+ if (!Array.isArray(members) || !members.every(isClientProjectMember)) throw new Error(`Project member directory response is invalid for project "${projectId}"`);
4102
+ return members;
4103
+ }
4104
+
4105
+ async function requestProjectUsers(args) {
4106
+ const {request: request, projectId: projectId, memberIds: memberIds} = args, response = await request({
4107
+ uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
4108
+ }), rows = Array.isArray(response) ? response : [ response ];
4109
+ if (!rows.every(isClientProjectUser)) throw new Error(`Project user directory response is invalid for project "${projectId}"`);
4110
+ const requested = new Set(memberIds);
4111
+ return rows.filter(row => requested.has(row.id));
4112
+ }
4113
+
4114
+ async function requestProjectMemberDirectory(args) {
4115
+ const {request: request, projectId: projectId} = args, members = await requestProjectMembers(request, projectId), memberIds = members.map(member => member.id).filter(id => invariants.classifyPrincipalId(id).namespace === "project");
4116
+ if (memberIds.length === 0) return {
4117
+ members: members,
4118
+ globalUsers: []
4119
+ };
4120
+ const users = await requestProjectUsers({
4121
+ request: request,
4122
+ projectId: projectId,
4123
+ memberIds: memberIds
4124
+ });
4125
+ return {
4126
+ members: members,
4127
+ globalUsers: users.flatMap(user => {
4128
+ const globalId = invariants.directoryBridgeId(user.sanityUserId);
4129
+ return globalId === void 0 ? [] : [ {
4130
+ memberId: user.id,
4131
+ globalId: globalId,
4132
+ user: user
4133
+ } ];
4134
+ })
4135
+ };
4136
+ }
4137
+
4138
+ async function resolveGlobalProjectUser(args) {
4139
+ const {client: client, request: request, projectId: projectId, id: id} = args, cache = joinCacheFor(client), key = `${projectId}:${id}`, hit = cache.get(key);
4140
+ if (hit !== void 0) return hit === null ? {
4141
+ status: "missing"
4142
+ } : {
4143
+ status: "resolved",
4144
+ user: hit
4145
+ };
4146
+ try {
4147
+ await ingestMemberJoin({
4148
+ request: request,
4149
+ projectId: projectId,
4150
+ cache: cache
4151
+ });
4152
+ const found = cache.get(key);
4153
+ return found != null ? {
4154
+ status: "resolved",
4155
+ user: found
4156
+ } : (cache.set(key, null), {
4157
+ status: "missing"
4158
+ });
4159
+ } catch (cause) {
4160
+ return {
4161
+ status: "inaccessible",
4162
+ cause: cause
4163
+ };
4164
+ }
4165
+ }
4166
+
4167
+ async function ingestMemberJoin(args) {
4168
+ const {request: request, projectId: projectId, cache: cache} = args, snapshot = await requestProjectMemberDirectory({
4169
+ request: request,
4170
+ projectId: projectId
4171
+ });
4172
+ for (const {globalId: globalId, user: user} of snapshot.globalUsers) cache.set(`${projectId}:${globalId}`, user);
4173
+ }
4174
+
4175
+ function clientProjectUserDirectory(client, projectId) {
4176
+ return {
4177
+ findById: async id => {
4178
+ if (!client.request) return {
4179
+ status: "inaccessible",
4180
+ cause: new Error("Project-user resolution requires WorkflowClient.request")
4181
+ };
4182
+ if (invariants.classifyPrincipalId(id).namespace === "global") return resolveGlobalProjectUser({
4183
+ client: client,
4184
+ request: client.request,
4185
+ projectId: projectId,
4186
+ id: id
4187
+ });
4188
+ try {
4189
+ const response = await client.request({
4190
+ uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
4191
+ }), candidate = Array.isArray(response) ? response[0] : response;
4192
+ return candidate == null ? {
4193
+ status: "missing"
4194
+ } : isClientProjectUser(candidate) ? candidate.id !== id ? {
4195
+ status: "inaccessible",
4196
+ cause: new Error(`Project-user response answered id "${candidate.id}", not the requested "${id}"`)
4197
+ } : {
4198
+ status: "resolved",
4199
+ user: candidate
4200
+ } : {
4201
+ status: "inaccessible",
4202
+ cause: new Error("Project-user response had an invalid shape")
4203
+ };
4204
+ } catch (cause) {
4205
+ return isProjectUserNotFoundError(cause) ? {
4206
+ status: "missing"
4207
+ } : {
4208
+ status: "inaccessible",
4209
+ cause: cause
4210
+ };
4211
+ }
4212
+ }
4213
+ };
4214
+ }
4215
+
4216
+ function resolveClientActor(client, args) {
4217
+ return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
3976
4218
  }
3977
4219
 
3978
- function remediationsFor(diagnosis) {
3979
- return diagnosis.state !== "stuck" ? [] : remediationsForCause(diagnosis.cause).map(seed => ({
3980
- ...seed,
3981
- available: RUNNABLE_VERBS.has(seed.verb)
3982
- }));
4220
+ async function resolveActor(directory, actor) {
4221
+ if (actor.kind !== "person") return {
4222
+ status: "not-person",
4223
+ actor: actor
4224
+ };
4225
+ const personActor = {
4226
+ ...actor,
4227
+ kind: "person"
4228
+ }, lookup = await directory.findById(personActor.id);
4229
+ return lookup.status === "resolved" ? {
4230
+ status: "resolved",
4231
+ actor: personActor,
4232
+ user: lookup.user
4233
+ } : lookup.status === "inaccessible" ? {
4234
+ status: "inaccessible",
4235
+ actor: personActor,
4236
+ ...lookup.cause === void 0 ? {} : {
4237
+ cause: lookup.cause
4238
+ }
4239
+ } : {
4240
+ status: "missing",
4241
+ actor: personActor
4242
+ };
3983
4243
  }
3984
4244
 
3985
- function isClaimExpired(claim, now) {
3986
- return claim.leaseExpiresAt === void 0 || hasPassed(claim.leaseExpiresAt, now);
4245
+ function assertRoleConstrainedAssignmentResource(args) {
4246
+ if (hasRoleConstrainedAssignments(args.definition) && args.workflowResource.type !== "dataset") throw new Error(`${args.context}: definition "${args.definition.name}" uses role-constrained assignment fields, which require a dataset workflow resource; received resource type "${args.workflowResource.type}"`);
3987
4247
  }
3988
4248
 
3989
- const EFFECT_RUN_STATUSES = [ "done", "failed", "cancelled" ], EXECUTION_KINDS = {
4249
+ const EXECUTION_KINDS = {
3990
4250
  interactive: "interactive",
3991
4251
  server: "server",
3992
4252
  cli: "cli",
@@ -4409,6 +4669,9 @@ function buildResolvedEntry({entry: entry, value: value, _key: _key, now: now})
4409
4669
  ...entry.validation !== void 0 ? {
4410
4670
  validation: entry.validation
4411
4671
  } : {},
4672
+ ...entry.roles !== void 0 ? {
4673
+ roles: entry.roles
4674
+ } : {},
4412
4675
  value: value,
4413
4676
  ...entry.initialValue?.type === "query" ? {
4414
4677
  resolvedAt: now
@@ -4440,7 +4703,10 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
4440
4703
  fields: entry.fields,
4441
4704
  of: entry.of,
4442
4705
  options: entry.options,
4443
- validation: entry.validation
4706
+ validation: entry.validation,
4707
+ roles: entry.roles,
4708
+ memberRoles: ctx.memberRoles,
4709
+ roleAliases: ctx.roleAliases
4444
4710
  });
4445
4711
  return "issues" in check ? (ctx.recordDiscard?.({
4446
4712
  field: entry.name,
@@ -4465,7 +4731,10 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
4465
4731
  fields: entry.fields,
4466
4732
  of: entry.of,
4467
4733
  options: entry.options,
4468
- validation: entry.validation
4734
+ validation: entry.validation,
4735
+ roles: entry.roles,
4736
+ memberRoles: ctx.memberRoles,
4737
+ roleAliases: ctx.roleAliases
4469
4738
  });
4470
4739
  return entry.initialValue?.type === "input" && ctx.inputProvenance !== "definition" && assertRefsWithinSurface({
4471
4740
  entryType: entry.type,
@@ -4559,7 +4828,7 @@ function coerceToGdr(raw, workflowResource) {
4559
4828
  } : null;
4560
4829
  }
4561
4830
 
4562
- const NonEmpty = invariants.NonEmptyString, UnknownRecord = v__namespace.record(v__namespace.string(), v__namespace.unknown()), PersistedChoiceOptionsSchema = v__namespace.looseObject({
4831
+ const NonEmpty = invariants.NonEmptyString, PersistedAssignmentRolesSchema = v__namespace.pipe(v__namespace.array(invariants.NonEmptyString), v__namespace.minLength(1, "assignment roles must not be empty")), UnknownRecord = v__namespace.record(v__namespace.string(), v__namespace.unknown()), PersistedChoiceOptionsSchema = v__namespace.looseObject({
4563
4832
  list: v__namespace.array(v__namespace.looseObject({
4564
4833
  title: v__namespace.string(),
4565
4834
  value: v__namespace.union([ v__namespace.string(), v__namespace.number() ])
@@ -4574,6 +4843,7 @@ const NonEmpty = invariants.NonEmptyString, UnknownRecord = v__namespace.record(
4574
4843
  description: v__namespace.optional(v__namespace.string()),
4575
4844
  options: v__namespace.optional(PersistedChoiceOptionsSchema),
4576
4845
  validation: v__namespace.optional(PersistedScalarValidationSchema),
4846
+ roles: v__namespace.optional(PersistedAssignmentRolesSchema),
4577
4847
  fields: v__namespace.optional(v__namespace.array(PersistedFieldShapeSchema)),
4578
4848
  of: v__namespace.optional(v__namespace.array(PersistedFieldShapeSchema))
4579
4849
  }))), ExecutionContextSchema = invariants.tolerantObject()({
@@ -4619,7 +4889,13 @@ const OptionalRefTypes = v__namespace.exactOptional(v__namespace.array(v__namesp
4619
4889
  })), v__namespace.looseObject(invariants.tolerantEntries()({
4620
4890
  ...fieldArm("subject", invariants.fieldValueSchemas.subject),
4621
4891
  types: OptionalRefTypes
4622
- })), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("release.ref", invariants.fieldValueSchemas["release.ref"]))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("string", invariants.fieldValueSchemas.string))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("text", invariants.fieldValueSchemas.text))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("number", invariants.fieldValueSchemas.number))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("progress", invariants.fieldValueSchemas.progress))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("boolean", invariants.fieldValueSchemas.boolean))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("date", invariants.fieldValueSchemas.date))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("dueDate", invariants.fieldValueSchemas.dueDate))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("datetime", invariants.fieldValueSchemas.datetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("dueDatetime", invariants.fieldValueSchemas.dueDatetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("url", invariants.fieldValueSchemas.url))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("actor", invariants.fieldValueSchemas.actor))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignee", invariants.fieldValueSchemas.assignee))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignees", invariants.fieldValueSchemas.assignees))), v__namespace.looseObject(invariants.tolerantEntries()({
4892
+ })), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("release.ref", invariants.fieldValueSchemas["release.ref"]))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("string", invariants.fieldValueSchemas.string))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("text", invariants.fieldValueSchemas.text))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("number", invariants.fieldValueSchemas.number))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("progress", invariants.fieldValueSchemas.progress))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("boolean", invariants.fieldValueSchemas.boolean))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("date", invariants.fieldValueSchemas.date))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("dueDate", invariants.fieldValueSchemas.dueDate))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("datetime", invariants.fieldValueSchemas.datetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("dueDatetime", invariants.fieldValueSchemas.dueDatetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("url", invariants.fieldValueSchemas.url))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("actor", invariants.fieldValueSchemas.actor))), v__namespace.looseObject(invariants.tolerantEntries()({
4893
+ ...fieldArm("assignee", invariants.fieldValueSchemas.assignee),
4894
+ roles: v__namespace.exactOptional(PersistedAssignmentRolesSchema)
4895
+ })), v__namespace.looseObject(invariants.tolerantEntries()({
4896
+ ...fieldArm("assignees", invariants.fieldValueSchemas.assignees),
4897
+ roles: v__namespace.exactOptional(PersistedAssignmentRolesSchema)
4898
+ })), v__namespace.looseObject(invariants.tolerantEntries()({
4623
4899
  ...fieldArm("object", v__namespace.union([ v__namespace.null(), UnknownRecord ])),
4624
4900
  fields: v__namespace.array(PersistedFieldShapeSchema)
4625
4901
  })), v__namespace.looseObject(invariants.tolerantEntries()({
@@ -4870,6 +5146,37 @@ function parseInstanceDocument(doc) {
4870
5146
  });
4871
5147
  }
4872
5148
 
5149
+ const WorkflowInstancePreviewEffectSchema = invariants.tolerantObject()({
5150
+ name: NonEmpty,
5151
+ title: v__namespace.exactOptional(v__namespace.string())
5152
+ }), WorkflowInstancePreviewSchema = v__namespace.looseObject(invariants.tolerantEntries()({
5153
+ _id: NonEmpty,
5154
+ _type: v__namespace.literal(WORKFLOW_INSTANCE_TYPE),
5155
+ modelVersion: v__namespace.exactOptional(v__namespace.number()),
5156
+ minReaderModel: v__namespace.exactOptional(v__namespace.number()),
5157
+ workflowResource: WorkflowResourceSchema,
5158
+ definition: NonEmpty,
5159
+ pinnedVersion: v__namespace.number(),
5160
+ fields: v__namespace.array(ResolvedFieldEntrySchema),
5161
+ ancestors: v__namespace.array(invariants.GdrShape),
5162
+ perspective: v__namespace.exactOptional(WorkflowPerspectiveSchema),
5163
+ currentStage: NonEmpty,
5164
+ stages: v__namespace.array(StageEntrySchema),
5165
+ claimedEffects: v__namespace.array(WorkflowInstancePreviewEffectSchema),
5166
+ failedEffects: v__namespace.array(WorkflowInstancePreviewEffectSchema),
5167
+ startedAt: invariants.IsoTimestamp,
5168
+ completedAt: v__namespace.exactOptional(invariants.IsoTimestamp),
5169
+ abortedAt: v__namespace.exactOptional(invariants.IsoTimestamp)
5170
+ }));
5171
+
5172
+ function parseInstancePreviewDocument(doc) {
5173
+ return invariants.parsePersistedDoc({
5174
+ schema: WorkflowInstancePreviewSchema,
5175
+ doc: doc,
5176
+ docType: WORKFLOW_INSTANCE_TYPE
5177
+ });
5178
+ }
5179
+
4873
5180
  const SYNC_COMMIT = {
4874
5181
  visibility: "sync"
4875
5182
  }, ENGINE_API_VERSION = "2026-04-29", REQUEST_TAG = {
@@ -5317,6 +5624,40 @@ function readInstanceDoc(doc) {
5317
5624
  return parseInstanceDocument(assertReadableModel(doc));
5318
5625
  }
5319
5626
 
5627
+ function readInstancePreviewDoc(doc) {
5628
+ return hasDocumentId(doc) ? parseInstancePreviewDocument(withoutProjectedNulls(assertReadableModel(doc))) : parseInstancePreviewDocument(doc);
5629
+ }
5630
+
5631
+ function hasDocumentId(doc) {
5632
+ return typeof doc == "object" && doc !== null && typeof doc._id == "string";
5633
+ }
5634
+
5635
+ function withoutProjectedNulls(doc) {
5636
+ const row = withoutNullMembers(doc);
5637
+ if (typeof row != "object" || row === null) return row;
5638
+ const out = {
5639
+ ...row
5640
+ };
5641
+ return Array.isArray(out.stages) && (out.stages = out.stages.map(withoutStageEntryNulls)),
5642
+ Array.isArray(out.claimedEffects) && (out.claimedEffects = out.claimedEffects.map(withoutNullMembers)),
5643
+ Array.isArray(out.failedEffects) && (out.failedEffects = out.failedEffects.map(withoutNullMembers)),
5644
+ out;
5645
+ }
5646
+
5647
+ function withoutStageEntryNulls(entry) {
5648
+ const stage = withoutNullMembers(entry);
5649
+ if (typeof stage != "object" || stage === null) return stage;
5650
+ const out = {
5651
+ ...stage
5652
+ };
5653
+ return Array.isArray(out.activities) && (out.activities = out.activities.map(withoutNullMembers)),
5654
+ out;
5655
+ }
5656
+
5657
+ function withoutNullMembers(value) {
5658
+ return value === null || typeof value != "object" || Array.isArray(value) ? value : Object.fromEntries(Object.entries(value).filter(([, member]) => member !== null));
5659
+ }
5660
+
5320
5661
  async function reload({client: client, instanceId: instanceId, tag: tag}) {
5321
5662
  const doc = await getInstanceDocument(client, instanceId);
5322
5663
  if (!doc) throw new invariants.InstanceNotFoundError({
@@ -5563,7 +5904,8 @@ function loadCallContext({client: client, instanceId: instanceId, options: optio
5563
5904
  } : {},
5564
5905
  ...options.telemetry ? {
5565
5906
  telemetry: options.telemetry
5566
- } : {}
5907
+ } : {},
5908
+ memberRolesLoader: options.memberRolesLoader
5567
5909
  }
5568
5910
  });
5569
5911
  }
@@ -5608,6 +5950,7 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
5608
5950
  ...options.telemetry !== void 0 ? {
5609
5951
  telemetry: options.telemetry
5610
5952
  } : {},
5953
+ memberRolesLoader: options.memberRolesLoader,
5611
5954
  ...options.overlay !== void 0 ? {
5612
5955
  overlay: options.overlay
5613
5956
  } : {},
@@ -5643,7 +5986,10 @@ async function ctxEvaluateCondition({ctx: ctx, condition: condition, opts: opts}
5643
5986
  }
5644
5987
 
5645
5988
  async function buildEngineContext(args) {
5646
- const {client: client, clientForGdr: clientForGdr, refSurface: refSurface, instance: instance, definition: definition} = args, clock = args.clock ?? wallClock;
5989
+ const {client: client, clientForGdr: clientForGdr, refSurface: refSurface, instance: instance, definition: definition} = args, clock = args.clock ?? wallClock, memberRolesLoader = args.memberRolesLoader, memberRoles = await memberRolesLoader({
5990
+ workflowResource: instance.workflowResource,
5991
+ definition: definition
5992
+ });
5647
5993
  return {
5648
5994
  client: client,
5649
5995
  clientForGdr: clientForGdr,
@@ -5660,6 +6006,10 @@ async function buildEngineContext(args) {
5660
6006
  } : {},
5661
6007
  instance: instance,
5662
6008
  definition: definition,
6009
+ memberRolesLoader: memberRolesLoader,
6010
+ ...memberRoles !== void 0 ? {
6011
+ memberRoles: memberRoles
6012
+ } : {},
5663
6013
  snapshot: await hydrateSnapshot({
5664
6014
  client: client,
5665
6015
  clientForGdr: clientForGdr,
@@ -5671,6 +6021,62 @@ async function buildEngineContext(args) {
5671
6021
  };
5672
6022
  }
5673
6023
 
6024
+ function createAssignmentMemberRolesLoader(client) {
6025
+ const byProjectId = /* @__PURE__ */ new Map;
6026
+ return async ({workflowResource: workflowResource, definition: definition}) => {
6027
+ if (!hasRoleConstrainedAssignments(definition)) return;
6028
+ assertRoleConstrainedAssignmentResource({
6029
+ context: "workflow",
6030
+ definition: definition,
6031
+ workflowResource: workflowResource
6032
+ });
6033
+ const projectId = invariants.datasetResourceParts(workflowResource.id).projectId;
6034
+ let pending = byProjectId.get(projectId);
6035
+ return pending === void 0 && (pending = client.request === void 0 ? Promise.reject(new Error(`Definition "${definition.name}" has role-constrained assignments, which require project-directory access for project "${projectId}"; the client cannot issue requests`)) : loadProjectMemberRoles({
6036
+ request: client.request,
6037
+ projectId: projectId
6038
+ }), byProjectId.set(projectId, pending)), pending;
6039
+ };
6040
+ }
6041
+
6042
+ async function loadProjectMemberRoles(args) {
6043
+ const {request: request, projectId: projectId} = args, snapshot = await requestProjectMemberDirectory({
6044
+ request: request,
6045
+ projectId: projectId
6046
+ }), rolesByProjectId = projectMemberRoles({
6047
+ members: snapshot.members,
6048
+ projectId: projectId
6049
+ });
6050
+ return globalizeMemberRoles({
6051
+ snapshot: snapshot,
6052
+ rolesByProjectId: rolesByProjectId
6053
+ });
6054
+ }
6055
+
6056
+ function globalizeMemberRoles(args) {
6057
+ const {snapshot: snapshot, rolesByProjectId: rolesByProjectId} = args, humanIds = [ ...rolesByProjectId.keys() ].filter(id => invariants.classifyPrincipalId(id).namespace === "project");
6058
+ for (const {globalId: globalId, memberId: memberId} of snapshot.globalUsers) {
6059
+ const roles = rolesByProjectId.get(memberId);
6060
+ roles !== void 0 && rolesByProjectId.set(globalId, roles);
6061
+ }
6062
+ for (const id of humanIds) rolesByProjectId.delete(id);
6063
+ return Object.fromEntries(rolesByProjectId);
6064
+ }
6065
+
6066
+ function projectMemberRoles(args) {
6067
+ const result = /* @__PURE__ */ new Map;
6068
+ for (const member of args.members) {
6069
+ const {id: id, roles: roles} = member;
6070
+ if (!Array.isArray(roles) || !roles.every(isProjectMemberRole)) throw new Error(`Project member role directory response is invalid for project "${args.projectId}" and member "${id}"`);
6071
+ result.set(id, roles.map(role => role.name));
6072
+ }
6073
+ return result;
6074
+ }
6075
+
6076
+ function isProjectMemberRole(role) {
6077
+ return invariants.isRecord(role) && typeof role.name == "string";
6078
+ }
6079
+
5674
6080
  function findStage(definition, stageName) {
5675
6081
  const stage = definition.stages.find(s => s.name === stageName);
5676
6082
  if (stage === void 0) throw new Error(`Stage "${stageName}" not found in definition ${definition.name}`);
@@ -5690,6 +6096,8 @@ async function resolveStageFieldEntries(args) {
5690
6096
  tag: instance.tag,
5691
6097
  stageName: stage.name,
5692
6098
  workflowResource: instance.workflowResource,
6099
+ memberRoles: args.memberRoles,
6100
+ roleAliases: args.roleAliases,
5693
6101
  workflowFields: instance.fields ?? [],
5694
6102
  ...instance.perspective !== void 0 ? {
5695
6103
  perspective: instance.perspective
@@ -5716,6 +6124,8 @@ async function resolveActivityFieldEntries(args) {
5716
6124
  stageName: stage.name,
5717
6125
  workflowResource: instance.workflowResource,
5718
6126
  activityName: activity.name,
6127
+ memberRoles: args.memberRoles,
6128
+ roleAliases: args.roleAliases,
5719
6129
  workflowFields: instance.fields ?? [],
5720
6130
  ...instance.perspective !== void 0 ? {
5721
6131
  perspective: instance.perspective
@@ -5799,237 +6209,76 @@ function resolveGuardRead(args) {
5799
6209
  return entry === void 0 ? void 0 : deref ? resolveFieldRead({
5800
6210
  kind: entry._type,
5801
6211
  value: entry.value,
5802
- path: fieldRead[2],
5803
- snapshot: ctx.snapshot
5804
- }) : fieldRead[2] !== void 0 ? getPath(entry.value, fieldRead[2]) : entry.value;
5805
- }
5806
- const effectsRead = invariants.EFFECTS_READ.exec(expr);
5807
- if (effectsRead !== null) {
5808
- const outputs = effectOutputsMap(ctx.instance)[effectsRead[1]];
5809
- return effectsRead[2] !== void 0 ? getPath(outputs, effectsRead[2]) : outputs;
5810
- }
5811
- throw new Error(`Guard read "${expr}" is not a supported deploy-time value — use "$self", "$now", "$fields.<name>[.path]", or "$effects['<name>'][.path]" (guards store resolved values; the lake cannot see $fields or $effects)`);
5812
- }
5813
-
5814
- function resolveIdRefTarget(expr, ctx) {
5815
- const value = resolveGuardRead({
5816
- expr: expr,
5817
- ctx: ctx,
5818
- deref: !1
5819
- });
5820
- if (typeof value == "string" && invariants.isGdrUri(value)) return {
5821
- parsed: invariants.parseGdr(value)
5822
- };
5823
- if (value && typeof value == "object") {
5824
- const v2 = value;
5825
- if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
5826
- parsed: invariants.parseGdr(v2.id),
5827
- type: v2.type
5828
- } : {
5829
- parsed: invariants.parseGdr(v2.id)
5830
- };
5831
- }
5832
- return null;
5833
- }
5834
-
5835
- function resolveIdRefTargets(idRefs, ctx) {
5836
- const targets = [];
5837
- for (const expr of idRefs ?? []) {
5838
- const target = resolveIdRefTarget(expr, ctx);
5839
- if (target === null) return null;
5840
- targets.push(target);
5841
- }
5842
- return targets.length === 0 ? null : targets;
5843
- }
5844
-
5845
- function assertSingleResource(targets) {
5846
- const resource = invariants.resourceFromParsed(targets[0].parsed);
5847
- for (const g of targets) {
5848
- const r = invariants.resourceFromParsed(g.parsed);
5849
- if (r.type !== resource.type || r.id !== resource.id) throw new Error(`Guard targets span multiple resources (${resource.type}:${resource.id} vs ${r.type}:${r.id}); a guard is single-resource.`);
5850
- }
5851
- return resource;
5852
- }
5853
-
5854
- function bareIdRefs(targets) {
5855
- return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
5856
- }
5857
-
5858
- function resolveMatchTypes(targets, authorTypes) {
5859
- if (authorTypes !== void 0) return authorTypes;
5860
- const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
5861
- return inferred.length > 0 ? inferred : void 0;
5862
- }
5863
-
5864
- function resolveMetadata(metadata, ctx) {
5865
- const out = {};
5866
- for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
5867
- expr: expr,
5868
- ctx: ctx,
5869
- deref: !0
5870
- });
5871
- return out;
5872
- }
5873
-
5874
- function userLoginProvider(user) {
5875
- return user?.provider ?? user?.loginProvider;
5876
- }
5877
-
5878
- function optionalString(value) {
5879
- return value === void 0 || typeof value == "string";
5880
- }
5881
-
5882
- function isClientProjectUser(value) {
5883
- return isRecord(value) && typeof value.id == "string" && optionalString(value.sanityUserId) && optionalString(value.displayName) && optionalString(value.email) && (value.imageUrl === null || optionalString(value.imageUrl)) && optionalString(value.provider) && optionalString(value.loginProvider);
5884
- }
5885
-
5886
- function objectProperty(value, property) {
5887
- if (!isRecord(value)) return;
5888
- const propertyValue = value[property];
5889
- return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
5890
- }
5891
-
5892
- function stringProperty(value, property) {
5893
- const propertyValue = Reflect.get(value, property);
5894
- return typeof propertyValue == "string" ? propertyValue : void 0;
5895
- }
5896
-
5897
- function apiErrorType(error) {
5898
- const response = objectProperty(error, "response"), body = objectProperty(response, "body");
5899
- if (!body) return;
5900
- const nestedError = objectProperty(body, "error");
5901
- return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
5902
- }
5903
-
5904
- function isProjectUserNotFoundError(error) {
5905
- return apiErrorType(error) === "projectUserNotFoundError";
5906
- }
5907
-
5908
- const memberJoinCache = /* @__PURE__ */ new WeakMap;
5909
-
5910
- function joinCacheFor(client) {
5911
- let cache = memberJoinCache.get(client);
5912
- return cache === void 0 && (cache = /* @__PURE__ */ new Map, memberJoinCache.set(client, cache)),
5913
- cache;
5914
- }
5915
-
5916
- async function projectMemberIds(request, projectId) {
5917
- const project = await request({
5918
- uri: `/projects/${encodeURIComponent(projectId)}`
5919
- }), members = isRecord(project) ? project.members : void 0;
5920
- return Array.isArray(members) ? members.map(member => isRecord(member) ? member.id : void 0).filter(id => typeof id == "string") : [];
6212
+ path: fieldRead[2],
6213
+ snapshot: ctx.snapshot
6214
+ }) : fieldRead[2] !== void 0 ? getPath(entry.value, fieldRead[2]) : entry.value;
6215
+ }
6216
+ const effectsRead = invariants.EFFECTS_READ.exec(expr);
6217
+ if (effectsRead !== null) {
6218
+ const outputs = effectOutputsMap(ctx.instance)[effectsRead[1]];
6219
+ return effectsRead[2] !== void 0 ? getPath(outputs, effectsRead[2]) : outputs;
6220
+ }
6221
+ throw new Error(`Guard read "${expr}" is not a supported deploy-time value — use "$self", "$now", "$fields.<name>[.path]", or "$effects['<name>'][.path]" (guards store resolved values; the lake cannot see $fields or $effects)`);
5921
6222
  }
5922
6223
 
5923
- async function resolveGlobalProjectUser(args) {
5924
- const {client: client, request: request, projectId: projectId, id: id} = args, cache = joinCacheFor(client), key = `${projectId}:${id}`, hit = cache.get(key);
5925
- if (hit !== void 0) return hit === null ? {
5926
- status: "missing"
5927
- } : {
5928
- status: "resolved",
5929
- user: hit
6224
+ function resolveIdRefTarget(expr, ctx) {
6225
+ const value = resolveGuardRead({
6226
+ expr: expr,
6227
+ ctx: ctx,
6228
+ deref: !1
6229
+ });
6230
+ if (typeof value == "string" && invariants.isGdrUri(value)) return {
6231
+ parsed: invariants.parseGdr(value)
5930
6232
  };
5931
- try {
5932
- await ingestMemberJoin({
5933
- request: request,
5934
- projectId: projectId,
5935
- cache: cache
5936
- });
5937
- const found = cache.get(key);
5938
- return found != null ? {
5939
- status: "resolved",
5940
- user: found
5941
- } : (cache.set(key, null), {
5942
- status: "missing"
5943
- });
5944
- } catch (cause) {
5945
- return {
5946
- status: "inaccessible",
5947
- cause: cause
6233
+ if (value && typeof value == "object") {
6234
+ const v2 = value;
6235
+ if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
6236
+ parsed: invariants.parseGdr(v2.id),
6237
+ type: v2.type
6238
+ } : {
6239
+ parsed: invariants.parseGdr(v2.id)
5948
6240
  };
5949
6241
  }
6242
+ return null;
5950
6243
  }
5951
6244
 
5952
- async function ingestMemberJoin(args) {
5953
- const {request: request, projectId: projectId, cache: cache} = args, memberIds = await projectMemberIds(request, projectId);
5954
- if (memberIds.length === 0) return;
5955
- const requested = new Set(memberIds), response = await request({
5956
- uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
5957
- });
5958
- for (const row of Array.isArray(response) ? response : [ response ]) {
5959
- if (!isClientProjectUser(row) || !requested.has(row.id)) continue;
5960
- const globalId = invariants.directoryBridgeId(row.sanityUserId);
5961
- globalId !== void 0 && cache.set(`${projectId}:${globalId}`, row);
6245
+ function resolveIdRefTargets(idRefs, ctx) {
6246
+ const targets = [];
6247
+ for (const expr of idRefs ?? []) {
6248
+ const target = resolveIdRefTarget(expr, ctx);
6249
+ if (target === null) return null;
6250
+ targets.push(target);
5962
6251
  }
6252
+ return targets.length === 0 ? null : targets;
5963
6253
  }
5964
6254
 
5965
- function clientProjectUserDirectory(client, projectId) {
5966
- return {
5967
- findById: async id => {
5968
- if (!client.request) return {
5969
- status: "inaccessible",
5970
- cause: new Error("Project-user resolution requires WorkflowClient.request")
5971
- };
5972
- if (invariants.classifyPrincipalId(id).namespace === "global") return resolveGlobalProjectUser({
5973
- client: client,
5974
- request: client.request,
5975
- projectId: projectId,
5976
- id: id
5977
- });
5978
- try {
5979
- const response = await client.request({
5980
- uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
5981
- }), candidate = Array.isArray(response) ? response[0] : response;
5982
- return candidate == null ? {
5983
- status: "missing"
5984
- } : isClientProjectUser(candidate) ? candidate.id !== id ? {
5985
- status: "inaccessible",
5986
- cause: new Error(`Project-user response answered id "${candidate.id}", not the requested "${id}"`)
5987
- } : {
5988
- status: "resolved",
5989
- user: candidate
5990
- } : {
5991
- status: "inaccessible",
5992
- cause: new Error("Project-user response had an invalid shape")
5993
- };
5994
- } catch (cause) {
5995
- return isProjectUserNotFoundError(cause) ? {
5996
- status: "missing"
5997
- } : {
5998
- status: "inaccessible",
5999
- cause: cause
6000
- };
6001
- }
6002
- }
6003
- };
6255
+ function assertSingleResource(targets) {
6256
+ const resource = invariants.resourceFromParsed(targets[0].parsed);
6257
+ for (const g of targets) {
6258
+ const r = invariants.resourceFromParsed(g.parsed);
6259
+ if (r.type !== resource.type || r.id !== resource.id) throw new Error(`Guard targets span multiple resources (${resource.type}:${resource.id} vs ${r.type}:${r.id}); a guard is single-resource.`);
6260
+ }
6261
+ return resource;
6004
6262
  }
6005
6263
 
6006
- function resolveClientActor(client, args) {
6007
- return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
6264
+ function bareIdRefs(targets) {
6265
+ return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
6008
6266
  }
6009
6267
 
6010
- async function resolveActor(directory, actor) {
6011
- if (actor.kind !== "person") return {
6012
- status: "not-person",
6013
- actor: actor
6014
- };
6015
- const personActor = {
6016
- ...actor,
6017
- kind: "person"
6018
- }, lookup = await directory.findById(personActor.id);
6019
- return lookup.status === "resolved" ? {
6020
- status: "resolved",
6021
- actor: personActor,
6022
- user: lookup.user
6023
- } : lookup.status === "inaccessible" ? {
6024
- status: "inaccessible",
6025
- actor: personActor,
6026
- ...lookup.cause === void 0 ? {} : {
6027
- cause: lookup.cause
6028
- }
6029
- } : {
6030
- status: "missing",
6031
- actor: personActor
6032
- };
6268
+ function resolveMatchTypes(targets, authorTypes) {
6269
+ if (authorTypes !== void 0) return authorTypes;
6270
+ const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
6271
+ return inferred.length > 0 ? inferred : void 0;
6272
+ }
6273
+
6274
+ function resolveMetadata(metadata, ctx) {
6275
+ const out = {};
6276
+ for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
6277
+ expr: expr,
6278
+ ctx: ctx,
6279
+ deref: !0
6280
+ });
6281
+ return out;
6033
6282
  }
6034
6283
 
6035
6284
  const IDENTITY_KINDS = /* @__PURE__ */ new Set([ "actor", "assignee", "assignees" ]);
@@ -6677,6 +6926,8 @@ async function buildActivityEntry({ctx: ctx, stage: stage, activity: activity, r
6677
6926
  activity: activity,
6678
6927
  now: ctx.now,
6679
6928
  refSurface: ctx.refSurface,
6929
+ memberRoles: ctx.memberRoles,
6930
+ roleAliases: ctx.definition.roleAliases,
6680
6931
  ...recordDiscard !== void 0 ? {
6681
6932
  recordDiscard: recordDiscard
6682
6933
  } : {}
@@ -6879,7 +7130,8 @@ async function spawnRow({ctx: ctx, mutation: mutation, activity: activity, actio
6879
7130
  context: context,
6880
7131
  actor: actor,
6881
7132
  now: now,
6882
- refSurface: ctx.refSurface
7133
+ refSurface: ctx.refSurface,
7134
+ memberRolesLoader: ctx.memberRolesLoader
6883
7135
  });
6884
7136
  mutation.pendingCreates.push({
6885
7137
  body: body,
@@ -7102,13 +7354,16 @@ async function resolveDefinitionRef({client: client, ref: ref, tag: tag}) {
7102
7354
  }
7103
7355
 
7104
7356
  async function prepareChildInstance(args) {
7105
- const {client: client, parent: parent, definition: definition, initialFields: initialFields, context: context, actor: actor, now: now, refSurface: refSurface} = args, childTag = parent.tag, workflowResource = parent.workflowResource, childDocId = instanceDocId(childTag), childRef = {
7357
+ const {client: client, parent: parent, definition: definition, initialFields: initialFields, context: context, actor: actor, now: now, refSurface: refSurface, memberRolesLoader: memberRolesLoader} = args, childTag = parent.tag, workflowResource = parent.workflowResource, childDocId = instanceDocId(childTag), childRef = {
7106
7358
  id: invariants.gdrFromResource(workflowResource, childDocId),
7107
7359
  type: WORKFLOW_INSTANCE_TYPE
7108
7360
  }, ancestors = [ ...parent.ancestors, {
7109
7361
  id: invariants.selfGdr(parent),
7110
7362
  type: WORKFLOW_INSTANCE_TYPE
7111
- } ], inheritedPerspective = parent.perspective, fieldDiscards = [], childFields = await resolveDeclaredFields({
7363
+ } ], inheritedPerspective = parent.perspective, fieldDiscards = [], memberRoles = await memberRolesLoader({
7364
+ workflowResource: workflowResource,
7365
+ definition: definition
7366
+ }), childFields = await resolveDeclaredFields({
7112
7367
  entryDefs: definition.fields,
7113
7368
  initialFields: initialFields,
7114
7369
  ctx: {
@@ -7119,6 +7374,8 @@ async function prepareChildInstance(args) {
7119
7374
  workflowResource: workflowResource,
7120
7375
  definitionName: definition.name,
7121
7376
  refSurface: refSurface,
7377
+ memberRoles: memberRoles,
7378
+ roleAliases: definition.roleAliases,
7122
7379
  inputProvenance: "definition",
7123
7380
  ...inheritedPerspective !== void 0 ? {
7124
7381
  perspective: inheritedPerspective
@@ -7189,6 +7446,8 @@ async function enterStage({ctx: ctx, mutation: mutation, nextStage: nextStage, a
7189
7446
  stage: nextStage,
7190
7447
  now: at,
7191
7448
  refSurface: ctx.refSurface,
7449
+ memberRoles: ctx.memberRoles,
7450
+ roleAliases: ctx.definition.roleAliases,
7192
7451
  recordDiscard: recordFieldDiscards({
7193
7452
  target: mutation.history,
7194
7453
  scope: "stage",
@@ -7415,11 +7674,11 @@ async function advisoryCan({instance: instance, identity: identity, grants: gran
7415
7674
  const DANGEROUS_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([ "__proto__", "constructor", "prototype" ]);
7416
7675
 
7417
7676
  function attributeEntry(row) {
7418
- if (!(!isRecord(row) || typeof row.key != "string" || row.key.length === 0) && !DANGEROUS_ATTRIBUTE_KEYS.has(row.key) && !(!("activeValue" in row) || row.activeValue === void 0)) return [ row.key, row.activeValue ];
7677
+ if (!(!invariants.isRecord(row) || typeof row.key != "string" || row.key.length === 0) && !DANGEROUS_ATTRIBUTE_KEYS.has(row.key) && !(!("activeValue" in row) || row.activeValue === void 0)) return [ row.key, row.activeValue ];
7419
7678
  }
7420
7679
 
7421
7680
  function normalizeUserAttributes(response) {
7422
- if (!isRecord(response)) return;
7681
+ if (!invariants.isRecord(response)) return;
7423
7682
  const rows = response.attributes;
7424
7683
  if (!Array.isArray(rows)) return;
7425
7684
  const out = {};
@@ -7743,7 +8002,7 @@ async function resolveOrganizationId(args) {
7743
8002
  uri: `/projects/${encodeURIComponent(projectId)}`,
7744
8003
  tag: REQUEST_TAG.accessResolveOrg
7745
8004
  });
7746
- if (!isRecord(project)) return;
8005
+ if (!invariants.isRecord(project)) return;
7747
8006
  const orgId = project.organizationId;
7748
8007
  return typeof orgId == "string" && orgId.length > 0 ? orgId : void 0;
7749
8008
  } catch (err) {
@@ -7760,7 +8019,7 @@ async function resolveOrganizationId(args) {
7760
8019
  const ATTRIBUTES_FETCH_LIMIT = 100, EXPECTED_ATTRIBUTES_ABSENCE = /* @__PURE__ */ new Set([ 401, 402, 403, 404 ]);
7761
8020
 
7762
8021
  function httpStatusOf(err) {
7763
- if (!isRecord(err)) return;
8022
+ if (!invariants.isRecord(err)) return;
7764
8023
  const status = err.statusCode;
7765
8024
  return typeof status == "number" ? status : void 0;
7766
8025
  }
@@ -7775,7 +8034,7 @@ async function fetchAttributesCached(args) {
7775
8034
  const response = await sibling.request({
7776
8035
  uri: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
7777
8036
  tag: REQUEST_TAG.accessAttributes
7778
- }), envelope = isRecord(response) ? response : void 0;
8037
+ }), envelope = invariants.isRecord(response) ? response : void 0;
7779
8038
  if (envelope?.hasMore === !0) {
7780
8039
  const page = Array.isArray(envelope.attributes) ? envelope.attributes : [];
7781
8040
  console.warn(`workflow: org attributes for organization "${orgId}" report hasMore=true (bound ${page.length} of the requested limit ${ATTRIBUTES_FETCH_LIMIT}); advisory $attributes may be incomplete — the engine fetches no further pages. Conditions that read missing keys fail closed.`);
@@ -8026,7 +8285,9 @@ async function applyActionFire({ctx: ctx, mutation: mutation, activity: activity
8026
8285
  self: invariants.selfGdr(ctx.instance),
8027
8286
  now: ctx.now,
8028
8287
  snapshot: ctx.snapshot,
8029
- refSurface: ctx.refSurface
8288
+ refSurface: ctx.refSurface,
8289
+ memberRoles: ctx.memberRoles,
8290
+ roleAliases: ctx.definition.roleAliases
8030
8291
  });
8031
8292
  if (await queueEffects({
8032
8293
  ctx: ctx,
@@ -8209,6 +8470,8 @@ async function primeInitialStage(args) {
8209
8470
  stage: stage,
8210
8471
  now: now,
8211
8472
  refSurface: refSurface,
8473
+ memberRoles: ctx.memberRoles,
8474
+ roleAliases: ctx.definition.roleAliases,
8212
8475
  recordDiscard: recordFieldDiscards({
8213
8476
  target: discards,
8214
8477
  scope: "stage",
@@ -8268,7 +8531,7 @@ async function primeInitialStage(args) {
8268
8531
 
8269
8532
  const CASCADE_LIMIT = 100;
8270
8533
 
8271
- async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts, instance: instance}) {
8534
+ async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts, instance: instance}) {
8272
8535
  const contextOptions = {
8273
8536
  clientForGdr: clientForGdr,
8274
8537
  refSurface: refSurface,
@@ -8289,7 +8552,8 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
8289
8552
  } : {},
8290
8553
  ...settlingCohorts ? {
8291
8554
  settlingCohorts: settlingCohorts
8292
- } : {}
8555
+ } : {},
8556
+ memberRolesLoader: memberRolesLoader
8293
8557
  }, ctx = instance === void 0 ? await loadContext({
8294
8558
  client: client,
8295
8559
  instanceId: instanceId,
@@ -8328,7 +8592,7 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
8328
8592
  });
8329
8593
  }
8330
8594
 
8331
- async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts}) {
8595
+ async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts}) {
8332
8596
  let count = 0;
8333
8597
  for (;;) {
8334
8598
  const drained = await drainCondemnedChildren({
@@ -8337,6 +8601,7 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
8337
8601
  actor: actor,
8338
8602
  clientForGdr: clientForGdr,
8339
8603
  refSurface: refSurface,
8604
+ memberRolesLoader: memberRolesLoader,
8340
8605
  clock: clock,
8341
8606
  executionContext: executionContext,
8342
8607
  telemetry: telemetry
@@ -8347,6 +8612,7 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
8347
8612
  actor: actor,
8348
8613
  clientForGdr: clientForGdr,
8349
8614
  refSurface: refSurface,
8615
+ memberRolesLoader: memberRolesLoader,
8350
8616
  clock: clock,
8351
8617
  executionContext: executionContext,
8352
8618
  telemetry: telemetry,
@@ -8363,7 +8629,7 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
8363
8629
  }
8364
8630
  }
8365
8631
 
8366
- async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set, instance: preloadedInstance}) {
8632
+ async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set, instance: preloadedInstance}) {
8367
8633
  if (draining.has(instanceId)) return {
8368
8634
  instance: preloadedInstance,
8369
8635
  drained: !1
@@ -8386,6 +8652,7 @@ async function drainCondemnedChildren({client: client, instanceId: instanceId, a
8386
8652
  actor: actor,
8387
8653
  clientForGdr: clientForGdr,
8388
8654
  refSurface: refSurface,
8655
+ memberRolesLoader: memberRolesLoader,
8389
8656
  clock: clock,
8390
8657
  executionContext: executionContext,
8391
8658
  telemetry: telemetry,
@@ -8403,7 +8670,7 @@ async function drainCondemnedChildren({client: client, instanceId: instanceId, a
8403
8670
  };
8404
8671
  }
8405
8672
 
8406
- async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
8673
+ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
8407
8674
  const childId = invariants.toBareId(row.ref.id);
8408
8675
  try {
8409
8676
  const result = await abortInstance({
@@ -8416,6 +8683,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
8416
8683
  } : {},
8417
8684
  clientForGdr: clientForGdr,
8418
8685
  refSurface: refSurface,
8686
+ memberRolesLoader: memberRolesLoader,
8419
8687
  ...clock ? {
8420
8688
  clock: clock
8421
8689
  } : {},
@@ -8433,6 +8701,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
8433
8701
  actor: actor,
8434
8702
  clientForGdr: clientForGdr,
8435
8703
  refSurface: refSurface,
8704
+ memberRolesLoader: memberRolesLoader,
8436
8705
  clock: clock,
8437
8706
  executionContext: executionContext,
8438
8707
  telemetry: telemetry,
@@ -8583,7 +8852,8 @@ async function buildCascadeStepContext(args, instance) {
8583
8852
  } : {},
8584
8853
  ...args.settlingCohorts ? {
8585
8854
  settlingCohorts: args.settlingCohorts
8586
- } : {}
8855
+ } : {},
8856
+ memberRolesLoader: args.memberRolesLoader
8587
8857
  });
8588
8858
  }
8589
8859
 
@@ -8811,6 +9081,7 @@ function spawnStepArgs(ctx, args) {
8811
9081
  actor: args.actor,
8812
9082
  clientForGdr: ctx.clientForGdr,
8813
9083
  refSurface: ctx.refSurface,
9084
+ memberRolesLoader: ctx.memberRolesLoader,
8814
9085
  clock: ctx.clock,
8815
9086
  executionContext: ctx.executionContext,
8816
9087
  telemetry: ctx.telemetry,
@@ -8952,7 +9223,11 @@ function validateEffectOutputs(args) {
8952
9223
  issues.push(`"${key}" is not a declared output`);
8953
9224
  continue;
8954
9225
  }
8955
- const check = effectOutputCheck(shape, value);
9226
+ const check = effectOutputCheck({
9227
+ shape: shape,
9228
+ value: value,
9229
+ eligibility: args
9230
+ });
8956
9231
  "issues" in check ? issues.push(...check.issues.map(i => `"${key}": ${i}`)) : normalized[key] = check.output;
8957
9232
  }
8958
9233
  if (issues.length > 0) throw new EffectOutputsInvalidError({
@@ -8962,7 +9237,8 @@ function validateEffectOutputs(args) {
8962
9237
  return normalized;
8963
9238
  }
8964
9239
 
8965
- function effectOutputCheck(shape, value) {
9240
+ function effectOutputCheck(args) {
9241
+ const {shape: shape, value: value, eligibility: eligibility} = args;
8966
9242
  return invariants.parseFieldValue({
8967
9243
  entryType: shape.type,
8968
9244
  value: value,
@@ -8977,7 +9253,12 @@ function effectOutputCheck(shape, value) {
8977
9253
  } : {},
8978
9254
  ...shape.validation !== void 0 ? {
8979
9255
  validation: shape.validation
8980
- } : {}
9256
+ } : {},
9257
+ ...shape.roles !== void 0 ? {
9258
+ roles: shape.roles
9259
+ } : {},
9260
+ memberRoles: eligibility.memberRoles,
9261
+ roleAliases: eligibility.roleAliases
8981
9262
  });
8982
9263
  }
8983
9264
 
@@ -9000,7 +9281,7 @@ function requirePendingEffect(instance, effectKey) {
9000
9281
  });
9001
9282
  }
9002
9283
 
9003
- function validateCompletionInput({pending: pending, definition: definition, status: status, ops: ops, outputs: outputs}) {
9284
+ function validateCompletionInput({pending: pending, definition: definition, status: status, ops: ops, outputs: outputs, memberRoles: memberRoles, roleAliases: roleAliases}) {
9004
9285
  if (status === "failed" && ops !== void 0 && ops.length > 0) throw new EffectOpsInvalidError({
9005
9286
  effect: pending.name,
9006
9287
  issues: [ "ops cannot accompany a failed completion — field.set the outcome on a done completion instead" ]
@@ -9012,7 +9293,9 @@ function validateCompletionInput({pending: pending, definition: definition, stat
9012
9293
  const normalizedOutputs = outputs !== void 0 ? validateEffectOutputs({
9013
9294
  outputs: outputs,
9014
9295
  declared: findEffect(definition, pending.name)?.outputs ?? [],
9015
- effectName: pending.name
9296
+ effectName: pending.name,
9297
+ memberRoles: memberRoles,
9298
+ roleAliases: roleAliases
9016
9299
  }) : void 0;
9017
9300
  return {
9018
9301
  ops: ops !== void 0 ? validateEffectOps(ops, pending.name) : [],
@@ -9031,7 +9314,9 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
9031
9314
  definition: ctx.definition,
9032
9315
  status: status,
9033
9316
  ops: ops,
9034
- outputs: outputs
9317
+ outputs: outputs,
9318
+ memberRoles: ctx.memberRoles,
9319
+ roleAliases: ctx.definition.roleAliases
9035
9320
  }), mutation = startMutation(ctx.instance);
9036
9321
  recordProcessedRequest({
9037
9322
  mutation: mutation,
@@ -9062,7 +9347,9 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
9062
9347
  self: invariants.selfGdr(ctx.instance),
9063
9348
  now: ranAt,
9064
9349
  snapshot: ctx.snapshot,
9065
- refSurface: ctx.refSurface
9350
+ refSurface: ctx.refSurface,
9351
+ memberRoles: ctx.memberRoles,
9352
+ roleAliases: ctx.definition.roleAliases
9066
9353
  }), needsGuardRefresh = wroteEffectOutputs || ranOps.some(isFieldOp);
9067
9354
  return await persistThenMaybeRefresh({
9068
9355
  ctx: ctx,
@@ -9231,7 +9518,9 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
9231
9518
  self: invariants.selfGdr(ctx.instance),
9232
9519
  now: ctx.now,
9233
9520
  snapshot: ctx.snapshot,
9234
- refSurface: ctx.refSurface
9521
+ refSurface: ctx.refSurface,
9522
+ memberRoles: ctx.memberRoles,
9523
+ roleAliases: ctx.definition.roleAliases
9235
9524
  }), await persistThenMaybeRefresh({
9236
9525
  ctx: ctx,
9237
9526
  mutation: mutation,
@@ -9726,6 +10015,12 @@ async function evaluateEditableFields(args) {
9726
10015
  ...site.validation !== void 0 ? {
9727
10016
  validation: site.validation
9728
10017
  } : {},
10018
+ ...site.roles !== void 0 ? {
10019
+ roles: site.roles,
10020
+ ...definition.roleAliases !== void 0 ? {
10021
+ roleAliases: definition.roleAliases
10022
+ } : {}
10023
+ } : {},
9729
10024
  value: value,
9730
10025
  editable: reason === void 0,
9731
10026
  ...reason !== void 0 ? {
@@ -10076,23 +10371,63 @@ function idsArm(filter, params) {
10076
10371
  }
10077
10372
  }
10078
10373
 
10079
- function instancesQuery(args) {
10080
- const {tag: tag, filter: filter = {}} = args;
10081
- if (invariants.validateTag(tag), filter.limit !== void 0 && (!Number.isInteger(filter.limit) || filter.limit <= 0)) throw new invariants.ContractViolationError(`instancesQuery: limit must be a positive integer; got ${JSON.stringify(filter.limit)}`);
10082
- const conditions = [ `_type == "${WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ], params = {
10083
- tag: tag
10084
- };
10374
+ function beforeArm(filter, params) {
10375
+ const before = filter.before;
10376
+ if (before !== void 0) {
10377
+ if (filter.limit === void 0) throw new invariants.ContractViolationError("instancesQuery: `before` requires `limit` — a cursor pages the newest-first sliced read");
10378
+ if (before.id === "" || before.startedAt === "") throw new invariants.ContractViolationError(`instancesQuery: \`before\` needs a non-empty id and startedAt; got ${JSON.stringify(before)}`);
10379
+ return params.beforeStartedAt = before.startedAt, params.beforeId = before.id, "(startedAt < $beforeStartedAt || (startedAt == $beforeStartedAt && _id > $beforeId))";
10380
+ }
10381
+ }
10382
+
10383
+ function compiledConditions(filter, params) {
10384
+ if (filter.limit !== void 0 && (!Number.isInteger(filter.limit) || filter.limit <= 0)) throw new invariants.ContractViolationError(`instancesQuery: limit must be a positive integer; got ${JSON.stringify(filter.limit)}`);
10385
+ const conditions = [ `_type == "${WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ];
10085
10386
  filter.includeCompleted !== !0 && conditions.push(inFlightFilter()), filter.definition !== void 0 && (conditions.push("definition == $definition"),
10086
10387
  params.definition = filter.definition), filter.stage !== void 0 && (conditions.push("currentStage == $stage"),
10087
10388
  params.stage = filter.stage);
10389
+ const cursor = beforeArm(filter, params);
10390
+ cursor !== void 0 && conditions.push(cursor);
10088
10391
  const arms = [ documentArm(filter, params), idsArm(filter, params) ].filter(arm => arm !== void 0);
10089
- arms.length > 0 && conditions.push(`(${arms.join(" || ")})`);
10090
- const body = `*[${conditions.join(" && ")}]`;
10091
- return filter.limit !== void 0 ? {
10092
- query: `${body} | order(startedAt desc) [0...${filter.limit}]`,
10392
+ return arms.length > 0 && conditions.push(`(${arms.join(" || ")})`), conditions;
10393
+ }
10394
+
10395
+ function orderedSlice(filter) {
10396
+ return filter.limit !== void 0 ? ` | order(startedAt desc, _id asc) [0...${filter.limit}]` : " | order(startedAt asc, _id asc)";
10397
+ }
10398
+
10399
+ function instancesQuery(args) {
10400
+ const {tag: tag, filter: filter = {}} = args;
10401
+ invariants.validateTag(tag);
10402
+ const params = {
10403
+ tag: tag
10404
+ };
10405
+ return {
10406
+ query: `*[${compiledConditions(filter, params).join(" && ")}]${orderedSlice(filter)}`,
10093
10407
  params: params
10094
- } : {
10095
- query: `${body} | order(startedAt asc)`,
10408
+ };
10409
+ }
10410
+
10411
+ function instanceChangesQuery(args) {
10412
+ return invariants.validateTag(args.tag), {
10413
+ query: `*[_type == "${WORKFLOW_INSTANCE_TYPE}" && ${invariants.tagScopeFilter()}]`,
10414
+ params: {
10415
+ tag: args.tag
10416
+ }
10417
+ };
10418
+ }
10419
+
10420
+ const PREVIEW_FIELD_TYPES = [ "actor", "assignee", "assignees", "date", "datetime", "doc.ref", "doc.refs", "dueDate", "dueDatetime", "release.ref", "subject" ], PREVIEW_PROJECTION = `{\n _id, _type, modelVersion, minReaderModel, workflowResource, definition, pinnedVersion,\n currentStage, startedAt, completedAt, abortedAt, perspective, ancestors,\n "fields": fields[_type in $previewFieldTypes],\n "stages": stages[!defined(exitedAt) && name == ^.currentStage]{\n _key, name, enteredAt,\n "fields": fields[_type in $previewFieldTypes],\n "activities": activities[]{\n _key, name, status, completedBy,\n "fields": fields[_type in $previewFieldTypes]\n }\n },\n "claimedEffects": pendingEffects[defined(claim)]{name, title},\n "failedEffects": effectHistory[status == "failed"]{name, title}\n}`.replaceAll(/\s+/g, " ").trim();
10421
+
10422
+ function instancePreviewsQuery(args) {
10423
+ const {tag: tag, filter: filter = {}} = args;
10424
+ invariants.validateTag(tag);
10425
+ const params = {
10426
+ tag: tag,
10427
+ previewFieldTypes: PREVIEW_FIELD_TYPES
10428
+ };
10429
+ return {
10430
+ query: `*[${compiledConditions(filter, params).join(" && ")}]${orderedSlice(filter)} ${PREVIEW_PROJECTION}`,
10096
10431
  params: params
10097
10432
  };
10098
10433
  }
@@ -10277,6 +10612,11 @@ function hashDefinitionContent(def) {
10277
10612
  }
10278
10613
 
10279
10614
  function planDefinitionDeploy({def: def, latest: latest, target: target}) {
10615
+ assertRoleConstrainedAssignmentResource({
10616
+ context: "workflow.deployDefinitions",
10617
+ definition: def,
10618
+ workflowResource: target.workflowResource
10619
+ });
10280
10620
  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 = invariants.definitionDocId({
10281
10621
  tag: target.tag,
10282
10622
  definition: expanded.name,
@@ -10469,7 +10809,9 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
10469
10809
  self: invariants.selfGdr(ctx.instance),
10470
10810
  now: ctx.now,
10471
10811
  snapshot: ctx.snapshot,
10472
- refSurface: ctx.refSurface
10812
+ refSurface: ctx.refSurface,
10813
+ memberRoles: ctx.memberRoles,
10814
+ roleAliases: ctx.definition.roleAliases
10473
10815
  });
10474
10816
  return await persistThenMaybeRefresh({
10475
10817
  ctx: ctx,
@@ -10568,6 +10910,7 @@ async function resolveOperationContext(args) {
10568
10910
  return {
10569
10911
  access: access,
10570
10912
  actor: access.actor,
10913
+ memberRolesLoader: createAssignmentMemberRolesLoader(args.client),
10571
10914
  clientForGdr: buildClientForGdr({
10572
10915
  client: args.client,
10573
10916
  workflowResource: args.workflowResource,
@@ -10600,6 +10943,7 @@ async function runCommitVerb(params) {
10600
10943
  actor: context.actor,
10601
10944
  clientForGdr: context.clientForGdr,
10602
10945
  refSurface: context.refSurface,
10946
+ memberRolesLoader: context.memberRolesLoader,
10603
10947
  clock: clock,
10604
10948
  executionContext: args.executionContext,
10605
10949
  telemetry: args.telemetry,
@@ -10624,7 +10968,7 @@ function requestRecordFor(args) {
10624
10968
  }
10625
10969
 
10626
10970
  async function runDeduped(args) {
10627
- const {client: client, tag: tag, instanceId: instanceId, record: record, before: before, now: now, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, run: run} = args, {clock: clock, executionContext: executionContext, telemetry: telemetry} = args, replay = async () => {
10971
+ const {client: client, tag: tag, instanceId: instanceId, record: record, before: before, now: now, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, run: run} = args, {clock: clock, executionContext: executionContext, telemetry: telemetry} = args, replay = async () => {
10628
10972
  const pre = await reload({
10629
10973
  client: client,
10630
10974
  instanceId: instanceId,
@@ -10636,6 +10980,7 @@ async function runDeduped(args) {
10636
10980
  actor: actor,
10637
10981
  clientForGdr: clientForGdr,
10638
10982
  refSurface: refSurface,
10983
+ memberRolesLoader: memberRolesLoader,
10639
10984
  clock: clock,
10640
10985
  executionContext: executionContext,
10641
10986
  telemetry: telemetry
@@ -10659,13 +11004,14 @@ async function runDeduped(args) {
10659
11004
  }
10660
11005
  }
10661
11006
 
10662
- async function cascade({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
11007
+ async function cascade({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
10663
11008
  const count = await cascadeAutoTransitions({
10664
11009
  client: client,
10665
11010
  instanceId: instanceId,
10666
11011
  actor: actor,
10667
11012
  clientForGdr: clientForGdr,
10668
11013
  refSurface: refSurface,
11014
+ memberRolesLoader: memberRolesLoader,
10669
11015
  ...clock !== void 0 ? {
10670
11016
  clock: clock
10671
11017
  } : {},
@@ -10685,6 +11031,7 @@ async function cascade({client: client, instanceId: instanceId, actor: actor, cl
10685
11031
  actor: actor,
10686
11032
  clientForGdr: clientForGdr,
10687
11033
  refSurface: refSurface,
11034
+ memberRolesLoader: memberRolesLoader,
10688
11035
  ...clock !== void 0 ? {
10689
11036
  clock: clock
10690
11037
  } : {},
@@ -10698,7 +11045,7 @@ async function cascade({client: client, instanceId: instanceId, actor: actor, cl
10698
11045
  }
10699
11046
 
10700
11047
  async function cascadeAndReload(args) {
10701
- const {client: client, tag: tag, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock} = args;
11048
+ const {client: client, tag: tag, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock} = args;
10702
11049
  return {
10703
11050
  cascaded: await cascade({
10704
11051
  client: client,
@@ -10706,6 +11053,7 @@ async function cascadeAndReload(args) {
10706
11053
  actor: actor,
10707
11054
  clientForGdr: clientForGdr,
10708
11055
  refSurface: refSurface,
11056
+ memberRolesLoader: memberRolesLoader,
10709
11057
  clock: clock,
10710
11058
  ...args.executionContext !== void 0 ? {
10711
11059
  executionContext: args.executionContext
@@ -10729,6 +11077,7 @@ async function settleStart(args) {
10729
11077
  actor: args.actor,
10730
11078
  clientForGdr: args.clientForGdr,
10731
11079
  refSurface: args.refSurface,
11080
+ memberRolesLoader: args.memberRolesLoader,
10732
11081
  clock: args.clock,
10733
11082
  ...args.executionContext !== void 0 ? {
10734
11083
  executionContext: args.executionContext
@@ -10771,31 +11120,20 @@ function resumeMismatch(args) {
10771
11120
  }
10772
11121
 
10773
11122
  async function resumeStart(args) {
10774
- const {existing: existing} = args, mismatch = resumeMismatch({
11123
+ const {existing: existing, definition: definition, version: version, initialFieldCount: initialFieldCount, ...settlementArgs} = args, mismatch = resumeMismatch({
10775
11124
  existing: existing,
10776
- definition: args.definition,
10777
- version: args.version
11125
+ definition: definition,
11126
+ version: version
10778
11127
  });
10779
11128
  if (mismatch !== void 0) throw new invariants.ContractViolationError(`startInstance: instanceId "${existing._id}" already exists and ${mismatch}. A supplied instanceId is start's idempotency key — reuse one only to retry the same start.`);
10780
11129
  if (existing.stages.length === 0 && terminalState(existing) !== "in-flight") throw new invariants.ContractViolationError(`startInstance: instanceId "${existing._id}" belongs to a start that was discarded (aborted before it finished starting) — mint a new id to start again.`);
10781
11130
  const completesStart = isUnprimed(existing), emitStarted = () => resolveTelemetry(args.telemetry).log(WorkflowInstanceStarted, instanceStartedDataFor({
10782
11131
  instance: existing,
10783
- initialFieldCount: args.initialFieldCount,
11132
+ initialFieldCount: initialFieldCount,
10784
11133
  viaSpawn: !1
10785
11134
  })), cascaded = await settleStart({
10786
- client: args.client,
10787
- tag: args.tag,
11135
+ ...settlementArgs,
10788
11136
  instanceId: existing._id,
10789
- actor: args.actor,
10790
- clientForGdr: args.clientForGdr,
10791
- refSurface: args.refSurface,
10792
- clock: args.clock,
10793
- ...args.executionContext !== void 0 ? {
10794
- executionContext: args.executionContext
10795
- } : {},
10796
- ...args.telemetry !== void 0 ? {
10797
- telemetry: args.telemetry
10798
- } : {},
10799
11137
  ...completesStart ? {
10800
11138
  emitStarted: emitStarted
10801
11139
  } : {}
@@ -10811,7 +11149,7 @@ async function resumeStart(args) {
10811
11149
  };
10812
11150
  }
10813
11151
 
10814
- function engineOptionsForActor({actor: actor, clock: clock, clientForGdr: clientForGdr, refSurface: refSurface, executionContext: executionContext, telemetry: telemetry}) {
11152
+ function engineOptionsForActor({actor: actor, clock: clock, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, executionContext: executionContext, telemetry: telemetry}) {
10815
11153
  return {
10816
11154
  ...actor !== void 0 ? {
10817
11155
  actor: actor
@@ -10819,6 +11157,7 @@ function engineOptionsForActor({actor: actor, clock: clock, clientForGdr: client
10819
11157
  clock: clock,
10820
11158
  clientForGdr: clientForGdr,
10821
11159
  refSurface: refSurface,
11160
+ memberRolesLoader: memberRolesLoader,
10822
11161
  ...executionContext !== void 0 ? {
10823
11162
  executionContext: executionContext
10824
11163
  } : {},
@@ -10829,7 +11168,7 @@ function engineOptionsForActor({actor: actor, clock: clock, clientForGdr: client
10829
11168
  }
10830
11169
 
10831
11170
  async function abortAndPropagate(args) {
10832
- const {client: client, instanceId: instanceId, reason: reason, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, requestRecord: requestRecord} = args, result = await abortInstance({
11171
+ const {client: client, instanceId: instanceId, reason: reason, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, executionContext: executionContext, telemetry: telemetry, requestRecord: requestRecord} = args, result = await abortInstance({
10833
11172
  client: client,
10834
11173
  instanceId: instanceId,
10835
11174
  ...reason !== void 0 ? {
@@ -10843,6 +11182,7 @@ async function abortAndPropagate(args) {
10843
11182
  clock: clock,
10844
11183
  clientForGdr: clientForGdr,
10845
11184
  refSurface: refSurface,
11185
+ memberRolesLoader: memberRolesLoader,
10846
11186
  executionContext: executionContext,
10847
11187
  telemetry: telemetry
10848
11188
  })
@@ -10852,6 +11192,7 @@ async function abortAndPropagate(args) {
10852
11192
  actor: actor,
10853
11193
  clientForGdr: clientForGdr,
10854
11194
  refSurface: refSurface,
11195
+ memberRolesLoader: memberRolesLoader,
10855
11196
  clock: clock,
10856
11197
  ...executionContext !== void 0 ? {
10857
11198
  executionContext: executionContext
@@ -10869,6 +11210,7 @@ async function abortAndPropagate(args) {
10869
11210
  actor: actor,
10870
11211
  clientForGdr: clientForGdr,
10871
11212
  refSurface: refSurface,
11213
+ memberRolesLoader: memberRolesLoader,
10872
11214
  clock: clock,
10873
11215
  ...executionContext !== void 0 ? {
10874
11216
  executionContext: executionContext
@@ -10910,6 +11252,7 @@ async function dispatchGatedWrite(args) {
10910
11252
  actor: args.actor,
10911
11253
  clientForGdr: args.clientForGdr,
10912
11254
  refSurface: args.refSurface,
11255
+ memberRolesLoader: args.memberRolesLoader,
10913
11256
  clock: args.clock,
10914
11257
  executionContext: args.executionContext,
10915
11258
  telemetry: args.telemetry
@@ -10985,6 +11328,7 @@ function buildEngineCallOptions(args) {
10985
11328
  actor: args.actor,
10986
11329
  clientForGdr: args.clientForGdr,
10987
11330
  refSurface: args.refSurface,
11331
+ memberRolesLoader: args.memberRolesLoader,
10988
11332
  ...args.localPrincipalId !== void 0 ? {
10989
11333
  localPrincipalId: args.localPrincipalId
10990
11334
  } : {},
@@ -11024,7 +11368,7 @@ async function applyAction(args) {
11024
11368
  }
11025
11369
 
11026
11370
  async function deleteDefinition(args) {
11027
- const {client: client, tag: tag, definition: definition, version: version, cascade: cascade2, reason: reason, executionContext: executionContext, telemetry: telemetry} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, versions = await loadDefinitionVersionsOrThrow({
11371
+ const {client: client, tag: tag, definition: definition, version: version, cascade: cascade2, reason: reason, executionContext: executionContext, telemetry: telemetry} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader} = await resolveOperationContext(args), clock = args.clock ?? wallClock, versions = await loadDefinitionVersionsOrThrow({
11028
11372
  client: client,
11029
11373
  definition: definition,
11030
11374
  tag: tag
@@ -11063,6 +11407,7 @@ async function deleteDefinition(args) {
11063
11407
  actor: actor,
11064
11408
  clientForGdr: clientForGdr,
11065
11409
  refSurface: refSurface,
11410
+ memberRolesLoader: memberRolesLoader,
11066
11411
  clock: clock,
11067
11412
  executionContext: executionContext,
11068
11413
  telemetry: telemetry
@@ -11121,6 +11466,7 @@ async function abortInstances(args) {
11121
11466
  actor: actor,
11122
11467
  clientForGdr: clientForGdr,
11123
11468
  refSurface: args.refSurface,
11469
+ memberRolesLoader: args.memberRolesLoader,
11124
11470
  clock: clock,
11125
11471
  ...executionContext !== void 0 ? {
11126
11472
  executionContext: executionContext
@@ -11153,11 +11499,12 @@ async function fetchStartSlice(args) {
11153
11499
 
11154
11500
  const workflow = {
11155
11501
  deployDefinitions: async rawArgs => {
11156
- assertReaderModelAcknowledgement(rawArgs.expectedMinReaderModel);
11157
- const args = taggedScope(rawArgs, REQUEST_TAG.deploy), {client: client, tag: tag, resourceAliases: resourceAliases} = args;
11502
+ const args = taggedScope(rawArgs, REQUEST_TAG.deploy), {client: client, tag: tag, workflowResource: workflowResource, resourceAliases: resourceAliases} = args;
11158
11503
  invariants.validateTag(tag);
11159
11504
  const definitions = args.definitions.map(def => parseDefinitionInput(def, "workflow.deployDefinitions"));
11160
- definitions.forEach(validateDefinition);
11505
+ definitions.forEach(validateDefinition), assertReaderModelAcknowledgement(args.expectedMinReaderModel, {
11506
+ requiredMinReaderModel: requiredDefinitionReaderModel(definitions)
11507
+ });
11161
11508
  const ordered = await sortByDependencies({
11162
11509
  client: client,
11163
11510
  definitions: definitions,
@@ -11176,6 +11523,7 @@ const workflow = {
11176
11523
  latest: latest,
11177
11524
  target: {
11178
11525
  tag: tag,
11526
+ workflowResource: workflowResource,
11179
11527
  ...resourceAliases !== void 0 ? {
11180
11528
  resourceAliases: resourceAliases
11181
11529
  } : {}
@@ -11226,7 +11574,7 @@ const workflow = {
11226
11574
  }), result;
11227
11575
  },
11228
11576
  startInstance: async rawArgs => {
11229
- const args = taggedScope(rawArgs, REQUEST_TAG.start), {client: client, tag: tag, definition: definitionName, version: version, initialFields: initialFields, instanceId: instanceId, executionContext: executionContext} = args, operationContext = await resolveOperationContext(args), {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = operationContext, clock = args.clock ?? wallClock, seedFields = initialFields ?? [], existing = instanceId !== void 0 ? await getInstanceDocument(client, instanceId) : void 0;
11577
+ const args = taggedScope(rawArgs, REQUEST_TAG.start), {client: client, tag: tag, definition: definitionName, version: version, initialFields: initialFields, instanceId: instanceId, executionContext: executionContext} = args, operationContext = await resolveOperationContext(args), {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader} = operationContext, clock = args.clock ?? wallClock, seedFields = initialFields ?? [], existing = instanceId !== void 0 ? await getInstanceDocument(client, instanceId) : void 0;
11230
11578
  return existing !== void 0 && existing.tag === tag ? resumeStart({
11231
11579
  client: client,
11232
11580
  tag: tag,
@@ -11237,6 +11585,7 @@ const workflow = {
11237
11585
  actor: actor,
11238
11586
  clientForGdr: clientForGdr,
11239
11587
  refSurface: refSurface,
11588
+ memberRolesLoader: memberRolesLoader,
11240
11589
  clock: clock,
11241
11590
  ...executionContext !== void 0 ? {
11242
11591
  executionContext: executionContext
@@ -11256,7 +11605,7 @@ const workflow = {
11256
11605
  return runCommitVerb({
11257
11606
  args: args,
11258
11607
  op: "fireAction",
11259
- run: async ({access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
11608
+ run: async ({access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, record: record, before: before}) => {
11260
11609
  if (findCurrentActivityEntry(before, activity) === void 0 && idempotent === !0) return {
11261
11610
  instance: before,
11262
11611
  cascaded: 0,
@@ -11270,6 +11619,7 @@ const workflow = {
11270
11619
  actor: actor,
11271
11620
  clientForGdr: clientForGdr,
11272
11621
  refSurface: refSurface,
11622
+ memberRolesLoader: memberRolesLoader,
11273
11623
  clock: clock,
11274
11624
  before: before,
11275
11625
  ...grantsFromPath !== void 0 ? {
@@ -11303,6 +11653,7 @@ const workflow = {
11303
11653
  clock: clock,
11304
11654
  clientForGdr: clientForGdr,
11305
11655
  refSurface: refSurface,
11656
+ memberRolesLoader: memberRolesLoader,
11306
11657
  ...executionContext !== void 0 ? {
11307
11658
  executionContext: executionContext
11308
11659
  } : {},
@@ -11331,7 +11682,7 @@ const workflow = {
11331
11682
  return runCommitVerb({
11332
11683
  args: args,
11333
11684
  op: "editField",
11334
- run: async ({access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
11685
+ run: async ({access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, record: record, before: before}) => {
11335
11686
  const result = await dispatchGatedWrite({
11336
11687
  client: client,
11337
11688
  tag: tag,
@@ -11340,6 +11691,7 @@ const workflow = {
11340
11691
  actor: actor,
11341
11692
  clientForGdr: clientForGdr,
11342
11693
  refSurface: refSurface,
11694
+ memberRolesLoader: memberRolesLoader,
11343
11695
  clock: clock,
11344
11696
  before: before,
11345
11697
  ...grantsFromPath !== void 0 ? {
@@ -11374,6 +11726,7 @@ const workflow = {
11374
11726
  clock: clock,
11375
11727
  clientForGdr: clientForGdr,
11376
11728
  refSurface: refSurface,
11729
+ memberRolesLoader: memberRolesLoader,
11377
11730
  ...executionContext !== void 0 ? {
11378
11731
  executionContext: executionContext
11379
11732
  } : {},
@@ -11394,7 +11747,7 @@ const workflow = {
11394
11747
  });
11395
11748
  },
11396
11749
  completeEffect: async rawArgs => {
11397
- const args = taggedScope(rawArgs, REQUEST_TAG.completeEffect), {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, record = requestRecordFor({
11750
+ const args = taggedScope(rawArgs, REQUEST_TAG.completeEffect), {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, executionContext: executionContext} = args, operationContext = await resolveOperationContext(args), clock = args.clock ?? wallClock, record = requestRecordFor({
11398
11751
  idempotencyKey: args.idempotencyKey,
11399
11752
  op: "completeEffect",
11400
11753
  idempotencyTtlMs: args.idempotencyTtlMs
@@ -11405,9 +11758,7 @@ const workflow = {
11405
11758
  instanceId: instanceId,
11406
11759
  record: record,
11407
11760
  now: clock(),
11408
- actor: actor,
11409
- clientForGdr: clientForGdr,
11410
- refSurface: refSurface,
11761
+ ...operationContext,
11411
11762
  clock: clock,
11412
11763
  executionContext: executionContext,
11413
11764
  telemetry: args.telemetry,
@@ -11436,10 +11787,8 @@ const workflow = {
11436
11787
  requestRecord: record
11437
11788
  } : {},
11438
11789
  options: engineOptionsForActor({
11439
- actor: actor,
11790
+ ...operationContext,
11440
11791
  clock: clock,
11441
- clientForGdr: clientForGdr,
11442
- refSurface: refSurface,
11443
11792
  executionContext: executionContext,
11444
11793
  telemetry: args.telemetry
11445
11794
  })
@@ -11447,9 +11796,7 @@ const workflow = {
11447
11796
  client: client,
11448
11797
  tag: tag,
11449
11798
  instanceId: instanceId,
11450
- actor: actor,
11451
- clientForGdr: clientForGdr,
11452
- refSurface: refSurface,
11799
+ ...operationContext,
11453
11800
  clock: clock,
11454
11801
  executionContext: executionContext,
11455
11802
  telemetry: args.telemetry
@@ -11470,7 +11817,7 @@ const workflow = {
11470
11817
  });
11471
11818
  },
11472
11819
  commitEffectOps: async rawArgs => {
11473
- const args = taggedScope(rawArgs, REQUEST_TAG.commitEffectOps), {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, claimToken: claimToken, ops: ops, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, record = requestRecordFor({
11820
+ const args = taggedScope(rawArgs, REQUEST_TAG.commitEffectOps), {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, claimToken: claimToken, ops: ops, executionContext: executionContext} = args, operationContext = await resolveOperationContext(args), clock = args.clock ?? wallClock, record = requestRecordFor({
11474
11821
  idempotencyKey: args.idempotencyKey,
11475
11822
  op: "commitEffectOps",
11476
11823
  idempotencyTtlMs: args.idempotencyTtlMs
@@ -11482,9 +11829,7 @@ const workflow = {
11482
11829
  instanceId: instanceId,
11483
11830
  record: record,
11484
11831
  now: clock(),
11485
- actor: actor,
11486
- clientForGdr: clientForGdr,
11487
- refSurface: refSurface,
11832
+ ...operationContext,
11488
11833
  clock: clock,
11489
11834
  executionContext: executionContext,
11490
11835
  telemetry: args.telemetry,
@@ -11498,10 +11843,8 @@ const workflow = {
11498
11843
  requestRecord: record,
11499
11844
  leaseMs: args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS,
11500
11845
  options: engineOptionsForActor({
11501
- actor: actor,
11846
+ ...operationContext,
11502
11847
  clock: clock,
11503
- clientForGdr: clientForGdr,
11504
- refSurface: refSurface,
11505
11848
  executionContext: executionContext,
11506
11849
  telemetry: args.telemetry
11507
11850
  })
@@ -11509,9 +11852,7 @@ const workflow = {
11509
11852
  client: client,
11510
11853
  tag: tag,
11511
11854
  instanceId: instanceId,
11512
- actor: actor,
11513
- clientForGdr: clientForGdr,
11514
- refSurface: refSurface,
11855
+ ...operationContext,
11515
11856
  clock: clock,
11516
11857
  executionContext: executionContext,
11517
11858
  telemetry: args.telemetry
@@ -11530,7 +11871,7 @@ const workflow = {
11530
11871
  });
11531
11872
  },
11532
11873
  tick: async rawArgs => {
11533
- const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, {access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, current = await reload({
11874
+ const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, operationContext = await resolveOperationContext(args), {access: access} = operationContext, clock = args.clock ?? wallClock, current = await reload({
11534
11875
  client: client,
11535
11876
  instanceId: instanceId,
11536
11877
  tag: tag
@@ -11544,9 +11885,7 @@ const workflow = {
11544
11885
  client: client,
11545
11886
  tag: tag,
11546
11887
  instanceId: instanceId,
11547
- actor: actor,
11548
- clientForGdr: clientForGdr,
11549
- refSurface: refSurface,
11888
+ ...operationContext,
11550
11889
  clock: clock,
11551
11890
  executionContext: executionContext,
11552
11891
  telemetry: args.telemetry
@@ -11566,7 +11905,7 @@ const workflow = {
11566
11905
  return runCommitVerb({
11567
11906
  args: args,
11568
11907
  op: "setStage",
11569
- run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
11908
+ run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, record: record, before: before}) => {
11570
11909
  const result = await setStage({
11571
11910
  client: client,
11572
11911
  instanceId: instanceId,
@@ -11582,6 +11921,7 @@ const workflow = {
11582
11921
  clock: clock,
11583
11922
  clientForGdr: clientForGdr,
11584
11923
  refSurface: refSurface,
11924
+ memberRolesLoader: memberRolesLoader,
11585
11925
  executionContext: executionContext,
11586
11926
  telemetry: args.telemetry
11587
11927
  })
@@ -11591,6 +11931,7 @@ const workflow = {
11591
11931
  actor: actor,
11592
11932
  clientForGdr: clientForGdr,
11593
11933
  refSurface: refSurface,
11934
+ memberRolesLoader: memberRolesLoader,
11594
11935
  clock: clock,
11595
11936
  ...executionContext !== void 0 ? {
11596
11937
  executionContext: executionContext
@@ -11620,7 +11961,7 @@ const workflow = {
11620
11961
  return runCommitVerb({
11621
11962
  args: args,
11622
11963
  op: "abortInstance",
11623
- run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
11964
+ run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, record: record, before: before}) => {
11624
11965
  const changed = await abortAndPropagate({
11625
11966
  client: client,
11626
11967
  instanceId: instanceId,
@@ -11628,6 +11969,7 @@ const workflow = {
11628
11969
  actor: actor,
11629
11970
  clientForGdr: clientForGdr,
11630
11971
  refSurface: refSurface,
11972
+ memberRolesLoader: memberRolesLoader,
11631
11973
  clock: clock,
11632
11974
  ...executionContext !== void 0 ? {
11633
11975
  executionContext: executionContext
@@ -11661,7 +12003,7 @@ const workflow = {
11661
12003
  return runCommitVerb({
11662
12004
  args: args,
11663
12005
  op: "resetActivity",
11664
- run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
12006
+ run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader, clock: clock, record: record, before: before}) => {
11665
12007
  const result = await resetActivity({
11666
12008
  client: client,
11667
12009
  instanceId: instanceId,
@@ -11675,6 +12017,7 @@ const workflow = {
11675
12017
  clock: clock,
11676
12018
  clientForGdr: clientForGdr,
11677
12019
  refSurface: refSurface,
12020
+ memberRolesLoader: memberRolesLoader,
11678
12021
  executionContext: executionContext,
11679
12022
  telemetry: args.telemetry
11680
12023
  })
@@ -11684,6 +12027,7 @@ const workflow = {
11684
12027
  actor: actor,
11685
12028
  clientForGdr: clientForGdr,
11686
12029
  refSurface: refSurface,
12030
+ memberRolesLoader: memberRolesLoader,
11687
12031
  clock: clock,
11688
12032
  ...executionContext !== void 0 ? {
11689
12033
  executionContext: executionContext
@@ -11989,7 +12333,7 @@ async function startRequirementVerdict(args) {
11989
12333
  }
11990
12334
 
11991
12335
  async function startFreshInstance(args) {
11992
- const {args: startArgs, operationContext: operationContext, clock: clock, seedFields: seedFields} = args, {client: client, tag: tag, workflowResource: workflowResource, definition: definitionName, version: version, ancestors: ancestors, context: context, instanceId: instanceId, perspective: perspective, executionContext: executionContext} = startArgs, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = operationContext, definition = await loadDefinition({
12336
+ const {args: startArgs, operationContext: operationContext, clock: clock, seedFields: seedFields} = args, {client: client, tag: tag, workflowResource: workflowResource, definition: definitionName, version: version, ancestors: ancestors, context: context, instanceId: instanceId, perspective: perspective, executionContext: executionContext} = startArgs, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, memberRolesLoader: memberRolesLoader} = operationContext, definition = await loadDefinition({
11993
12337
  client: client,
11994
12338
  definition: definitionName,
11995
12339
  version: version,
@@ -12013,6 +12357,7 @@ async function startFreshInstance(args) {
12013
12357
  id: id,
12014
12358
  now: now,
12015
12359
  refSurface: refSurface,
12360
+ memberRolesLoader: memberRolesLoader,
12016
12361
  ...perspective !== void 0 ? {
12017
12362
  perspective: perspective
12018
12363
  } : {}
@@ -12044,6 +12389,7 @@ async function startFreshInstance(args) {
12044
12389
  actor: actor,
12045
12390
  clientForGdr: clientForGdr,
12046
12391
  refSurface: refSurface,
12392
+ memberRolesLoader: memberRolesLoader,
12047
12393
  clock: clock,
12048
12394
  ...executionContext !== void 0 ? {
12049
12395
  executionContext: executionContext
@@ -12099,7 +12445,10 @@ async function assertStartInputs(args) {
12099
12445
  }
12100
12446
 
12101
12447
  async function resolveStartFields(args) {
12102
- const {client: client, tag: tag, workflowResource: workflowResource, definition: definition, initialFields: initialFields, id: id, now: now, refSurface: refSurface, perspective: perspective} = args, fieldDiscards = [];
12448
+ const {client: client, tag: tag, workflowResource: workflowResource, definition: definition, initialFields: initialFields, id: id, now: now, refSurface: refSurface, memberRolesLoader: memberRolesLoader, perspective: perspective} = args, fieldDiscards = [], memberRoles = await memberRolesLoader({
12449
+ workflowResource: workflowResource,
12450
+ definition: definition
12451
+ });
12103
12452
  return {
12104
12453
  resolvedFields: await resolveDeclaredFields({
12105
12454
  entryDefs: definition.fields ?? [],
@@ -12112,6 +12461,8 @@ async function resolveStartFields(args) {
12112
12461
  workflowResource: workflowResource,
12113
12462
  definitionName: definition.name,
12114
12463
  refSurface: refSurface,
12464
+ memberRoles: memberRoles,
12465
+ roleAliases: definition.roleAliases,
12115
12466
  ...perspective !== void 0 ? {
12116
12467
  perspective: perspective
12117
12468
  } : {},
@@ -12779,11 +13130,12 @@ function createInstanceSession(args) {
12779
13130
  attributes: attributes
12780
13131
  } : {}
12781
13132
  });
12782
- }, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope}) => {
13133
+ }, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope, memberRolesLoader: memberRolesLoader}) => {
12783
13134
  const cascaded = await cascadeHeld({
12784
13135
  scope: scope,
12785
13136
  actor: actor,
12786
- held: held
13137
+ held: held,
13138
+ memberRolesLoader: memberRolesLoader
12787
13139
  });
12788
13140
  return instance = await reload({
12789
13141
  client: scope.client,
@@ -12797,12 +13149,13 @@ function createInstanceSession(args) {
12797
13149
  ranOps: ranOps
12798
13150
  } : {}
12799
13151
  };
12800
- }, cascadeHeld = ({scope: scope, actor: actor, held: held}) => cascade({
13152
+ }, cascadeHeld = ({scope: scope, actor: actor, held: held, memberRolesLoader: memberRolesLoader}) => cascade({
12801
13153
  client: scope.client,
12802
13154
  instanceId: instance._id,
12803
13155
  actor: actor,
12804
13156
  clientForGdr: scope.clientForGdr,
12805
13157
  refSurface: scope.refSurface,
13158
+ memberRolesLoader: memberRolesLoader,
12806
13159
  ...clock !== void 0 ? {
12807
13160
  clock: clock
12808
13161
  } : {},
@@ -12899,6 +13252,7 @@ function createInstanceSession(args) {
12899
13252
  },
12900
13253
  tick() {
12901
13254
  return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
13255
+ const memberRolesLoader = createAssignmentMemberRolesLoader(tickScope.client);
12902
13256
  await assertInstanceWriteAllowed({
12903
13257
  instance: instance,
12904
13258
  guards: heldGuards,
@@ -12914,7 +13268,8 @@ function createInstanceSession(args) {
12914
13268
  }), cascaded = await cascadeHeld({
12915
13269
  scope: tickScope,
12916
13270
  actor: actor,
12917
- held: held
13271
+ held: held,
13272
+ memberRolesLoader: memberRolesLoader
12918
13273
  });
12919
13274
  return instance = await reload({
12920
13275
  client: tickScope.client,
@@ -12933,6 +13288,7 @@ function createInstanceSession(args) {
12933
13288
  },
12934
13289
  fireAction({activity: activity, action: action, params: params}) {
12935
13290
  return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
13291
+ const memberRolesLoader = createAssignmentMemberRolesLoader(fireScope.client);
12936
13292
  assertActionAllowed({
12937
13293
  evaluation: await evaluateWith({
12938
13294
  held: held,
@@ -12953,6 +13309,7 @@ function createInstanceSession(args) {
12953
13309
  } : {},
12954
13310
  clientForGdr: fireScope.clientForGdr,
12955
13311
  refSurface: fireScope.refSurface,
13312
+ memberRolesLoader: memberRolesLoader,
12956
13313
  ...grants !== void 0 ? {
12957
13314
  grants: grants
12958
13315
  } : {},
@@ -12972,7 +13329,8 @@ function createInstanceSession(args) {
12972
13329
  actor: actor,
12973
13330
  held: held,
12974
13331
  ranOps: ranOps,
12975
- scope: fireScope
13332
+ scope: fireScope,
13333
+ memberRolesLoader: memberRolesLoader
12976
13334
  });
12977
13335
  return telemetry.log(WorkflowActionFired, actionFiredData({
12978
13336
  instance: preOp,
@@ -12994,6 +13352,7 @@ function createInstanceSession(args) {
12994
13352
  return Promise.reject(err);
12995
13353
  }
12996
13354
  return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
13355
+ const memberRolesLoader = createAssignmentMemberRolesLoader(editScope.client);
12997
13356
  assertEditAllowed(await evaluateWith({
12998
13357
  held: held,
12999
13358
  guards: heldGuards,
@@ -13015,6 +13374,7 @@ function createInstanceSession(args) {
13015
13374
  } : {},
13016
13375
  clientForGdr: editScope.clientForGdr,
13017
13376
  refSurface: editScope.refSurface,
13377
+ memberRolesLoader: memberRolesLoader,
13018
13378
  ...grants !== void 0 ? {
13019
13379
  grants: grants
13020
13380
  } : {},
@@ -13031,7 +13391,8 @@ function createInstanceSession(args) {
13031
13391
  actor: actor,
13032
13392
  held: held,
13033
13393
  ranOps: ranOps,
13034
- scope: editScope
13394
+ scope: editScope,
13395
+ memberRolesLoader: memberRolesLoader
13035
13396
  });
13036
13397
  return telemetry.log(WorkflowFieldEdited, fieldEditedData({
13037
13398
  instance: preOp,
@@ -13350,8 +13711,11 @@ function attributeMember({member: member, group: group, chain: chain}) {
13350
13711
  }
13351
13712
 
13352
13713
  function diffEntry({def: rawDef, latestRaw: latestRaw, target: target}) {
13353
- assertReaderModelAcknowledgement(target.expectedMinReaderModel);
13354
- const def = parseDefinitionInput(rawDef, "diffEntry"), plan = planDefinitionDeploy({
13714
+ const def = parseDefinitionInput(rawDef, "diffEntry");
13715
+ assertReaderModelAcknowledgement(target.expectedMinReaderModel, {
13716
+ requiredMinReaderModel: requiredDefinitionReaderModel([ def ])
13717
+ });
13718
+ const plan = planDefinitionDeploy({
13355
13719
  def: def,
13356
13720
  latest: asLatest(latestRaw),
13357
13721
  target: target
@@ -13382,10 +13746,13 @@ function asLatest(raw) {
13382
13746
  }
13383
13747
 
13384
13748
  async function computeDiffEntries({client: client, defs: defs, target: target}) {
13385
- assertReaderModelAcknowledgement(target.expectedMinReaderModel);
13749
+ const definitions = defs.map(def => parseDefinitionInput(def, "computeDiffEntries"));
13750
+ assertReaderModelAcknowledgement(target.expectedMinReaderModel, {
13751
+ requiredMinReaderModel: requiredDefinitionReaderModel(definitions)
13752
+ });
13386
13753
  const entries = [];
13387
- for (const rawDef of defs) {
13388
- const def = parseDefinitionInput(rawDef, "computeDiffEntries"), latest = await loadLatestDeployed({
13754
+ for (const def of definitions) {
13755
+ const latest = await loadLatestDeployed({
13389
13756
  client: client,
13390
13757
  definition: def.name,
13391
13758
  tag: target.tag
@@ -13764,6 +14131,8 @@ exports.WORKFLOW_DEFINITION_TYPE = invariants.WORKFLOW_DEFINITION_TYPE;
13764
14131
 
13765
14132
  exports.WorkflowError = invariants.WorkflowError;
13766
14133
 
14134
+ exports.actorFulfillsRole = invariants.actorFulfillsRole;
14135
+
13767
14136
  exports.classifyPrincipalId = invariants.classifyPrincipalId;
13768
14137
 
13769
14138
  exports.clientConfigFromResource = invariants.clientConfigFromResource;
@@ -13978,6 +14347,8 @@ exports.ConcurrentFireActionError = ConcurrentFireActionError;
13978
14347
 
13979
14348
  exports.DATA_MODEL_CHANGES = DATA_MODEL_CHANGES;
13980
14349
 
14350
+ exports.DATA_MODEL_MAX_READER = DATA_MODEL_MAX_READER;
14351
+
13981
14352
  exports.DATA_MODEL_MIN_READER = DATA_MODEL_MIN_READER;
13982
14353
 
13983
14354
  exports.DATA_MODEL_VERSION = DATA_MODEL_VERSION;
@@ -14070,6 +14441,8 @@ exports.WorkflowFieldEdited = WorkflowFieldEdited;
14070
14441
 
14071
14442
  exports.WorkflowInstanceAborted = WorkflowInstanceAborted;
14072
14443
 
14444
+ exports.WorkflowInstancePreviewSchema = WorkflowInstancePreviewSchema;
14445
+
14073
14446
  exports.WorkflowInstanceSchema = WorkflowInstanceSchema;
14074
14447
 
14075
14448
  exports.WorkflowInstanceStarted = WorkflowInstanceStarted;
@@ -14228,10 +14601,14 @@ exports.inFlightFilter = inFlightFilter;
14228
14601
 
14229
14602
  exports.initialFieldIssues = initialFieldIssues;
14230
14603
 
14604
+ exports.instanceChangesQuery = instanceChangesQuery;
14605
+
14231
14606
  exports.instanceDocId = instanceDocId;
14232
14607
 
14233
14608
  exports.instanceGuardQuery = instanceGuardQuery;
14234
14609
 
14610
+ exports.instancePreviewsQuery = instancePreviewsQuery;
14611
+
14235
14612
  exports.instanceWatchesDocument = instanceWatchesDocument;
14236
14613
 
14237
14614
  exports.instancesGuardQuery = instancesGuardQuery;
@@ -14286,6 +14663,8 @@ exports.parseGuardDocument = parseGuardDocument;
14286
14663
 
14287
14664
  exports.parseInstanceDocument = parseInstanceDocument;
14288
14665
 
14666
+ exports.parseInstancePreviewDocument = parseInstancePreviewDocument;
14667
+
14289
14668
  exports.processShellUserProperties = processShellUserProperties;
14290
14669
 
14291
14670
  exports.projectStartSliceRow = projectStartSliceRow;
@@ -14294,12 +14673,16 @@ exports.projectToWatchRef = projectToWatchRef;
14294
14673
 
14295
14674
  exports.readInstanceDoc = readInstanceDoc;
14296
14675
 
14676
+ exports.readInstancePreviewDoc = readInstancePreviewDoc;
14677
+
14297
14678
  exports.readsRaw = readsRaw;
14298
14679
 
14299
14680
  exports.refsOf = refsOf;
14300
14681
 
14301
14682
  exports.remediationsFor = remediationsFor;
14302
14683
 
14684
+ exports.requiredDefinitionReaderModel = requiredDefinitionReaderModel;
14685
+
14303
14686
  exports.requiredModelFeatures = requiredModelFeatures;
14304
14687
 
14305
14688
  exports.requiredReaderModel = requiredReaderModel;