@sanity/workflow-engine 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -0
- package/DATAMODEL.md +107 -0
- package/dist/_chunks-cjs/invariants.cjs +179 -88
- package/dist/_chunks-es/invariants.js +174 -89
- package/dist/define.d.cts +187 -9
- package/dist/define.d.ts +187 -9
- package/dist/index.cjs +883 -468
- package/dist/index.d.cts +414 -19
- package/dist/index.d.ts +414 -19
- package/dist/index.js +880 -478
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -449,7 +449,7 @@ function fieldEditedData(args) {
|
|
|
449
449
|
};
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
-
const DATA_MODEL_VERSION =
|
|
452
|
+
const DATA_MODEL_VERSION = 7, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
|
|
453
453
|
|
|
454
454
|
class ReaderModelAcknowledgementError extends invariants.WorkflowError {
|
|
455
455
|
code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
|
|
@@ -499,7 +499,7 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
|
|
|
499
499
|
documentTypes: Object.freeze([ "definition" ]),
|
|
500
500
|
compatibility: "additive",
|
|
501
501
|
applicability: "detectable",
|
|
502
|
-
summary: "Ordinary actions may carry
|
|
502
|
+
summary: "Ordinary actions may carry advisory workflow semantics."
|
|
503
503
|
}), Object.freeze({
|
|
504
504
|
id: "inclusive-scalar-bounds",
|
|
505
505
|
introducedInModel: 2,
|
|
@@ -548,6 +548,30 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
|
|
|
548
548
|
compatibility: "additive",
|
|
549
549
|
applicability: "detectable",
|
|
550
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)."
|
|
551
575
|
}) ]);
|
|
552
576
|
|
|
553
577
|
function recordOf(value) {
|
|
@@ -570,13 +594,34 @@ function parsedDefinitionSnapshot(root) {
|
|
|
570
594
|
}));
|
|
571
595
|
}
|
|
572
596
|
|
|
573
|
-
function
|
|
597
|
+
function persistedDefinitionTree(document) {
|
|
574
598
|
const root = recordOf(document);
|
|
575
|
-
if (root === void 0) return
|
|
576
|
-
const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], stages
|
|
599
|
+
if (root === void 0) return;
|
|
600
|
+
const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], {stages: stages, activities: activities, actions: actions} = definitionDescendants(roots);
|
|
601
|
+
return {
|
|
602
|
+
roots: roots,
|
|
603
|
+
stages: stages,
|
|
604
|
+
activities: activities,
|
|
605
|
+
actions: actions
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function persistedFieldEntries(document) {
|
|
610
|
+
const tree = persistedDefinitionTree(document);
|
|
611
|
+
if (tree === void 0) return [];
|
|
612
|
+
const {roots: roots, stages: stages, activities: activities, actions: actions} = tree, effects = actions.flatMap(action => recordsAt(action, "effects"));
|
|
577
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")) ]);
|
|
578
614
|
}
|
|
579
615
|
|
|
616
|
+
function definitionDescendants(roots) {
|
|
617
|
+
const stages = roots.flatMap(root => recordsAt(root, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions"));
|
|
618
|
+
return {
|
|
619
|
+
stages: stages,
|
|
620
|
+
activities: activities,
|
|
621
|
+
actions: actions
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
580
625
|
function hasChoiceList(document) {
|
|
581
626
|
return persistedFieldEntries(document).some(entry => {
|
|
582
627
|
const options = recordOf(entry.options);
|
|
@@ -588,9 +633,34 @@ function hasFieldKind(document, kind) {
|
|
|
588
633
|
return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
|
|
589
634
|
}
|
|
590
635
|
|
|
591
|
-
function
|
|
636
|
+
function definitionNodes(document) {
|
|
592
637
|
const root = recordOf(document);
|
|
593
|
-
|
|
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)));
|
|
594
664
|
}
|
|
595
665
|
|
|
596
666
|
function hasScalarValidation(document) {
|
|
@@ -623,7 +693,10 @@ const featureDetectors = {
|
|
|
623
693
|
"effect-claim-tokens": hasClaimTokens,
|
|
624
694
|
"classified-principal-ids": () => !0,
|
|
625
695
|
"readiness-requirements": hasReadinessRequirements,
|
|
626
|
-
"due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime")
|
|
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
|
|
627
700
|
};
|
|
628
701
|
|
|
629
702
|
function requiredModelFeatures(documentType, document) {
|
|
@@ -1157,12 +1230,8 @@ function renderWorkflowRead(read, ctx) {
|
|
|
1157
1230
|
text: groqConditionDescribe.guillemets(title)
|
|
1158
1231
|
});
|
|
1159
1232
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
permission: read.path[0]
|
|
1163
|
-
},
|
|
1164
|
-
text: `your ${read.path[0]} permission`
|
|
1165
|
-
});
|
|
1233
|
+
const keyed = keyedCallerRead(read);
|
|
1234
|
+
if (keyed !== void 0) return keyed;
|
|
1166
1235
|
if (read.variable === "actor" && read.path.length === 1 && read.path[0] === "id") return groqConditionDescribe.phrase("read.actor-id", {
|
|
1167
1236
|
params: {},
|
|
1168
1237
|
text: "your id"
|
|
@@ -1184,6 +1253,24 @@ function renderWorkflowRead(read, ctx) {
|
|
|
1184
1253
|
});
|
|
1185
1254
|
}
|
|
1186
1255
|
|
|
1256
|
+
function keyedCallerRead(read) {
|
|
1257
|
+
const key = read.path[0];
|
|
1258
|
+
if (typeof key == "string") {
|
|
1259
|
+
if (read.variable === "can") return groqConditionDescribe.phrase("read.permission", {
|
|
1260
|
+
params: {
|
|
1261
|
+
permission: key
|
|
1262
|
+
},
|
|
1263
|
+
text: `your ${key} permission`
|
|
1264
|
+
});
|
|
1265
|
+
if (read.variable === "attributes") return groqConditionDescribe.phrase("read.attribute", {
|
|
1266
|
+
params: {
|
|
1267
|
+
attribute: key
|
|
1268
|
+
},
|
|
1269
|
+
text: `your ${groqConditionDescribe.guillemets(key)} attribute`
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1187
1274
|
function workflowRequirement(requirement, ctx) {
|
|
1188
1275
|
const {target: target} = requirement, clause = clauseVarRequirement(requirement);
|
|
1189
1276
|
if (clause !== void 0) return clause;
|
|
@@ -2084,6 +2171,10 @@ function derefBase(ref, snapshot) {
|
|
|
2084
2171
|
};
|
|
2085
2172
|
}
|
|
2086
2173
|
|
|
2174
|
+
function isRecord(value) {
|
|
2175
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2087
2178
|
function buildParams(args) {
|
|
2088
2179
|
const {instance: instance, now: now, snapshot: snapshot, extra: extra} = args, currentActivities2 = findOpenStageEntry(instance)?.activities ?? [];
|
|
2089
2180
|
return {
|
|
@@ -2612,7 +2703,7 @@ class CascadeLimitError extends invariants.WorkflowError {
|
|
|
2612
2703
|
}
|
|
2613
2704
|
}
|
|
2614
2705
|
|
|
2615
|
-
const FIELD_OP_TYPES = [ "field.set", "field.unset", "field.append", "field.updateWhere", "field.removeWhere" ];
|
|
2706
|
+
const FIELD_OP_TYPES = [ "field.set", "field.setIfMissing", "field.unset", "field.append", "field.inc", "field.dec", "field.updateWhere", "field.removeWhere" ];
|
|
2616
2707
|
|
|
2617
2708
|
function isFieldOp(summary) {
|
|
2618
2709
|
return FIELD_OP_TYPES.includes(summary.opType);
|
|
@@ -2713,7 +2804,7 @@ async function runOps(args) {
|
|
|
2713
2804
|
refSurface: refSurface,
|
|
2714
2805
|
opsFromDefinition: opsFromDefinition
|
|
2715
2806
|
});
|
|
2716
|
-
summaries.push(summary), mutation.history.push(opAppliedEntry({
|
|
2807
|
+
summaries.push(summary), shouldRecordOpApplied(summary) && mutation.history.push(opAppliedEntry({
|
|
2717
2808
|
origin: origin,
|
|
2718
2809
|
summary: summary,
|
|
2719
2810
|
stage: stage,
|
|
@@ -2724,6 +2815,10 @@ async function runOps(args) {
|
|
|
2724
2815
|
return summaries;
|
|
2725
2816
|
}
|
|
2726
2817
|
|
|
2818
|
+
function shouldRecordOpApplied(summary) {
|
|
2819
|
+
return summary.opType !== "field.setIfMissing" || summary.resolved !== void 0;
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2727
2822
|
function opAppliedEntry(args) {
|
|
2728
2823
|
const {origin: origin, summary: summary, stage: stage, actor: actor, now: now} = args;
|
|
2729
2824
|
return {
|
|
@@ -2795,12 +2890,19 @@ async function applyOp(op, ctx) {
|
|
|
2795
2890
|
case "field.set":
|
|
2796
2891
|
return applyFieldSet(op, ctx);
|
|
2797
2892
|
|
|
2893
|
+
case "field.setIfMissing":
|
|
2894
|
+
return applyFieldSetIfMissing(op, ctx);
|
|
2895
|
+
|
|
2798
2896
|
case "field.unset":
|
|
2799
2897
|
return applyFieldUnset(op, ctx);
|
|
2800
2898
|
|
|
2801
2899
|
case "field.append":
|
|
2802
2900
|
return applyFieldAppend(op, ctx);
|
|
2803
2901
|
|
|
2902
|
+
case "field.inc":
|
|
2903
|
+
case "field.dec":
|
|
2904
|
+
return applyFieldArithmetic(op, ctx);
|
|
2905
|
+
|
|
2804
2906
|
case "field.updateWhere":
|
|
2805
2907
|
return applyFieldUpdateWhere(op, ctx);
|
|
2806
2908
|
|
|
@@ -2839,6 +2941,78 @@ function applyFieldSet(op, ctx) {
|
|
|
2839
2941
|
};
|
|
2840
2942
|
}
|
|
2841
2943
|
|
|
2944
|
+
function applyFieldSetIfMissing(op, ctx) {
|
|
2945
|
+
const entry = locateEntry(ctx, op.target);
|
|
2946
|
+
return invariants.isAlwaysArrayFieldKind(entry._type) && rejectFieldOpTarget({
|
|
2947
|
+
entry: entry,
|
|
2948
|
+
op: op,
|
|
2949
|
+
issue: "is always array-valued — setIfMissing applies to nullable entries only; an empty array entry already holds []"
|
|
2950
|
+
}), entry.value !== null && entry.value !== void 0 ? {
|
|
2951
|
+
opType: op.type,
|
|
2952
|
+
target: op.target
|
|
2953
|
+
} : {
|
|
2954
|
+
...applyFieldSet({
|
|
2955
|
+
...op,
|
|
2956
|
+
type: "field.set"
|
|
2957
|
+
}, ctx),
|
|
2958
|
+
opType: op.type
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
function applyFieldArithmetic(op, ctx) {
|
|
2963
|
+
const entry = locateEntry(ctx, op.target);
|
|
2964
|
+
entry._type !== "number" && rejectFieldOpTarget({
|
|
2965
|
+
entry: entry,
|
|
2966
|
+
op: op,
|
|
2967
|
+
issue: `is a ${entry._type} entry — arithmetic ops target \`number\` entries only`
|
|
2968
|
+
}), typeof entry.value != "number" && rejectFieldOpTarget({
|
|
2969
|
+
entry: entry,
|
|
2970
|
+
op: op,
|
|
2971
|
+
issue: "has no numeric value — initialize it before applying arithmetic"
|
|
2972
|
+
});
|
|
2973
|
+
const resolvedDelta = op.value === void 0 ? 1 : resolveOpValue({
|
|
2974
|
+
src: op.value,
|
|
2975
|
+
ctx: ctx,
|
|
2976
|
+
target: {
|
|
2977
|
+
kind: "number"
|
|
2978
|
+
}
|
|
2979
|
+
});
|
|
2980
|
+
(typeof resolvedDelta != "number" || !Number.isFinite(resolvedDelta)) && rejectFieldOpTarget({
|
|
2981
|
+
entry: entry,
|
|
2982
|
+
op: op,
|
|
2983
|
+
issue: "value must resolve to a finite number"
|
|
2984
|
+
});
|
|
2985
|
+
const nextValue = entry.value + (op.type === "field.inc" ? resolvedDelta : -resolvedDelta);
|
|
2986
|
+
Number.isFinite(nextValue) || rejectFieldOpTarget({
|
|
2987
|
+
entry: entry,
|
|
2988
|
+
op: op,
|
|
2989
|
+
issue: "result must be a finite number"
|
|
2990
|
+
});
|
|
2991
|
+
const value = invariants.validateFieldValue({
|
|
2992
|
+
entryType: entry._type,
|
|
2993
|
+
entryName: entry.name,
|
|
2994
|
+
value: nextValue,
|
|
2995
|
+
...entryShape(entry)
|
|
2996
|
+
});
|
|
2997
|
+
return setEntryValue(entry, value), {
|
|
2998
|
+
opType: op.type,
|
|
2999
|
+
target: op.target,
|
|
3000
|
+
resolved: {
|
|
3001
|
+
value: value
|
|
3002
|
+
}
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
function rejectFieldOpTarget(args) {
|
|
3007
|
+
const {entry: entry, op: op, issue: issue} = args;
|
|
3008
|
+
throw new invariants.FieldValueShapeError({
|
|
3009
|
+
entryType: entry._type,
|
|
3010
|
+
entryName: entry.name,
|
|
3011
|
+
mode: "value",
|
|
3012
|
+
issues: [ `${op.type} target ${op.target.scope}:"${op.target.field}" ${issue}` ]
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
|
|
2842
3016
|
function entryShape(entry) {
|
|
2843
3017
|
return entry._type === "object" ? {
|
|
2844
3018
|
fields: entry.fields
|
|
@@ -2874,15 +3048,10 @@ function appendItemSlot(entry) {
|
|
|
2874
3048
|
};
|
|
2875
3049
|
}
|
|
2876
3050
|
|
|
2877
|
-
const EMPTY_BY_KIND = {
|
|
2878
|
-
"doc.refs": [],
|
|
2879
|
-
array: [],
|
|
2880
|
-
assignees: []
|
|
2881
|
-
};
|
|
2882
|
-
|
|
2883
3051
|
function applyFieldUnset(op, ctx) {
|
|
2884
3052
|
const entry = locateEntry(ctx, op.target);
|
|
2885
|
-
return setEntryValue(entry,
|
|
3053
|
+
return setEntryValue(entry, invariants.isAlwaysArrayFieldKind(entry._type) ? [] : null),
|
|
3054
|
+
{
|
|
2886
3055
|
opType: op.type,
|
|
2887
3056
|
target: op.target
|
|
2888
3057
|
};
|
|
@@ -2921,7 +3090,7 @@ function applyFieldAppend(op, ctx) {
|
|
|
2921
3090
|
}
|
|
2922
3091
|
|
|
2923
3092
|
function withRowKey(item) {
|
|
2924
|
-
return
|
|
3093
|
+
return isRecord(item) && !("_key" in item) ? {
|
|
2925
3094
|
_key: randomKey(),
|
|
2926
3095
|
...item
|
|
2927
3096
|
} : item;
|
|
@@ -3620,6 +3789,14 @@ function latestDeployedDefinitions(rows) {
|
|
|
3620
3789
|
return [ ...byName.values() ];
|
|
3621
3790
|
}
|
|
3622
3791
|
|
|
3792
|
+
function findStageNode(args) {
|
|
3793
|
+
return args.definition?.stages.find(entry => entry.name === args.stageName);
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
function findActivityNode(args) {
|
|
3797
|
+
return findStageNode(args)?.activities?.find(entry => entry.name === args.activityName);
|
|
3798
|
+
}
|
|
3799
|
+
|
|
3623
3800
|
function liveChildrenField(instance) {
|
|
3624
3801
|
const live = liveSubworkflows(instance).length;
|
|
3625
3802
|
return live > 0 ? {
|
|
@@ -3708,6 +3885,27 @@ function noTransitionFiresCause(input) {
|
|
|
3708
3885
|
};
|
|
3709
3886
|
}
|
|
3710
3887
|
|
|
3888
|
+
function stuckFromDocumentState(input) {
|
|
3889
|
+
return failedEffectCause(input) ?? failedActivityCause(input) ?? hungEffectCause(input);
|
|
3890
|
+
}
|
|
3891
|
+
|
|
3892
|
+
function documentStuckCause(args) {
|
|
3893
|
+
const stage = findOpenStageEntry(args.instance);
|
|
3894
|
+
if (stage !== void 0) return stuckFromDocumentState({
|
|
3895
|
+
instance: args.instance,
|
|
3896
|
+
activities: stage.activities.map(entry => ({
|
|
3897
|
+
status: entry.status,
|
|
3898
|
+
activity: findActivityNode({
|
|
3899
|
+
activityName: entry.name,
|
|
3900
|
+
definition: args.definition,
|
|
3901
|
+
stageName: stage.name
|
|
3902
|
+
}) ?? {
|
|
3903
|
+
name: entry.name
|
|
3904
|
+
}
|
|
3905
|
+
}))
|
|
3906
|
+
});
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3711
3909
|
function diagnoseInstance(input) {
|
|
3712
3910
|
const {instance: instance} = input, terminal = terminalState(instance);
|
|
3713
3911
|
if (terminal === "aborted" && instance.abortedAt !== void 0) {
|
|
@@ -3726,7 +3924,7 @@ function diagnoseInstance(input) {
|
|
|
3726
3924
|
at: instance.completedAt,
|
|
3727
3925
|
...liveChildrenField(instance)
|
|
3728
3926
|
};
|
|
3729
|
-
const cause =
|
|
3927
|
+
const cause = stuckFromDocumentState(input) ?? noTransitionFiresCause(input);
|
|
3730
3928
|
return cause !== void 0 ? {
|
|
3731
3929
|
state: "stuck",
|
|
3732
3930
|
cause: cause
|
|
@@ -4105,10 +4303,8 @@ function assertRequiredInputProvided({entryDefs: entryDefs, initialFields: initi
|
|
|
4105
4303
|
});
|
|
4106
4304
|
}
|
|
4107
4305
|
|
|
4108
|
-
const ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([ "doc.refs", "array", "assignees" ]);
|
|
4109
|
-
|
|
4110
4306
|
function defaultEntryValue(entryType) {
|
|
4111
|
-
return
|
|
4307
|
+
return invariants.isAlwaysArrayFieldKind(entryType) ? [] : null;
|
|
4112
4308
|
}
|
|
4113
4309
|
|
|
4114
4310
|
function resolveInputValue({entry: entry, initialFields: initialFields, defaultValue: defaultValue}) {
|
|
@@ -4709,7 +4905,9 @@ const SYNC_COMMIT = {
|
|
|
4709
4905
|
effect: "workflow.effect",
|
|
4710
4906
|
verifyDefinitions: "workflow.verify-definitions",
|
|
4711
4907
|
accessResolveActor: "workflow.access.resolve-actor",
|
|
4712
|
-
accessGrants: "workflow.access.grants"
|
|
4908
|
+
accessGrants: "workflow.access.grants",
|
|
4909
|
+
accessResolveOrg: "workflow.access.resolve-org",
|
|
4910
|
+
accessAttributes: "workflow.access.attributes"
|
|
4713
4911
|
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
4714
4912
|
|
|
4715
4913
|
function unwrapPatch(patch) {
|
|
@@ -5677,10 +5875,6 @@ function userLoginProvider(user) {
|
|
|
5677
5875
|
return user?.provider ?? user?.loginProvider;
|
|
5678
5876
|
}
|
|
5679
5877
|
|
|
5680
|
-
function isRecord(value) {
|
|
5681
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
5682
|
-
}
|
|
5683
|
-
|
|
5684
5878
|
function optionalString(value) {
|
|
5685
5879
|
return value === void 0 || typeof value == "string";
|
|
5686
5880
|
}
|
|
@@ -7218,116 +7412,523 @@ async function advisoryCan({instance: instance, identity: identity, grants: gran
|
|
|
7218
7412
|
return can;
|
|
7219
7413
|
}
|
|
7220
7414
|
|
|
7221
|
-
|
|
7222
|
-
return {
|
|
7223
|
-
name: requirement.name,
|
|
7224
|
-
...requirement.title !== void 0 ? {
|
|
7225
|
-
title: requirement.title
|
|
7226
|
-
} : {},
|
|
7227
|
-
...requirement.description !== void 0 ? {
|
|
7228
|
-
description: requirement.description
|
|
7229
|
-
} : {}
|
|
7230
|
-
};
|
|
7231
|
-
}
|
|
7415
|
+
const DANGEROUS_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([ "__proto__", "constructor", "prototype" ]);
|
|
7232
7416
|
|
|
7233
|
-
function
|
|
7234
|
-
|
|
7417
|
+
function attributeEntry(row) {
|
|
7418
|
+
if (!(!isRecord(row) || typeof row.key != "string" || row.key.length === 0) && !DANGEROUS_ATTRIBUTE_KEYS.has(row.key) && !(!("activeValue" in row) || row.activeValue === void 0)) return [ row.key, row.activeValue ];
|
|
7235
7419
|
}
|
|
7236
7420
|
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
reason: args.reason
|
|
7246
|
-
})), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
|
|
7247
|
-
this.action = args.action;
|
|
7421
|
+
function normalizeUserAttributes(response) {
|
|
7422
|
+
if (!isRecord(response)) return;
|
|
7423
|
+
const rows = response.attributes;
|
|
7424
|
+
if (!Array.isArray(rows)) return;
|
|
7425
|
+
const out = {};
|
|
7426
|
+
for (const row of rows) {
|
|
7427
|
+
const entry = attributeEntry(row);
|
|
7428
|
+
entry !== void 0 && (out[entry[0]] = entry[1]);
|
|
7248
7429
|
}
|
|
7430
|
+
return out;
|
|
7249
7431
|
}
|
|
7250
7432
|
|
|
7251
|
-
|
|
7252
|
-
definition;
|
|
7253
|
-
unmetRequirements;
|
|
7254
|
-
constructor(args) {
|
|
7255
|
-
super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
|
|
7256
|
-
this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
|
|
7257
|
-
}
|
|
7258
|
-
}
|
|
7433
|
+
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap, orgIdCache = /* @__PURE__ */ new WeakMap, attributesCache = /* @__PURE__ */ new WeakMap;
|
|
7259
7434
|
|
|
7260
|
-
function
|
|
7261
|
-
const
|
|
7262
|
-
|
|
7435
|
+
async function resolveAccess(taggedClient, args = {}) {
|
|
7436
|
+
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
7437
|
+
if (requestFn === void 0) throw new invariants.ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({ uri: '/users/me' })`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
|
|
7438
|
+
const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
|
|
7439
|
+
client: client,
|
|
7440
|
+
requestFn: requestFn,
|
|
7441
|
+
resourcePath: args.grantsFromPath
|
|
7442
|
+
}) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
7443
|
+
if (identity === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
|
|
7444
|
+
return {
|
|
7445
|
+
actor: identity.actor,
|
|
7446
|
+
...identity.localPrincipalId !== void 0 ? {
|
|
7447
|
+
localPrincipalId: identity.localPrincipalId
|
|
7448
|
+
} : {},
|
|
7449
|
+
...grants !== void 0 ? {
|
|
7450
|
+
grants: grants
|
|
7451
|
+
} : {}
|
|
7452
|
+
};
|
|
7263
7453
|
}
|
|
7264
7454
|
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
7272
|
-
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
|
|
7273
|
-
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
7274
|
-
};
|
|
7275
|
-
|
|
7276
|
-
function actionDisabledDetail(reason) {
|
|
7277
|
-
return disabledReasonDetail[reason.kind](reason);
|
|
7455
|
+
async function resolveUserAttributes(taggedClient) {
|
|
7456
|
+
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
7457
|
+
if (requestFn !== void 0) return cachedAttributes({
|
|
7458
|
+
client: client,
|
|
7459
|
+
requestFn: requestFn
|
|
7460
|
+
});
|
|
7278
7461
|
}
|
|
7279
7462
|
|
|
7280
|
-
function
|
|
7281
|
-
|
|
7463
|
+
function cachedActor(client, requestFn) {
|
|
7464
|
+
const cached = actorCache.get(client);
|
|
7465
|
+
if (cached !== void 0) return cached;
|
|
7466
|
+
const pending = fetchActor(client, requestFn).catch(err => {
|
|
7467
|
+
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
7468
|
+
});
|
|
7469
|
+
return actorCache.set(client, pending), pending;
|
|
7282
7470
|
}
|
|
7283
7471
|
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
}
|
|
7472
|
+
function grantsForClientPath(taggedClient, resourcePath) {
|
|
7473
|
+
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
7474
|
+
return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
|
|
7475
|
+
client: client,
|
|
7476
|
+
requestFn: requestFn,
|
|
7477
|
+
resourcePath: resourcePath
|
|
7478
|
+
});
|
|
7291
7479
|
}
|
|
7292
7480
|
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
7296
|
-
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
7297
|
-
"edit-window-closed": r => `edit window closed (${r.detail})`,
|
|
7298
|
-
"editor-not-permitted": r => `editor not permitted (${r.predicate})`
|
|
7299
|
-
};
|
|
7300
|
-
|
|
7301
|
-
function formatEditDisabledReason(target, reason) {
|
|
7302
|
-
const detail = editDisabledReasonDetail[reason.kind](reason), where = target.activity !== void 0 ? `${target.activity}.${target.field}` : target.field;
|
|
7303
|
-
return `Field "${target.scope}:${where}" is not editable: ${detail}`;
|
|
7481
|
+
function lazyRequest(client) {
|
|
7482
|
+
return client.request === void 0 ? void 0 : opts => client.request(opts);
|
|
7304
7483
|
}
|
|
7305
7484
|
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7485
|
+
function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
|
|
7486
|
+
return cachedByKey({
|
|
7487
|
+
store: grantsCache,
|
|
7309
7488
|
client: client,
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
commit: ctx => commitAction({
|
|
7313
|
-
ctx: ctx,
|
|
7314
|
-
activityName: activity,
|
|
7315
|
-
actionName: action,
|
|
7316
|
-
callerParams: params,
|
|
7317
|
-
requestRecord: requestRecord,
|
|
7318
|
-
options: options
|
|
7319
|
-
}),
|
|
7320
|
-
onExhausted: () => new ConcurrentFireActionError({
|
|
7321
|
-
instanceId: instanceId,
|
|
7322
|
-
activity: activity,
|
|
7323
|
-
action: action,
|
|
7324
|
-
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
7325
|
-
})
|
|
7489
|
+
key: resourcePath,
|
|
7490
|
+
load: () => fetchGrantsCached(requestFn, resourcePath)
|
|
7326
7491
|
});
|
|
7327
7492
|
}
|
|
7328
7493
|
|
|
7329
|
-
|
|
7330
|
-
|
|
7494
|
+
function cachedByKey(args) {
|
|
7495
|
+
let byKey = args.store.get(args.client);
|
|
7496
|
+
byKey === void 0 && (byKey = /* @__PURE__ */ new Map, args.store.set(args.client, byKey));
|
|
7497
|
+
const cached = byKey.get(args.key);
|
|
7498
|
+
if (cached !== void 0) return cached;
|
|
7499
|
+
const pending = args.evictOnRejection ? args.load().catch(err => {
|
|
7500
|
+
throw byKey.get(args.key) === pending && byKey.delete(args.key), err;
|
|
7501
|
+
}) : args.load();
|
|
7502
|
+
return byKey.set(args.key, pending), pending;
|
|
7503
|
+
}
|
|
7504
|
+
|
|
7505
|
+
async function fetchActor(client, requestFn) {
|
|
7506
|
+
const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = invariants.firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
|
|
7507
|
+
if (sessionId === void 0) return;
|
|
7508
|
+
const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
|
|
7509
|
+
client: client,
|
|
7510
|
+
sessionId: sessionId,
|
|
7511
|
+
resourceId: resourceId
|
|
7512
|
+
}) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
|
|
7513
|
+
refuseProjectScopedActor({
|
|
7514
|
+
id: id,
|
|
7515
|
+
globalUser: globalUser,
|
|
7516
|
+
globalHostId: globalHostId,
|
|
7517
|
+
bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
|
|
7518
|
+
});
|
|
7519
|
+
const roleNames = roleNamesFor(resourceUser, globalUser);
|
|
7520
|
+
return {
|
|
7521
|
+
actor: {
|
|
7522
|
+
kind: "person",
|
|
7523
|
+
id: id,
|
|
7524
|
+
...roleNames.length > 0 ? {
|
|
7525
|
+
roles: roleNames
|
|
7526
|
+
} : {}
|
|
7527
|
+
},
|
|
7528
|
+
...resourceId !== void 0 && resourceId !== id ? {
|
|
7529
|
+
localPrincipalId: resourceId
|
|
7530
|
+
} : {}
|
|
7531
|
+
};
|
|
7532
|
+
}
|
|
7533
|
+
|
|
7534
|
+
function roleNamesFor(resourceUser, globalUser) {
|
|
7535
|
+
return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
7536
|
+
}
|
|
7537
|
+
|
|
7538
|
+
const NO_BRIDGE = {
|
|
7539
|
+
status: "not-applicable"
|
|
7540
|
+
};
|
|
7541
|
+
|
|
7542
|
+
function globalRouteReason(globalUser, globalHostId) {
|
|
7543
|
+
return "reason" in globalUser ? globalUser.reason : globalHostId === void 0 ? "no record" : `the global host answered with project-scoped principal "${globalHostId}"`;
|
|
7544
|
+
}
|
|
7545
|
+
|
|
7546
|
+
async function bridgeProjectPrincipal(args) {
|
|
7547
|
+
const {client: client, sessionId: sessionId, resourceId: resourceId} = args;
|
|
7548
|
+
return invariants.classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project" ? {
|
|
7549
|
+
status: "unavailable",
|
|
7550
|
+
reason: "no project-scoped principal from the resource host to address the directory with"
|
|
7551
|
+
} : directoryGlobalId({
|
|
7552
|
+
client: client,
|
|
7553
|
+
principalId: resourceId
|
|
7554
|
+
});
|
|
7555
|
+
}
|
|
7556
|
+
|
|
7557
|
+
async function directoryGlobalId(args) {
|
|
7558
|
+
const {client: client, principalId: principalId} = args, projectId = projectIdOf(client);
|
|
7559
|
+
if (projectId === void 0) return {
|
|
7560
|
+
status: "unavailable",
|
|
7561
|
+
reason: "the client reports no projectId, so its user directory has no address"
|
|
7562
|
+
};
|
|
7563
|
+
const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
|
|
7564
|
+
if (lookup.status !== "resolved") return {
|
|
7565
|
+
status: "unavailable",
|
|
7566
|
+
reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
|
|
7567
|
+
...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
|
|
7568
|
+
cause: lookup.cause
|
|
7569
|
+
} : {}
|
|
7570
|
+
};
|
|
7571
|
+
const globalId = invariants.directoryBridgeId(lookup.user.sanityUserId);
|
|
7572
|
+
return globalId === void 0 ? {
|
|
7573
|
+
status: "unavailable",
|
|
7574
|
+
reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
|
|
7575
|
+
} : {
|
|
7576
|
+
status: "resolved",
|
|
7577
|
+
globalId: globalId
|
|
7578
|
+
};
|
|
7579
|
+
}
|
|
7580
|
+
|
|
7581
|
+
function refuseProjectScopedActor(args) {
|
|
7582
|
+
const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
|
|
7583
|
+
if (invariants.classifyPrincipalId(id).namespace !== "project") return;
|
|
7584
|
+
const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
|
|
7585
|
+
bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
|
|
7586
|
+
const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
|
|
7587
|
+
throw new Error(`workflow: the caller's identity resolves to the project-scoped principal "${id}" and its account-global id could not be resolved. ${routes.join(" ")} The engine speaks account-global user ids only and never acts as a project-scoped principal.`, cause === void 0 ? void 0 : {
|
|
7588
|
+
cause: cause
|
|
7589
|
+
});
|
|
7590
|
+
}
|
|
7591
|
+
|
|
7592
|
+
function usableId(user) {
|
|
7593
|
+
if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
|
|
7594
|
+
}
|
|
7595
|
+
|
|
7596
|
+
async function fetchCurrentUser(requestFn, hostDescription) {
|
|
7597
|
+
try {
|
|
7598
|
+
return await requestFn({
|
|
7599
|
+
uri: "/users/me",
|
|
7600
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
7601
|
+
});
|
|
7602
|
+
} catch (err) {
|
|
7603
|
+
throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({ uri: '/users/me' })\`. Check the token/connectivity.`, {
|
|
7604
|
+
cause: err
|
|
7605
|
+
});
|
|
7606
|
+
}
|
|
7607
|
+
}
|
|
7608
|
+
|
|
7609
|
+
async function fetchGlobalUser(client) {
|
|
7610
|
+
const sibling = globalHostRequestOf(client);
|
|
7611
|
+
if ("reason" in sibling) return {
|
|
7612
|
+
user: void 0,
|
|
7613
|
+
reason: sibling.reason,
|
|
7614
|
+
...sibling.cause !== void 0 ? {
|
|
7615
|
+
cause: sibling.cause
|
|
7616
|
+
} : {}
|
|
7617
|
+
};
|
|
7618
|
+
try {
|
|
7619
|
+
const user = await sibling.request({
|
|
7620
|
+
uri: "/users/me",
|
|
7621
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
7622
|
+
}), id = usableId(user);
|
|
7623
|
+
return sibling.requireGlobalPrincipal && id !== void 0 && invariants.classifyPrincipalId(id).namespace === "project" ? {
|
|
7624
|
+
user: void 0,
|
|
7625
|
+
reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
|
|
7626
|
+
} : {
|
|
7627
|
+
user: user
|
|
7628
|
+
};
|
|
7629
|
+
} catch (err) {
|
|
7630
|
+
return {
|
|
7631
|
+
user: void 0,
|
|
7632
|
+
reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
|
|
7633
|
+
cause: err
|
|
7634
|
+
};
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
|
|
7638
|
+
function globalHostRequestOf(client) {
|
|
7639
|
+
if (typeof client.withConfig != "function") return {
|
|
7640
|
+
reason: "the client cannot reach the global API host (no withConfig)"
|
|
7641
|
+
};
|
|
7642
|
+
const hostResolution = resolveGlobalApiHost(client);
|
|
7643
|
+
try {
|
|
7644
|
+
const globalClient = client.withConfig({
|
|
7645
|
+
useProjectHostname: !1,
|
|
7646
|
+
apiVersion: ENGINE_API_VERSION,
|
|
7647
|
+
...hostResolution.apiHost === void 0 ? {} : {
|
|
7648
|
+
apiHost: hostResolution.apiHost
|
|
7649
|
+
}
|
|
7650
|
+
}), request = lazyRequest(globalClient);
|
|
7651
|
+
return request === void 0 ? {
|
|
7652
|
+
reason: "the global-host sibling client cannot issue requests"
|
|
7653
|
+
} : {
|
|
7654
|
+
request: request,
|
|
7655
|
+
requireGlobalPrincipal: hostResolution.requireGlobalPrincipal
|
|
7656
|
+
};
|
|
7657
|
+
} catch (err) {
|
|
7658
|
+
return {
|
|
7659
|
+
reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
|
|
7660
|
+
cause: err
|
|
7661
|
+
};
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
|
|
7665
|
+
function resolveGlobalApiHost(client) {
|
|
7666
|
+
if (typeof client.config != "function") return {
|
|
7667
|
+
requireGlobalPrincipal: !1
|
|
7668
|
+
};
|
|
7669
|
+
const apiHost = client.config().apiHost;
|
|
7670
|
+
if (apiHost === void 0) return {
|
|
7671
|
+
requireGlobalPrincipal: !1
|
|
7672
|
+
};
|
|
7673
|
+
let parsed;
|
|
7674
|
+
try {
|
|
7675
|
+
parsed = new URL(apiHost);
|
|
7676
|
+
} catch {
|
|
7677
|
+
return {
|
|
7678
|
+
requireGlobalPrincipal: !0
|
|
7679
|
+
};
|
|
7680
|
+
}
|
|
7681
|
+
if (/^api\.sanity\.(io|work)$/.test(parsed.hostname)) return {
|
|
7682
|
+
requireGlobalPrincipal: !1
|
|
7683
|
+
};
|
|
7684
|
+
const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
|
|
7685
|
+
return match === null ? {
|
|
7686
|
+
requireGlobalPrincipal: !0
|
|
7687
|
+
} : (parsed.hostname = `api.sanity.${match[1]}`, {
|
|
7688
|
+
apiHost: parsed.origin,
|
|
7689
|
+
requireGlobalPrincipal: !0
|
|
7690
|
+
});
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7693
|
+
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
7694
|
+
try {
|
|
7695
|
+
return await fetchGrants({
|
|
7696
|
+
client: {
|
|
7697
|
+
request: requestFn
|
|
7698
|
+
},
|
|
7699
|
+
resourcePath: resourcePath
|
|
7700
|
+
});
|
|
7701
|
+
} catch (err) {
|
|
7702
|
+
console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
|
|
7703
|
+
return;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
|
|
7707
|
+
function projectIdOf(client) {
|
|
7708
|
+
if (typeof client.config != "function") return;
|
|
7709
|
+
const projectId = client.config().projectId;
|
|
7710
|
+
return typeof projectId == "string" && projectId.length > 0 ? projectId : void 0;
|
|
7711
|
+
}
|
|
7712
|
+
|
|
7713
|
+
function cachedAttributes(args) {
|
|
7714
|
+
const projectId = projectIdOf(args.client);
|
|
7715
|
+
return projectId === void 0 ? Promise.resolve(void 0) : resolveOrganizationId({
|
|
7716
|
+
client: args.client,
|
|
7717
|
+
requestFn: args.requestFn,
|
|
7718
|
+
projectId: projectId
|
|
7719
|
+
}).then(orgId => {
|
|
7720
|
+
if (orgId !== void 0) return cachedByKey({
|
|
7721
|
+
store: attributesCache,
|
|
7722
|
+
client: args.client,
|
|
7723
|
+
key: orgId,
|
|
7724
|
+
evictOnRejection: !0,
|
|
7725
|
+
load: () => fetchAttributesCached({
|
|
7726
|
+
client: args.client,
|
|
7727
|
+
orgId: orgId
|
|
7728
|
+
})
|
|
7729
|
+
});
|
|
7730
|
+
});
|
|
7731
|
+
}
|
|
7732
|
+
|
|
7733
|
+
async function resolveOrganizationId(args) {
|
|
7734
|
+
const {client: client, requestFn: requestFn, projectId: projectId} = args;
|
|
7735
|
+
return cachedByKey({
|
|
7736
|
+
store: orgIdCache,
|
|
7737
|
+
client: client,
|
|
7738
|
+
key: projectId,
|
|
7739
|
+
evictOnRejection: !0,
|
|
7740
|
+
load: async () => {
|
|
7741
|
+
try {
|
|
7742
|
+
const project = await requestFn({
|
|
7743
|
+
uri: `/projects/${encodeURIComponent(projectId)}`,
|
|
7744
|
+
tag: REQUEST_TAG.accessResolveOrg
|
|
7745
|
+
});
|
|
7746
|
+
if (!isRecord(project)) return;
|
|
7747
|
+
const orgId = project.organizationId;
|
|
7748
|
+
return typeof orgId == "string" && orgId.length > 0 ? orgId : void 0;
|
|
7749
|
+
} catch (err) {
|
|
7750
|
+
const status = httpStatusOf(err);
|
|
7751
|
+
if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
|
|
7752
|
+
throw new Error(`workflow: failed to resolve organizationId for project "${projectId}"; advisory $attributes cannot be bound. Original error: ${invariants.errorMessage(err)}`, {
|
|
7753
|
+
cause: err
|
|
7754
|
+
});
|
|
7755
|
+
}
|
|
7756
|
+
}
|
|
7757
|
+
});
|
|
7758
|
+
}
|
|
7759
|
+
|
|
7760
|
+
const ATTRIBUTES_FETCH_LIMIT = 100, EXPECTED_ATTRIBUTES_ABSENCE = /* @__PURE__ */ new Set([ 401, 402, 403, 404 ]);
|
|
7761
|
+
|
|
7762
|
+
function httpStatusOf(err) {
|
|
7763
|
+
if (!isRecord(err)) return;
|
|
7764
|
+
const status = err.statusCode;
|
|
7765
|
+
return typeof status == "number" ? status : void 0;
|
|
7766
|
+
}
|
|
7767
|
+
|
|
7768
|
+
async function fetchAttributesCached(args) {
|
|
7769
|
+
const {client: client, orgId: orgId} = args, sibling = globalHostRequestOf(client);
|
|
7770
|
+
if ("reason" in sibling) {
|
|
7771
|
+
console.warn(`workflow: skipped org attributes fetch (${sibling.reason}); advisory $attributes stays undefined (conditions referencing it fail closed).`);
|
|
7772
|
+
return;
|
|
7773
|
+
}
|
|
7774
|
+
try {
|
|
7775
|
+
const response = await sibling.request({
|
|
7776
|
+
uri: `/organizations/${encodeURIComponent(orgId)}/users/me/attributes?limit=${ATTRIBUTES_FETCH_LIMIT}`,
|
|
7777
|
+
tag: REQUEST_TAG.accessAttributes
|
|
7778
|
+
}), envelope = isRecord(response) ? response : void 0;
|
|
7779
|
+
if (envelope?.hasMore === !0) {
|
|
7780
|
+
const page = Array.isArray(envelope.attributes) ? envelope.attributes : [];
|
|
7781
|
+
console.warn(`workflow: org attributes for organization "${orgId}" report hasMore=true (bound ${page.length} of the requested limit ${ATTRIBUTES_FETCH_LIMIT}); advisory $attributes may be incomplete — the engine fetches no further pages. Conditions that read missing keys fail closed.`);
|
|
7782
|
+
}
|
|
7783
|
+
const normalized = normalizeUserAttributes(response);
|
|
7784
|
+
return normalized === void 0 && console.warn(`workflow: org attributes response for organization "${orgId}" was unusable; advisory $attributes stays undefined (conditions referencing it fail closed).`),
|
|
7785
|
+
normalized;
|
|
7786
|
+
} catch (err) {
|
|
7787
|
+
const status = httpStatusOf(err);
|
|
7788
|
+
if (status !== void 0 && EXPECTED_ATTRIBUTES_ABSENCE.has(status)) return;
|
|
7789
|
+
throw new Error(`workflow: failed to fetch org attributes for organization "${orgId}". Original error: ${invariants.errorMessage(err)}`, {
|
|
7790
|
+
cause: err
|
|
7791
|
+
});
|
|
7792
|
+
}
|
|
7793
|
+
}
|
|
7794
|
+
|
|
7795
|
+
function callerBoundVars(args) {
|
|
7796
|
+
const vars = {
|
|
7797
|
+
...args.can !== void 0 ? {
|
|
7798
|
+
can: args.can
|
|
7799
|
+
} : {},
|
|
7800
|
+
...args.attributes !== void 0 ? {
|
|
7801
|
+
attributes: args.attributes
|
|
7802
|
+
} : {}
|
|
7803
|
+
};
|
|
7804
|
+
return Object.keys(vars).length > 0 ? vars : void 0;
|
|
7805
|
+
}
|
|
7806
|
+
|
|
7807
|
+
async function callerBoundVarsForCall(args) {
|
|
7808
|
+
const can = await advisoryCanForCall({
|
|
7809
|
+
instance: args.instance,
|
|
7810
|
+
options: args.options
|
|
7811
|
+
}), attributes = args.options?.attributes !== void 0 ? args.options.attributes : await resolveUserAttributes(args.client);
|
|
7812
|
+
return callerBoundVars({
|
|
7813
|
+
...can !== void 0 ? {
|
|
7814
|
+
can: can
|
|
7815
|
+
} : {},
|
|
7816
|
+
...attributes !== void 0 ? {
|
|
7817
|
+
attributes: attributes
|
|
7818
|
+
} : {}
|
|
7819
|
+
});
|
|
7820
|
+
}
|
|
7821
|
+
|
|
7822
|
+
function requirementDescriptor(requirement) {
|
|
7823
|
+
return {
|
|
7824
|
+
name: requirement.name,
|
|
7825
|
+
...requirement.title !== void 0 ? {
|
|
7826
|
+
title: requirement.title
|
|
7827
|
+
} : {},
|
|
7828
|
+
...requirement.description !== void 0 ? {
|
|
7829
|
+
description: requirement.description
|
|
7830
|
+
} : {}
|
|
7831
|
+
};
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7834
|
+
function subjectDenialLabels(denied) {
|
|
7835
|
+
return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
|
|
7836
|
+
}
|
|
7837
|
+
|
|
7838
|
+
class ActionDisabledError extends invariants.WorkflowError {
|
|
7839
|
+
reason;
|
|
7840
|
+
activity;
|
|
7841
|
+
action;
|
|
7842
|
+
constructor(args) {
|
|
7843
|
+
super("action-disabled", formatDisabledReason({
|
|
7844
|
+
activity: args.activity,
|
|
7845
|
+
action: args.action,
|
|
7846
|
+
reason: args.reason
|
|
7847
|
+
})), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
|
|
7848
|
+
this.action = args.action;
|
|
7849
|
+
}
|
|
7850
|
+
}
|
|
7851
|
+
|
|
7852
|
+
class StartNotAllowedError extends invariants.WorkflowError {
|
|
7853
|
+
definition;
|
|
7854
|
+
unmetRequirements;
|
|
7855
|
+
constructor(args) {
|
|
7856
|
+
super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
|
|
7857
|
+
this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
|
|
7861
|
+
function actionRendering(action) {
|
|
7862
|
+
const kind = action.disabledReason?.kind;
|
|
7863
|
+
return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
|
|
7864
|
+
}
|
|
7865
|
+
|
|
7866
|
+
const disabledReasonDetail = {
|
|
7867
|
+
"filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
|
|
7868
|
+
"cascade-fired": r => `the action is cascade-fired (when: ${JSON.stringify(r.when)}) — the engine fires it on truth; it cannot be invoked via fireAction`,
|
|
7869
|
+
"activity-not-active": r => `activity status is "${r.status}"`,
|
|
7870
|
+
"stage-terminal": r => `stage "${r.stage}" is terminal`,
|
|
7871
|
+
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
7872
|
+
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
7873
|
+
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
|
|
7874
|
+
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
7875
|
+
};
|
|
7876
|
+
|
|
7877
|
+
function actionDisabledDetail(reason) {
|
|
7878
|
+
return disabledReasonDetail[reason.kind](reason);
|
|
7879
|
+
}
|
|
7880
|
+
|
|
7881
|
+
function formatDisabledReason({activity: activity, action: action, reason: reason}) {
|
|
7882
|
+
return `Action "${activity}:${action}" is not allowed: ${actionDisabledDetail(reason)}`;
|
|
7883
|
+
}
|
|
7884
|
+
|
|
7885
|
+
class EditFieldDeniedError extends invariants.WorkflowError {
|
|
7886
|
+
reason;
|
|
7887
|
+
target;
|
|
7888
|
+
constructor(args) {
|
|
7889
|
+
super("edit-field-denied", formatEditDisabledReason(args.target, args.reason)),
|
|
7890
|
+
this.name = "EditFieldDeniedError", this.reason = args.reason, this.target = args.target;
|
|
7891
|
+
}
|
|
7892
|
+
}
|
|
7893
|
+
|
|
7894
|
+
const editDisabledReasonDetail = {
|
|
7895
|
+
"not-editable": () => "field is not declared editable",
|
|
7896
|
+
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
7897
|
+
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
7898
|
+
"edit-window-closed": r => `edit window closed (${r.detail})`,
|
|
7899
|
+
"editor-not-permitted": r => `editor not permitted (${r.predicate})`
|
|
7900
|
+
};
|
|
7901
|
+
|
|
7902
|
+
function formatEditDisabledReason(target, reason) {
|
|
7903
|
+
const detail = editDisabledReasonDetail[reason.kind](reason), where = target.activity !== void 0 ? `${target.activity}.${target.field}` : target.field;
|
|
7904
|
+
return `Field "${target.scope}:${where}" is not editable: ${detail}`;
|
|
7905
|
+
}
|
|
7906
|
+
|
|
7907
|
+
async function fireAction(args) {
|
|
7908
|
+
const {client: client, instanceId: instanceId, activity: activity, action: action, params: params, requestRecord: requestRecord, options: options} = args;
|
|
7909
|
+
return retryOnRevisionConflict({
|
|
7910
|
+
client: client,
|
|
7911
|
+
instanceId: instanceId,
|
|
7912
|
+
options: options,
|
|
7913
|
+
commit: ctx => commitAction({
|
|
7914
|
+
ctx: ctx,
|
|
7915
|
+
activityName: activity,
|
|
7916
|
+
actionName: action,
|
|
7917
|
+
callerParams: params,
|
|
7918
|
+
requestRecord: requestRecord,
|
|
7919
|
+
options: options
|
|
7920
|
+
}),
|
|
7921
|
+
onExhausted: () => new ConcurrentFireActionError({
|
|
7922
|
+
instanceId: instanceId,
|
|
7923
|
+
activity: activity,
|
|
7924
|
+
action: action,
|
|
7925
|
+
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
7926
|
+
})
|
|
7927
|
+
});
|
|
7928
|
+
}
|
|
7929
|
+
|
|
7930
|
+
async function resolveActionCommit({ctx: ctx, activityName: activityName, actionName: actionName, callerParams: callerParams, options: options}) {
|
|
7931
|
+
const actor = options?.actor, {stage: stage, activity: activity} = findActivityInCurrentStage(ctx, activityName), action = (activity.actions ?? []).find(a => a.name === actionName);
|
|
7331
7932
|
if (action === void 0) throw new invariants.ContractViolationError(`Action "${actionName}" not declared on activity "${activityName}"`);
|
|
7332
7933
|
if (action.when !== void 0) throw new ActionDisabledError({
|
|
7333
7934
|
activity: activityName,
|
|
@@ -7338,7 +7939,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
|
|
|
7338
7939
|
}
|
|
7339
7940
|
});
|
|
7340
7941
|
if (action.filter !== void 0) {
|
|
7341
|
-
const
|
|
7942
|
+
const vars = await callerBoundVarsForCall({
|
|
7943
|
+
client: ctx.client,
|
|
7342
7944
|
instance: ctx.instance,
|
|
7343
7945
|
options: options
|
|
7344
7946
|
});
|
|
@@ -7350,10 +7952,8 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
|
|
|
7350
7952
|
...actor !== void 0 ? {
|
|
7351
7953
|
actor: actor
|
|
7352
7954
|
} : {},
|
|
7353
|
-
...
|
|
7354
|
-
vars:
|
|
7355
|
-
can: can
|
|
7356
|
-
}
|
|
7955
|
+
...vars !== void 0 ? {
|
|
7956
|
+
vars: vars
|
|
7357
7957
|
} : {}
|
|
7358
7958
|
}
|
|
7359
7959
|
})) throw new ActionDisabledError({
|
|
@@ -8614,334 +9214,91 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
|
|
|
8614
9214
|
mutation: mutation,
|
|
8615
9215
|
record: requestRecord,
|
|
8616
9216
|
now: ctx.now
|
|
8617
|
-
}), renewClaimLease({
|
|
8618
|
-
mutation: mutation,
|
|
8619
|
-
effectKey: effectKey,
|
|
8620
|
-
now: ctx.now,
|
|
8621
|
-
leaseMs: leaseMs
|
|
8622
|
-
}), await runOps({
|
|
8623
|
-
ops: validatedOps,
|
|
8624
|
-
mutation: mutation,
|
|
8625
|
-
stage: ctx.instance.currentStage,
|
|
8626
|
-
origin: {
|
|
8627
|
-
effect: pending.name
|
|
8628
|
-
},
|
|
8629
|
-
params: pending.params,
|
|
8630
|
-
actor: ctx.actor,
|
|
8631
|
-
self: invariants.selfGdr(ctx.instance),
|
|
8632
|
-
now: ctx.now,
|
|
8633
|
-
snapshot: ctx.snapshot,
|
|
8634
|
-
refSurface: ctx.refSurface
|
|
8635
|
-
}), await persistThenMaybeRefresh({
|
|
8636
|
-
ctx: ctx,
|
|
8637
|
-
mutation: mutation,
|
|
8638
|
-
stageName: ctx.instance.currentStage,
|
|
8639
|
-
didChangeState: !0
|
|
8640
|
-
}), {
|
|
8641
|
-
effectKey: effectKey,
|
|
8642
|
-
effect: pending.name
|
|
8643
|
-
};
|
|
8644
|
-
}
|
|
8645
|
-
|
|
8646
|
-
const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
|
|
8647
|
-
|
|
8648
|
-
function isResetActivityTarget(value) {
|
|
8649
|
-
return RESET_ACTIVITY_TARGETS.includes(value);
|
|
8650
|
-
}
|
|
8651
|
-
|
|
8652
|
-
async function resetActivity(args) {
|
|
8653
|
-
const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
|
|
8654
|
-
client: client,
|
|
8655
|
-
instanceId: instanceId,
|
|
8656
|
-
options: options
|
|
8657
|
-
});
|
|
8658
|
-
return commitResetActivity({
|
|
8659
|
-
ctx: ctx,
|
|
8660
|
-
activity: activity,
|
|
8661
|
-
to: to,
|
|
8662
|
-
requestRecord: requestRecord,
|
|
8663
|
-
actor: options?.actor
|
|
8664
|
-
});
|
|
8665
|
-
}
|
|
8666
|
-
|
|
8667
|
-
async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
|
|
8668
|
-
if (assertRequestUnprocessed({
|
|
8669
|
-
instance: ctx.instance,
|
|
8670
|
-
record: requestRecord,
|
|
8671
|
-
now: ctx.now
|
|
8672
|
-
}), isTerminal(ctx)) return {
|
|
8673
|
-
fired: !1
|
|
8674
|
-
};
|
|
8675
|
-
const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
|
|
8676
|
-
if (openStage2 === void 0 || entry === void 0) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
|
|
8677
|
-
const from = entry.status;
|
|
8678
|
-
if (from === to) return {
|
|
8679
|
-
fired: !1
|
|
8680
|
-
};
|
|
8681
|
-
if (!invariants.isTerminalActivityStatus(from)) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is "${from}", not a terminal status — a reset only recovers a resolved (typically failed) activity. Use setStage to force past a live stage.`);
|
|
8682
|
-
return recordProcessedRequest({
|
|
8683
|
-
mutation: mutation,
|
|
8684
|
-
record: requestRecord,
|
|
8685
|
-
now: ctx.now
|
|
8686
|
-
}), applyActivityStatusChange({
|
|
8687
|
-
entry: entry,
|
|
8688
|
-
history: mutation.history,
|
|
8689
|
-
stage: openStage2.name,
|
|
8690
|
-
to: to,
|
|
8691
|
-
at: ctx.now,
|
|
8692
|
-
...actor !== void 0 ? {
|
|
8693
|
-
actor: actor
|
|
8694
|
-
} : {}
|
|
8695
|
-
}), await persist(ctx, mutation), {
|
|
8696
|
-
fired: !0,
|
|
8697
|
-
stage: openStage2.name,
|
|
8698
|
-
activity: activity,
|
|
8699
|
-
from: from,
|
|
8700
|
-
to: to
|
|
8701
|
-
};
|
|
8702
|
-
}
|
|
8703
|
-
|
|
8704
|
-
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
|
|
8705
|
-
|
|
8706
|
-
async function resolveAccess(taggedClient, args = {}) {
|
|
8707
|
-
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
8708
|
-
if (requestFn === void 0) throw new invariants.ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({ uri: '/users/me' })`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
|
|
8709
|
-
const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
|
|
8710
|
-
client: client,
|
|
8711
|
-
requestFn: requestFn,
|
|
8712
|
-
resourcePath: args.grantsFromPath
|
|
8713
|
-
}) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
8714
|
-
if (identity === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
|
|
8715
|
-
return {
|
|
8716
|
-
actor: identity.actor,
|
|
8717
|
-
...identity.localPrincipalId !== void 0 ? {
|
|
8718
|
-
localPrincipalId: identity.localPrincipalId
|
|
8719
|
-
} : {},
|
|
8720
|
-
...grants !== void 0 ? {
|
|
8721
|
-
grants: grants
|
|
8722
|
-
} : {}
|
|
8723
|
-
};
|
|
8724
|
-
}
|
|
8725
|
-
|
|
8726
|
-
function cachedActor(client, requestFn) {
|
|
8727
|
-
const cached = actorCache.get(client);
|
|
8728
|
-
if (cached !== void 0) return cached;
|
|
8729
|
-
const pending = fetchActor(client, requestFn).catch(err => {
|
|
8730
|
-
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
8731
|
-
});
|
|
8732
|
-
return actorCache.set(client, pending), pending;
|
|
8733
|
-
}
|
|
8734
|
-
|
|
8735
|
-
function grantsForClientPath(taggedClient, resourcePath) {
|
|
8736
|
-
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
8737
|
-
return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
|
|
8738
|
-
client: client,
|
|
8739
|
-
requestFn: requestFn,
|
|
8740
|
-
resourcePath: resourcePath
|
|
8741
|
-
});
|
|
8742
|
-
}
|
|
8743
|
-
|
|
8744
|
-
function lazyRequest(client) {
|
|
8745
|
-
return client.request === void 0 ? void 0 : opts => client.request(opts);
|
|
8746
|
-
}
|
|
8747
|
-
|
|
8748
|
-
function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
|
|
8749
|
-
let byPath = grantsCache.get(client);
|
|
8750
|
-
byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
|
|
8751
|
-
let cached = byPath.get(resourcePath);
|
|
8752
|
-
return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
|
|
8753
|
-
byPath.set(resourcePath, cached)), cached;
|
|
8754
|
-
}
|
|
8755
|
-
|
|
8756
|
-
async function fetchActor(client, requestFn) {
|
|
8757
|
-
const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalHostId = usableId(globalUser.user), carriedId = invariants.firstCarriedGlobalId([ globalHostId, resourceId ]), sessionId = carriedId ?? globalHostId ?? resourceId;
|
|
8758
|
-
if (sessionId === void 0) return;
|
|
8759
|
-
const bridge = carriedId === void 0 ? await bridgeProjectPrincipal({
|
|
8760
|
-
client: client,
|
|
8761
|
-
sessionId: sessionId,
|
|
8762
|
-
resourceId: resourceId
|
|
8763
|
-
}) : NO_BRIDGE, id = bridge.status === "resolved" ? bridge.globalId : sessionId;
|
|
8764
|
-
refuseProjectScopedActor({
|
|
8765
|
-
id: id,
|
|
8766
|
-
globalUser: globalUser,
|
|
8767
|
-
globalHostId: globalHostId,
|
|
8768
|
-
bridgeFailure: bridge.status === "unavailable" ? bridge : void 0
|
|
8769
|
-
});
|
|
8770
|
-
const roleNames = roleNamesFor(resourceUser, globalUser);
|
|
8771
|
-
return {
|
|
8772
|
-
actor: {
|
|
8773
|
-
kind: "person",
|
|
8774
|
-
id: id,
|
|
8775
|
-
...roleNames.length > 0 ? {
|
|
8776
|
-
roles: roleNames
|
|
8777
|
-
} : {}
|
|
9217
|
+
}), renewClaimLease({
|
|
9218
|
+
mutation: mutation,
|
|
9219
|
+
effectKey: effectKey,
|
|
9220
|
+
now: ctx.now,
|
|
9221
|
+
leaseMs: leaseMs
|
|
9222
|
+
}), await runOps({
|
|
9223
|
+
ops: validatedOps,
|
|
9224
|
+
mutation: mutation,
|
|
9225
|
+
stage: ctx.instance.currentStage,
|
|
9226
|
+
origin: {
|
|
9227
|
+
effect: pending.name
|
|
8778
9228
|
},
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
9229
|
+
params: pending.params,
|
|
9230
|
+
actor: ctx.actor,
|
|
9231
|
+
self: invariants.selfGdr(ctx.instance),
|
|
9232
|
+
now: ctx.now,
|
|
9233
|
+
snapshot: ctx.snapshot,
|
|
9234
|
+
refSurface: ctx.refSurface
|
|
9235
|
+
}), await persistThenMaybeRefresh({
|
|
9236
|
+
ctx: ctx,
|
|
9237
|
+
mutation: mutation,
|
|
9238
|
+
stageName: ctx.instance.currentStage,
|
|
9239
|
+
didChangeState: !0
|
|
9240
|
+
}), {
|
|
9241
|
+
effectKey: effectKey,
|
|
9242
|
+
effect: pending.name
|
|
8782
9243
|
};
|
|
8783
9244
|
}
|
|
8784
9245
|
|
|
8785
|
-
|
|
8786
|
-
return (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
8787
|
-
}
|
|
8788
|
-
|
|
8789
|
-
const NO_BRIDGE = {
|
|
8790
|
-
status: "not-applicable"
|
|
8791
|
-
};
|
|
9246
|
+
const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
|
|
8792
9247
|
|
|
8793
|
-
function
|
|
8794
|
-
return
|
|
9248
|
+
function isResetActivityTarget(value) {
|
|
9249
|
+
return RESET_ACTIVITY_TARGETS.includes(value);
|
|
8795
9250
|
}
|
|
8796
9251
|
|
|
8797
|
-
async function
|
|
8798
|
-
const {client: client,
|
|
8799
|
-
return invariants.classifyPrincipalId(sessionId).namespace !== "project" ? NO_BRIDGE : resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project" ? {
|
|
8800
|
-
status: "unavailable",
|
|
8801
|
-
reason: "no project-scoped principal from the resource host to address the directory with"
|
|
8802
|
-
} : directoryGlobalId({
|
|
9252
|
+
async function resetActivity(args) {
|
|
9253
|
+
const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
|
|
8803
9254
|
client: client,
|
|
8804
|
-
|
|
9255
|
+
instanceId: instanceId,
|
|
9256
|
+
options: options
|
|
8805
9257
|
});
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
reason: "the client reports no projectId, so its user directory has no address"
|
|
8813
|
-
};
|
|
8814
|
-
const lookup = await clientProjectUserDirectory(withRequestTag(client, REQUEST_TAG.accessResolveActor), projectId).findById(principalId);
|
|
8815
|
-
if (lookup.status !== "resolved") return {
|
|
8816
|
-
status: "unavailable",
|
|
8817
|
-
reason: `project "${projectId}"'s user directory reported the principal ${lookup.status}`,
|
|
8818
|
-
...lookup.status === "inaccessible" && lookup.cause !== void 0 ? {
|
|
8819
|
-
cause: lookup.cause
|
|
8820
|
-
} : {}
|
|
8821
|
-
};
|
|
8822
|
-
const globalId = invariants.directoryBridgeId(lookup.user.sanityUserId);
|
|
8823
|
-
return globalId === void 0 ? {
|
|
8824
|
-
status: "unavailable",
|
|
8825
|
-
reason: `project "${projectId}"'s user directory row for the principal carries no account-global sanityUserId`
|
|
8826
|
-
} : {
|
|
8827
|
-
status: "resolved",
|
|
8828
|
-
globalId: globalId
|
|
8829
|
-
};
|
|
8830
|
-
}
|
|
8831
|
-
|
|
8832
|
-
function refuseProjectScopedActor(args) {
|
|
8833
|
-
const {id: id, globalUser: globalUser, globalHostId: globalHostId, bridgeFailure: bridgeFailure} = args;
|
|
8834
|
-
if (invariants.classifyPrincipalId(id).namespace !== "project") return;
|
|
8835
|
-
const routes = [ `The account-global record: ${globalRouteReason(globalUser, globalHostId)}.` ];
|
|
8836
|
-
bridgeFailure !== void 0 && routes.push(`The project user directory: ${bridgeFailure.reason}.`);
|
|
8837
|
-
const cause = bridgeFailure?.cause ?? ("cause" in globalUser ? globalUser.cause : void 0);
|
|
8838
|
-
throw new Error(`workflow: the caller's identity resolves to the project-scoped principal "${id}" and its account-global id could not be resolved. ${routes.join(" ")} The engine speaks account-global user ids only and never acts as a project-scoped principal.`, cause === void 0 ? void 0 : {
|
|
8839
|
-
cause: cause
|
|
9258
|
+
return commitResetActivity({
|
|
9259
|
+
ctx: ctx,
|
|
9260
|
+
activity: activity,
|
|
9261
|
+
to: to,
|
|
9262
|
+
requestRecord: requestRecord,
|
|
9263
|
+
actor: options?.actor
|
|
8840
9264
|
});
|
|
8841
9265
|
}
|
|
8842
9266
|
|
|
8843
|
-
function
|
|
8844
|
-
if (
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
uri: "/users/me",
|
|
8851
|
-
tag: REQUEST_TAG.accessResolveActor
|
|
8852
|
-
});
|
|
8853
|
-
} catch (err) {
|
|
8854
|
-
throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({ uri: '/users/me' })\`. Check the token/connectivity.`, {
|
|
8855
|
-
cause: err
|
|
8856
|
-
});
|
|
8857
|
-
}
|
|
8858
|
-
}
|
|
8859
|
-
|
|
8860
|
-
async function fetchGlobalUser(client) {
|
|
8861
|
-
if (typeof client.withConfig != "function") return {
|
|
8862
|
-
user: void 0,
|
|
8863
|
-
reason: "the client cannot reach the global API host (no withConfig)"
|
|
8864
|
-
};
|
|
8865
|
-
let globalRequest, globalClient;
|
|
8866
|
-
const hostResolution = resolveGlobalApiHost(client);
|
|
8867
|
-
try {
|
|
8868
|
-
globalClient = client.withConfig({
|
|
8869
|
-
useProjectHostname: !1,
|
|
8870
|
-
...hostResolution.apiHost === void 0 ? {} : {
|
|
8871
|
-
apiHost: hostResolution.apiHost
|
|
8872
|
-
}
|
|
8873
|
-
}), globalRequest = lazyRequest(globalClient);
|
|
8874
|
-
} catch (err) {
|
|
8875
|
-
return {
|
|
8876
|
-
user: void 0,
|
|
8877
|
-
reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
|
|
8878
|
-
cause: err
|
|
8879
|
-
};
|
|
8880
|
-
}
|
|
8881
|
-
if (globalRequest === void 0) return {
|
|
8882
|
-
user: void 0,
|
|
8883
|
-
reason: "the global-host sibling client cannot issue requests"
|
|
8884
|
-
};
|
|
8885
|
-
try {
|
|
8886
|
-
const user = await globalRequest({
|
|
8887
|
-
uri: "/users/me",
|
|
8888
|
-
tag: REQUEST_TAG.accessResolveActor
|
|
8889
|
-
}), id = usableId(user);
|
|
8890
|
-
return hostResolution.requireGlobalPrincipal && id !== void 0 && invariants.classifyPrincipalId(id).namespace === "project" ? {
|
|
8891
|
-
user: void 0,
|
|
8892
|
-
reason: `global-host /users/me returned project-scoped principal "${id}"; the sibling client is still bound to a project API host`
|
|
8893
|
-
} : {
|
|
8894
|
-
user: user
|
|
8895
|
-
};
|
|
8896
|
-
} catch (err) {
|
|
8897
|
-
return {
|
|
8898
|
-
user: void 0,
|
|
8899
|
-
reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
|
|
8900
|
-
cause: err
|
|
8901
|
-
};
|
|
8902
|
-
}
|
|
8903
|
-
}
|
|
8904
|
-
|
|
8905
|
-
function resolveGlobalApiHost(client) {
|
|
8906
|
-
if (typeof client.config != "function") return {
|
|
8907
|
-
requireGlobalPrincipal: !1
|
|
9267
|
+
async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
|
|
9268
|
+
if (assertRequestUnprocessed({
|
|
9269
|
+
instance: ctx.instance,
|
|
9270
|
+
record: requestRecord,
|
|
9271
|
+
now: ctx.now
|
|
9272
|
+
}), isTerminal(ctx)) return {
|
|
9273
|
+
fired: !1
|
|
8908
9274
|
};
|
|
8909
|
-
const
|
|
8910
|
-
if (
|
|
8911
|
-
|
|
9275
|
+
const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
|
|
9276
|
+
if (openStage2 === void 0 || entry === void 0) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
|
|
9277
|
+
const from = entry.status;
|
|
9278
|
+
if (from === to) return {
|
|
9279
|
+
fired: !1
|
|
8912
9280
|
};
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
9281
|
+
if (!invariants.isTerminalActivityStatus(from)) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is "${from}", not a terminal status — a reset only recovers a resolved (typically failed) activity. Use setStage to force past a live stage.`);
|
|
9282
|
+
return recordProcessedRequest({
|
|
9283
|
+
mutation: mutation,
|
|
9284
|
+
record: requestRecord,
|
|
9285
|
+
now: ctx.now
|
|
9286
|
+
}), applyActivityStatusChange({
|
|
9287
|
+
entry: entry,
|
|
9288
|
+
history: mutation.history,
|
|
9289
|
+
stage: openStage2.name,
|
|
9290
|
+
to: to,
|
|
9291
|
+
at: ctx.now,
|
|
9292
|
+
...actor !== void 0 ? {
|
|
9293
|
+
actor: actor
|
|
9294
|
+
} : {}
|
|
9295
|
+
}), await persist(ctx, mutation), {
|
|
9296
|
+
fired: !0,
|
|
9297
|
+
stage: openStage2.name,
|
|
9298
|
+
activity: activity,
|
|
9299
|
+
from: from,
|
|
9300
|
+
to: to
|
|
8923
9301
|
};
|
|
8924
|
-
const match = /^[^.]+\.api\.sanity\.(io|work)$/.exec(parsed.hostname);
|
|
8925
|
-
return match === null ? {
|
|
8926
|
-
requireGlobalPrincipal: !0
|
|
8927
|
-
} : (parsed.hostname = `api.sanity.${match[1]}`, {
|
|
8928
|
-
apiHost: parsed.origin,
|
|
8929
|
-
requireGlobalPrincipal: !0
|
|
8930
|
-
});
|
|
8931
|
-
}
|
|
8932
|
-
|
|
8933
|
-
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
8934
|
-
try {
|
|
8935
|
-
return await fetchGrants({
|
|
8936
|
-
client: {
|
|
8937
|
-
request: requestFn
|
|
8938
|
-
},
|
|
8939
|
-
resourcePath: resourcePath
|
|
8940
|
-
});
|
|
8941
|
-
} catch (err) {
|
|
8942
|
-
console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
|
|
8943
|
-
return;
|
|
8944
|
-
}
|
|
8945
9302
|
}
|
|
8946
9303
|
|
|
8947
9304
|
const REPLAY_SURFACE = {
|
|
@@ -9125,7 +9482,7 @@ async function resourceActorId(client) {
|
|
|
9125
9482
|
async function evaluateInstance(args) {
|
|
9126
9483
|
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
9127
9484
|
invariants.validateTag(tag);
|
|
9128
|
-
const [access, instance] = await Promise.all([ resolveAccess(client, {
|
|
9485
|
+
const [access, instance, attributes] = await Promise.all([ resolveAccess(client, {
|
|
9129
9486
|
...args.grantsFromPath !== void 0 ? {
|
|
9130
9487
|
grantsFromPath: args.grantsFromPath
|
|
9131
9488
|
} : {}
|
|
@@ -9133,7 +9490,7 @@ async function evaluateInstance(args) {
|
|
|
9133
9490
|
client: client,
|
|
9134
9491
|
instanceId: instanceId,
|
|
9135
9492
|
tag: tag
|
|
9136
|
-
}) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
9493
|
+
}), resolveUserAttributes(client) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
9137
9494
|
client: client,
|
|
9138
9495
|
workflowResource: workflowResource,
|
|
9139
9496
|
resourceClients: resourceClients
|
|
@@ -9158,6 +9515,9 @@ async function evaluateInstance(args) {
|
|
|
9158
9515
|
} : {},
|
|
9159
9516
|
...grants !== void 0 ? {
|
|
9160
9517
|
grants: grants
|
|
9518
|
+
} : {},
|
|
9519
|
+
...attributes !== void 0 ? {
|
|
9520
|
+
attributes: attributes
|
|
9161
9521
|
} : {}
|
|
9162
9522
|
});
|
|
9163
9523
|
}
|
|
@@ -9172,6 +9532,33 @@ function memoizedByName(render) {
|
|
|
9172
9532
|
};
|
|
9173
9533
|
}
|
|
9174
9534
|
|
|
9535
|
+
async function callerBoundProjectionScopes(args) {
|
|
9536
|
+
const can = await advisoryCan({
|
|
9537
|
+
instance: args.instance,
|
|
9538
|
+
identity: args.identity,
|
|
9539
|
+
grants: args.grants
|
|
9540
|
+
}), vars = callerBoundVars({
|
|
9541
|
+
...can !== void 0 ? {
|
|
9542
|
+
can: can
|
|
9543
|
+
} : {},
|
|
9544
|
+
...args.attributes !== void 0 ? {
|
|
9545
|
+
attributes: args.attributes
|
|
9546
|
+
} : {}
|
|
9547
|
+
}), opts = {
|
|
9548
|
+
actor: args.actor,
|
|
9549
|
+
...vars !== void 0 ? {
|
|
9550
|
+
vars: vars
|
|
9551
|
+
} : {}
|
|
9552
|
+
};
|
|
9553
|
+
return {
|
|
9554
|
+
scope: await renderConditionScope(args.scopeSource, opts),
|
|
9555
|
+
scopeForActivity: memoizedByName(activityName => renderConditionScope(args.scopeSource, {
|
|
9556
|
+
activityName: activityName,
|
|
9557
|
+
...opts
|
|
9558
|
+
}))
|
|
9559
|
+
};
|
|
9560
|
+
}
|
|
9561
|
+
|
|
9175
9562
|
function currentStageOf(instance, definition) {
|
|
9176
9563
|
try {
|
|
9177
9564
|
return findStage(definition, instance.currentStage);
|
|
@@ -9197,7 +9584,7 @@ async function explainSite(args) {
|
|
|
9197
9584
|
}
|
|
9198
9585
|
|
|
9199
9586
|
async function evaluateFromSnapshot(args) {
|
|
9200
|
-
const {instance: instance, definition: definition, actor: actor, grants: grants, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), fireConsequence = (activity, action) => whatIfFireAction({
|
|
9587
|
+
const {instance: instance, definition: definition, actor: actor, grants: grants, attributes: attributes, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), fireConsequence = (activity, action) => whatIfFireAction({
|
|
9201
9588
|
instance: instance,
|
|
9202
9589
|
definition: definition,
|
|
9203
9590
|
snapshot: snapshot,
|
|
@@ -9214,22 +9601,14 @@ async function evaluateFromSnapshot(args) {
|
|
|
9214
9601
|
}, anchorIdentity = invariants.lakePrincipalId({
|
|
9215
9602
|
actor: actor,
|
|
9216
9603
|
localPrincipalId: args.localPrincipalId
|
|
9217
|
-
}),
|
|
9218
|
-
|
|
9219
|
-
identity: anchorIdentity,
|
|
9220
|
-
grants: grants
|
|
9221
|
-
}), scope = await renderConditionScope(scopeSource, {
|
|
9222
|
-
actor: actor,
|
|
9223
|
-
vars: {
|
|
9224
|
-
can: can
|
|
9225
|
-
}
|
|
9226
|
-
}), scopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
|
|
9227
|
-
activityName: activityName,
|
|
9604
|
+
}), {scope: scope, scopeForActivity: scopeForActivity} = await callerBoundProjectionScopes({
|
|
9605
|
+
scopeSource: scopeSource,
|
|
9228
9606
|
actor: actor,
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9607
|
+
instance: instance,
|
|
9608
|
+
grants: grants,
|
|
9609
|
+
attributes: attributes,
|
|
9610
|
+
identity: anchorIdentity
|
|
9611
|
+
}), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
|
|
9233
9612
|
activityName: activityName
|
|
9234
9613
|
})), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
|
|
9235
9614
|
instance: instance,
|
|
@@ -9278,6 +9657,7 @@ async function evaluateFromSnapshot(args) {
|
|
|
9278
9657
|
}
|
|
9279
9658
|
const currentStage = {
|
|
9280
9659
|
stage: stage,
|
|
9660
|
+
...semanticsOf(stage),
|
|
9281
9661
|
activities: activityEvaluations,
|
|
9282
9662
|
transitions: transitionEvaluations,
|
|
9283
9663
|
autonomy: stageAutonomy2
|
|
@@ -9294,6 +9674,7 @@ async function evaluateFromSnapshot(args) {
|
|
|
9294
9674
|
return {
|
|
9295
9675
|
instance: instance,
|
|
9296
9676
|
definition: definition,
|
|
9677
|
+
...semanticsOf(definition),
|
|
9297
9678
|
actor: actor,
|
|
9298
9679
|
currentStage: currentStage,
|
|
9299
9680
|
pendingOnYou: pendingOnYou,
|
|
@@ -9449,6 +9830,7 @@ async function evaluateActivity(args) {
|
|
|
9449
9830
|
}));
|
|
9450
9831
|
return {
|
|
9451
9832
|
activity: activity,
|
|
9833
|
+
...semanticsOf(activity),
|
|
9452
9834
|
status: status,
|
|
9453
9835
|
kind: invariants.deriveActivityKind(activity),
|
|
9454
9836
|
classification: invariants.deriveExecutorClassification(activity),
|
|
@@ -9619,9 +10001,13 @@ function fireableActionVerdict({args: args, insights: insights}) {
|
|
|
9619
10001
|
function actionEvaluationIdentity(action) {
|
|
9620
10002
|
return {
|
|
9621
10003
|
action: action,
|
|
9622
|
-
...action
|
|
9623
|
-
|
|
9624
|
-
|
|
10004
|
+
...semanticsOf(action)
|
|
10005
|
+
};
|
|
10006
|
+
}
|
|
10007
|
+
|
|
10008
|
+
function semanticsOf(node) {
|
|
10009
|
+
return node.semantics === void 0 ? {} : {
|
|
10010
|
+
semantics: node.semantics
|
|
9625
10011
|
};
|
|
9626
10012
|
}
|
|
9627
10013
|
|
|
@@ -10100,7 +10486,8 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
|
|
|
10100
10486
|
}
|
|
10101
10487
|
|
|
10102
10488
|
async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
|
|
10103
|
-
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site),
|
|
10489
|
+
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), vars = await callerBoundVarsForCall({
|
|
10490
|
+
client: ctx.client,
|
|
10104
10491
|
instance: ctx.instance,
|
|
10105
10492
|
options: options
|
|
10106
10493
|
}), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
|
|
@@ -10113,10 +10500,8 @@ async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
|
|
|
10113
10500
|
...actor !== void 0 ? {
|
|
10114
10501
|
actor: actor
|
|
10115
10502
|
} : {},
|
|
10116
|
-
...
|
|
10117
|
-
vars:
|
|
10118
|
-
can: can
|
|
10119
|
-
}
|
|
10503
|
+
...vars !== void 0 ? {
|
|
10504
|
+
vars: vars
|
|
10120
10505
|
} : {}
|
|
10121
10506
|
}
|
|
10122
10507
|
}) : site.effective === !0, reason = editDisabledReason({
|
|
@@ -10606,6 +10991,9 @@ function buildEngineCallOptions(args) {
|
|
|
10606
10991
|
...args.grants !== void 0 ? {
|
|
10607
10992
|
grants: args.grants
|
|
10608
10993
|
} : {},
|
|
10994
|
+
...args.attributes !== void 0 ? {
|
|
10995
|
+
attributes: args.attributes
|
|
10996
|
+
} : {},
|
|
10609
10997
|
...args.clock !== void 0 ? {
|
|
10610
10998
|
clock: args.clock
|
|
10611
10999
|
} : {},
|
|
@@ -12364,7 +12752,7 @@ function createInstanceSession(args) {
|
|
|
12364
12752
|
refSurface: evalScope.refSurface
|
|
12365
12753
|
});
|
|
12366
12754
|
}, evaluateWith = async ({held: held, guards: guards, self: self}) => {
|
|
12367
|
-
const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
12755
|
+
const [{actor: actor, localPrincipalId: localPrincipalId, grants: grants}, attributes] = await Promise.all([ access(), resolveUserAttributes(client) ]), resourceGrants = await subjectResourceGrants({
|
|
12368
12756
|
clientForGdr: evalScope.clientForGdr,
|
|
12369
12757
|
instance: instance
|
|
12370
12758
|
}), normalizedSelf = await normalizeInstanceIdentities({
|
|
@@ -12386,6 +12774,9 @@ function createInstanceSession(args) {
|
|
|
12386
12774
|
} : {},
|
|
12387
12775
|
...grants !== void 0 ? {
|
|
12388
12776
|
grants: grants
|
|
12777
|
+
} : {},
|
|
12778
|
+
...attributes !== void 0 ? {
|
|
12779
|
+
attributes: attributes
|
|
12389
12780
|
} : {}
|
|
12390
12781
|
});
|
|
12391
12782
|
}, settleAfterApply = async ({actor: actor, held: held, ranOps: ranOps, scope: scope}) => {
|
|
@@ -13081,7 +13472,7 @@ const HISTORY_DISPLAY = {
|
|
|
13081
13472
|
},
|
|
13082
13473
|
opApplied: {
|
|
13083
13474
|
title: "Op applied",
|
|
13084
|
-
description: "An
|
|
13475
|
+
description: "An action, direct edit, or effect completion executed an operation and recorded its audit payload."
|
|
13085
13476
|
},
|
|
13086
13477
|
fieldQueryDiscarded: {
|
|
13087
13478
|
title: "Query result discarded",
|
|
@@ -13186,6 +13577,10 @@ const HISTORY_DISPLAY = {
|
|
|
13186
13577
|
title: "Set field entry",
|
|
13187
13578
|
description: "Overwrite a field entry's value with a resolved value expression."
|
|
13188
13579
|
},
|
|
13580
|
+
"field.setIfMissing": {
|
|
13581
|
+
title: "Set field entry if missing",
|
|
13582
|
+
description: "Set a nullable field entry's value only when it is currently null or undefined; array, assignees, and doc.refs entries are always arrays and are not supported."
|
|
13583
|
+
},
|
|
13189
13584
|
"field.unset": {
|
|
13190
13585
|
title: "Unset field entry",
|
|
13191
13586
|
description: "Reset a field entry to its default (null for scalars, [] for array kinds)."
|
|
@@ -13194,6 +13589,14 @@ const HISTORY_DISPLAY = {
|
|
|
13194
13589
|
title: "Append to field entry",
|
|
13195
13590
|
description: "Push a resolved item onto an array-kind entry (array, assignees, doc.refs)."
|
|
13196
13591
|
},
|
|
13592
|
+
"field.inc": {
|
|
13593
|
+
title: "Increment field entry",
|
|
13594
|
+
description: "Add a resolved numeric delta, defaulting to 1, to a number entry that already holds a finite number."
|
|
13595
|
+
},
|
|
13596
|
+
"field.dec": {
|
|
13597
|
+
title: "Decrement field entry",
|
|
13598
|
+
description: "Subtract a resolved numeric delta, defaulting to 1, from a number entry that already holds a finite number."
|
|
13599
|
+
},
|
|
13197
13600
|
"field.updateWhere": {
|
|
13198
13601
|
title: "Update matching rows",
|
|
13199
13602
|
description: "Merge declared sub-fields into rows of an `array` entry that match the `where` condition (`array` only — `doc.refs`/`assignees` rows are engine-shaped)."
|
|
@@ -13319,6 +13722,8 @@ exports.CONDITION_VARS = invariants.CONDITION_VARS;
|
|
|
13319
13722
|
|
|
13320
13723
|
exports.ContractViolationError = invariants.ContractViolationError;
|
|
13321
13724
|
|
|
13725
|
+
exports.DECISION_SEMANTICS = invariants.DECISION_SEMANTICS;
|
|
13726
|
+
|
|
13322
13727
|
exports.DEFAULT_TRANSITION_WHEN = invariants.DEFAULT_TRANSITION_WHEN;
|
|
13323
13728
|
|
|
13324
13729
|
exports.DRIVER_KINDS = invariants.DRIVER_KINDS;
|
|
@@ -13345,6 +13750,8 @@ exports.PersistedDocShapeError = invariants.PersistedDocShapeError;
|
|
|
13345
13750
|
|
|
13346
13751
|
exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
|
|
13347
13752
|
|
|
13753
|
+
exports.SIGNAL_SEMANTICS = invariants.SIGNAL_SEMANTICS;
|
|
13754
|
+
|
|
13348
13755
|
exports.START_FILTER_VARS = invariants.START_FILTER_VARS;
|
|
13349
13756
|
|
|
13350
13757
|
exports.START_REQUIREMENT_VARS = invariants.START_REQUIREMENT_VARS;
|
|
@@ -13777,6 +14184,8 @@ exports.documentActionDenials = documentActionDenials;
|
|
|
13777
14184
|
|
|
13778
14185
|
exports.documentPrefilter = documentPrefilter;
|
|
13779
14186
|
|
|
14187
|
+
exports.documentStuckCause = documentStuckCause;
|
|
14188
|
+
|
|
13780
14189
|
exports.effectOutputsMap = effectOutputsMap;
|
|
13781
14190
|
|
|
13782
14191
|
exports.entryDocRefs = entryDocRefs;
|
|
@@ -13793,10 +14202,14 @@ exports.explainStartRequirement = explainStartRequirement;
|
|
|
13793
14202
|
|
|
13794
14203
|
exports.fieldTreeShape = fieldTreeShape;
|
|
13795
14204
|
|
|
14205
|
+
exports.findActivityNode = findActivityNode;
|
|
14206
|
+
|
|
13796
14207
|
exports.findCurrentActivityEntry = findCurrentActivityEntry;
|
|
13797
14208
|
|
|
13798
14209
|
exports.findOpenStageEntry = findOpenStageEntry;
|
|
13799
14210
|
|
|
14211
|
+
exports.findStageNode = findStageNode;
|
|
14212
|
+
|
|
13800
14213
|
exports.groupSitesOf = groupSitesOf;
|
|
13801
14214
|
|
|
13802
14215
|
exports.guardMatches = guardMatches;
|
|
@@ -13899,6 +14312,8 @@ exports.resolveClientActor = resolveClientActor;
|
|
|
13899
14312
|
|
|
13900
14313
|
exports.resolveFieldEntry = resolveFieldEntry$1;
|
|
13901
14314
|
|
|
14315
|
+
exports.resolveUserAttributes = resolveUserAttributes;
|
|
14316
|
+
|
|
13902
14317
|
exports.retractStageGuards = retractStageGuards;
|
|
13903
14318
|
|
|
13904
14319
|
exports.silentLogger = silentLogger;
|