@sanity/workflow-engine 0.20.0 → 0.22.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 +99 -0
- package/DATAMODEL.md +168 -0
- package/dist/_chunks-cjs/invariants.cjs +223 -82
- package/dist/_chunks-es/invariants.js +213 -78
- package/dist/define.d.cts +42 -23
- package/dist/define.d.ts +42 -23
- package/dist/index.cjs +1717 -864
- package/dist/index.d.cts +450 -176
- package/dist/index.d.ts +450 -176
- package/dist/index.js +1698 -863
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -279,6 +279,10 @@ const HIGH_FREQUENCY_SAMPLE_MS = 6e4, WorkflowDefinitionDeployed = defineWorkflo
|
|
|
279
279
|
name: "Editorial Workflows Stage Set",
|
|
280
280
|
version: 1,
|
|
281
281
|
description: "The set-stage admin override was invoked (changed: false = already at the target stage)"
|
|
282
|
+
}), WorkflowActivityReset = defineWorkflowEvent({
|
|
283
|
+
name: "Editorial Workflows Activity Reset",
|
|
284
|
+
version: 1,
|
|
285
|
+
description: "The reset-activity admin override was invoked (changed: false = already at the target status, or the instance was terminal)"
|
|
282
286
|
}), WorkflowDefinitionDeleted = defineWorkflowEvent({
|
|
283
287
|
name: "Editorial Workflows Definition Deleted",
|
|
284
288
|
version: 1,
|
|
@@ -859,7 +863,7 @@ function toGroqDescribeContext(ctx) {
|
|
|
859
863
|
};
|
|
860
864
|
}
|
|
861
865
|
|
|
862
|
-
const VAR_LABELS = new Map([ ...invariants.
|
|
866
|
+
const VAR_LABELS = new Map([ ...invariants.START_REQUIREMENT_VARS, ...invariants.CONDITION_VARS ].map(entry => [ entry.name, entry.label ]));
|
|
863
867
|
|
|
864
868
|
function renderWorkflowRead(read, ctx) {
|
|
865
869
|
if (read.variable === "fields" && typeof read.path[0] == "string") {
|
|
@@ -932,13 +936,6 @@ function clauseVarRequirement(requirement) {
|
|
|
932
936
|
params: {},
|
|
933
937
|
text: "no activity in this stage may have failed"
|
|
934
938
|
});
|
|
935
|
-
if (target.variable === invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR) return kind === "truthy" ? groqConditionDescribe.phrase("requirement.subject-has-in-flight-instance", {
|
|
936
|
-
params: {},
|
|
937
|
-
text: "the subject must already have an in-flight workflow"
|
|
938
|
-
}) : groqConditionDescribe.phrase("requirement.subject-has-no-in-flight-instance", {
|
|
939
|
-
params: {},
|
|
940
|
-
text: "the subject must not already have an in-flight workflow"
|
|
941
|
-
});
|
|
942
939
|
}
|
|
943
940
|
}
|
|
944
941
|
|
|
@@ -1434,14 +1431,14 @@ function activitySites(activity, stage) {
|
|
|
1434
1431
|
activity: activity.name
|
|
1435
1432
|
},
|
|
1436
1433
|
condition: activity.filter
|
|
1437
|
-
} ] : [], ...
|
|
1434
|
+
} ] : [], ...(activity.requirements ?? []).map(requirement => ({
|
|
1438
1435
|
stage: stage,
|
|
1439
1436
|
address: {
|
|
1440
1437
|
kind: "requirement",
|
|
1441
1438
|
activity: activity.name,
|
|
1442
|
-
requirement: requirement
|
|
1439
|
+
requirement: requirement.name
|
|
1443
1440
|
},
|
|
1444
|
-
condition:
|
|
1441
|
+
condition: requirement.query
|
|
1445
1442
|
})), ...(activity.actions ?? []).flatMap(action => [ ...action.filter !== void 0 ? [ {
|
|
1446
1443
|
stage: stage,
|
|
1447
1444
|
address: {
|
|
@@ -1509,13 +1506,7 @@ async function evaluateStartFilter(args) {
|
|
|
1509
1506
|
const {filter: filter, definition: definition, document: document, scope: scope} = args, parsed = parseStartFilter({
|
|
1510
1507
|
filter: filter,
|
|
1511
1508
|
definition: definition
|
|
1512
|
-
});
|
|
1513
|
-
assertFilterSubject({
|
|
1514
|
-
readsSubject: parsed.readsSubject,
|
|
1515
|
-
definition: definition,
|
|
1516
|
-
scope: scope
|
|
1517
|
-
});
|
|
1518
|
-
const dataset = await filterDataset(parsed.needsDataset, scope);
|
|
1509
|
+
}), dataset = await filterDataset(parsed.needsDataset, scope);
|
|
1519
1510
|
if (dataset === void 0) return !1;
|
|
1520
1511
|
try {
|
|
1521
1512
|
const result = await (await groqJs.evaluate(parsed.tree, {
|
|
@@ -1525,8 +1516,7 @@ async function evaluateStartFilter(args) {
|
|
|
1525
1516
|
dataset: dataset,
|
|
1526
1517
|
params: startContextParams({
|
|
1527
1518
|
definition: definition,
|
|
1528
|
-
scope: scope
|
|
1529
|
-
dataset: dataset
|
|
1519
|
+
scope: scope
|
|
1530
1520
|
})
|
|
1531
1521
|
})).get();
|
|
1532
1522
|
return invariants.isUnevaluable(result) ? !1 : !!result;
|
|
@@ -1542,11 +1532,9 @@ async function evaluateStartFilter(args) {
|
|
|
1542
1532
|
function parseStartFilter(args) {
|
|
1543
1533
|
const {filter: filter, definition: definition} = args;
|
|
1544
1534
|
try {
|
|
1545
|
-
const readsSubject = readsSubjectHasInFlightInstance(filter);
|
|
1546
1535
|
return {
|
|
1547
1536
|
tree: groqJs.parse(filter),
|
|
1548
|
-
needsDataset: groqConditionDescribe.analyzeCondition(filter).readsDataset
|
|
1549
|
-
readsSubject: readsSubject
|
|
1537
|
+
needsDataset: groqConditionDescribe.analyzeCondition(filter).readsDataset
|
|
1550
1538
|
};
|
|
1551
1539
|
} catch (err) {
|
|
1552
1540
|
rethrowNamingDefinition({
|
|
@@ -1557,70 +1545,81 @@ function parseStartFilter(args) {
|
|
|
1557
1545
|
}
|
|
1558
1546
|
}
|
|
1559
1547
|
|
|
1560
|
-
function assertFilterSubject(args) {
|
|
1561
|
-
if (!(!args.readsSubject || args.scope?.subject !== void 0)) throw new invariants.ContractViolationError(`start.filter on definition "${args.definition.name ?? "<unnamed>"}" reads $${invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the caller supplied no resource-qualified \`scope.subject\` — a loaded document alone cannot identify its project and dataset.`);
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
1548
|
async function filterDataset(needsDataset, scope) {
|
|
1565
1549
|
if (!needsDataset) return [];
|
|
1566
1550
|
if (scope?.fetchDataset !== void 0) return scope.fetchDataset();
|
|
1567
1551
|
}
|
|
1568
1552
|
|
|
1569
|
-
async function
|
|
1570
|
-
const {
|
|
1553
|
+
async function explainStartRequirement(args) {
|
|
1554
|
+
const {query: query, definition: definition, fields: fields, scope: scope} = args;
|
|
1571
1555
|
let needsDataset;
|
|
1572
1556
|
try {
|
|
1573
|
-
needsDataset = groqConditionDescribe.analyzeCondition(
|
|
1557
|
+
needsDataset = groqConditionDescribe.analyzeCondition(query).readsDataset;
|
|
1574
1558
|
} catch (err) {
|
|
1575
1559
|
rethrowNamingDefinition({
|
|
1576
1560
|
err: err,
|
|
1577
1561
|
definition: definition,
|
|
1578
|
-
key: "
|
|
1562
|
+
key: "requirement"
|
|
1579
1563
|
});
|
|
1580
1564
|
}
|
|
1581
1565
|
let dataset = [];
|
|
1582
1566
|
if (needsDataset) {
|
|
1583
|
-
if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`start
|
|
1567
|
+
if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`start requirement on definition "${definition.name ?? "<unnamed>"}" reads the dataset (\`*[...]\`), but the caller supplied no \`scope.fetchDataset\` — evaluating over an empty slice would let a count()-style rule pass vacuously. Supply the instance slice.`);
|
|
1584
1568
|
dataset = await scope.fetchDataset();
|
|
1585
1569
|
}
|
|
1586
1570
|
try {
|
|
1587
1571
|
return await groqConditionDescribe.explainCondition({
|
|
1588
|
-
condition:
|
|
1572
|
+
condition: query,
|
|
1589
1573
|
dataset: dataset,
|
|
1590
1574
|
params: startContextParams({
|
|
1591
1575
|
definition: definition,
|
|
1592
1576
|
scope: scope,
|
|
1593
|
-
fields: fields
|
|
1594
|
-
dataset: dataset
|
|
1577
|
+
fields: fields
|
|
1595
1578
|
})
|
|
1596
1579
|
});
|
|
1597
1580
|
} catch (err) {
|
|
1598
1581
|
rethrowNamingDefinition({
|
|
1599
1582
|
err: err,
|
|
1600
1583
|
definition: definition,
|
|
1601
|
-
key: "
|
|
1584
|
+
key: "requirement"
|
|
1602
1585
|
});
|
|
1603
1586
|
}
|
|
1604
1587
|
}
|
|
1605
1588
|
|
|
1606
|
-
function
|
|
1607
|
-
return [ ...invariants.conditionFieldReadNames(
|
|
1589
|
+
function unboundRequirementReads(query, fields) {
|
|
1590
|
+
return [ ...invariants.conditionFieldReadNames(query) ].filter(name => !Object.hasOwn(fields, name));
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function hasSingleSubjectRequirement(definition) {
|
|
1594
|
+
return definition.start?.requirements?.some(requirement => requirement.type === "singleSubject") ?? !1;
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
async function singleSubjectRequirementRefused(args) {
|
|
1598
|
+
const {definition: definition, fields: fields, scope: scope} = args, name = singleSubjectDefinitionName(definition), subject = (fields !== void 0 ? startSubject(definition, fields) : void 0) ?? scope?.subject;
|
|
1599
|
+
if (subject === void 0) return !1;
|
|
1600
|
+
if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`singleSubject requirement on definition "${name}" scans the tag's instance slice, but the caller supplied no \`scope.fetchDataset\` — evaluating over an empty slice would let the rule pass vacuously. Supply the projected start slice.`);
|
|
1601
|
+
const dataset = await scope.fetchDataset();
|
|
1602
|
+
return sliceHasInFlightSubject({
|
|
1603
|
+
dataset: dataset,
|
|
1604
|
+
subject: subject,
|
|
1605
|
+
definition: name
|
|
1606
|
+
});
|
|
1608
1607
|
}
|
|
1609
1608
|
|
|
1610
|
-
function
|
|
1611
|
-
const
|
|
1612
|
-
|
|
1613
|
-
|
|
1609
|
+
function singleSubjectDefinitionName(definition) {
|
|
1610
|
+
const label = definition.name ?? "<unnamed>";
|
|
1611
|
+
if (definition.start?.requirements?.find(requirement => requirement.type === "singleSubject") === void 0) throw new invariants.ContractViolationError(`singleSubjectRequirementRefused called for definition "${label}", which declares no \`singleSubject\` requirement — evaluate only what the definition declares.`);
|
|
1612
|
+
if (definition.name === void 0) throw new invariants.ContractViolationError("singleSubjectRequirementRefused needs the definition `name` — the rule scopes its in-flight scan to instances of the definition, which a nameless source cannot identify.");
|
|
1613
|
+
return definition.name;
|
|
1614
1614
|
}
|
|
1615
1615
|
|
|
1616
1616
|
function rethrowNamingDefinition({err: err, definition: definition, key: key}) {
|
|
1617
|
-
invariants.rethrowWithContext(err,
|
|
1617
|
+
invariants.rethrowWithContext(err, `${key === "filter" ? "start.filter" : "start requirement"} on definition "${definition.name ?? "<unnamed>"}" failed to evaluate (check the predicate and its evaluation inputs)`);
|
|
1618
1618
|
}
|
|
1619
1619
|
|
|
1620
|
-
function startContextParams({definition: definition, scope: scope, fields: fields
|
|
1621
|
-
const
|
|
1622
|
-
return fields !== void 0 && (params.fields = fields),
|
|
1623
|
-
params;
|
|
1620
|
+
function startContextParams({definition: definition, scope: scope, fields: fields}) {
|
|
1621
|
+
const params = baseStartParams(definition, scope);
|
|
1622
|
+
return fields !== void 0 && (params.fields = fields), params;
|
|
1624
1623
|
}
|
|
1625
1624
|
|
|
1626
1625
|
function baseStartParams(definition, scope) {
|
|
@@ -1637,10 +1636,6 @@ function baseStartParams(definition, scope) {
|
|
|
1637
1636
|
};
|
|
1638
1637
|
}
|
|
1639
1638
|
|
|
1640
|
-
function readsSubjectHasInFlightInstance(groq) {
|
|
1641
|
-
return invariants.conditionParameterNames(groq).has(invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR);
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
1639
|
function startSubject(definition, fields) {
|
|
1645
1640
|
const subjectEntry = (definition.fields ?? []).find(invariants.isSubjectEntry);
|
|
1646
1641
|
if (subjectEntry === void 0) return;
|
|
@@ -1648,15 +1643,12 @@ function startSubject(definition, fields) {
|
|
|
1648
1643
|
return invariants.isGdr(value) ? value.id : void 0;
|
|
1649
1644
|
}
|
|
1650
1645
|
|
|
1651
|
-
function
|
|
1646
|
+
function sliceHasInFlightSubject(args) {
|
|
1647
|
+
const {dataset: dataset, subject: subject, definition: definition} = args;
|
|
1652
1648
|
return dataset.some(row => {
|
|
1653
1649
|
if (typeof row != "object" || row === null) return !1;
|
|
1654
1650
|
const instance = row;
|
|
1655
|
-
return instance.
|
|
1656
|
-
if (typeof entry != "object" || entry === null) return !1;
|
|
1657
|
-
const field = entry;
|
|
1658
|
-
return field._type === "subject" && invariants.isGdr(field.value) && field.value.id === subject;
|
|
1659
|
-
});
|
|
1651
|
+
return instance.completedAt != null || instance.definition !== definition ? !1 : instance.subject === subject;
|
|
1660
1652
|
});
|
|
1661
1653
|
}
|
|
1662
1654
|
|
|
@@ -1686,11 +1678,11 @@ function startFilterSyntaxIssues(groq) {
|
|
|
1686
1678
|
});
|
|
1687
1679
|
}
|
|
1688
1680
|
|
|
1689
|
-
function
|
|
1681
|
+
function startRequirementSyntaxIssues(groq) {
|
|
1690
1682
|
return startContextSyntaxIssues({
|
|
1691
1683
|
groq: groq,
|
|
1692
|
-
vars: invariants.
|
|
1693
|
-
context: "start-
|
|
1684
|
+
vars: invariants.START_REQUIREMENT_VARS,
|
|
1685
|
+
context: "start-requirement"
|
|
1694
1686
|
});
|
|
1695
1687
|
}
|
|
1696
1688
|
|
|
@@ -1698,7 +1690,7 @@ function startContextSyntaxIssues({groq: groq, vars: vars, context: context, ski
|
|
|
1698
1690
|
try {
|
|
1699
1691
|
groqJs.parse(groq);
|
|
1700
1692
|
} catch (err) {
|
|
1701
|
-
return [
|
|
1693
|
+
return [ invariants.errorMessage(err) ];
|
|
1702
1694
|
}
|
|
1703
1695
|
const bound = new Set(vars.map(v2 => v2.name));
|
|
1704
1696
|
return [ ...invariants.conditionParameterNames(groq) ].filter(name => !bound.has(name) && name !== skip).map(name => `reads $${name}, which the ${context} context does not bind (an unbound variable is GROQ null, so the predicate silently misevaluates — failing closed or passing vacuously by shape). Bound here: ` + vars.map(v2 => `$${v2.name}`).join(", "));
|
|
@@ -2538,24 +2530,24 @@ function applyFieldSet(op, ctx) {
|
|
|
2538
2530
|
src: op.value,
|
|
2539
2531
|
ctx: ctx,
|
|
2540
2532
|
target: entrySlot(entry)
|
|
2541
|
-
})
|
|
2542
|
-
return invariants.validateFieldValue({
|
|
2533
|
+
}), validated = invariants.validateFieldValue({
|
|
2543
2534
|
entryType: entry._type,
|
|
2544
2535
|
entryName: entry.name,
|
|
2545
2536
|
value: value,
|
|
2546
2537
|
...entryShape(entry)
|
|
2547
|
-
})
|
|
2538
|
+
});
|
|
2539
|
+
return assertRuntimeRefsWithinSurface({
|
|
2548
2540
|
entryType: entry._type,
|
|
2549
2541
|
entryName: entry.name,
|
|
2550
|
-
value:
|
|
2542
|
+
value: validated,
|
|
2551
2543
|
...entryShape(entry),
|
|
2552
2544
|
ctx: ctx,
|
|
2553
2545
|
src: op.value
|
|
2554
|
-
}), setEntryValue(entry,
|
|
2546
|
+
}), setEntryValue(entry, validated), {
|
|
2555
2547
|
opType: op.type,
|
|
2556
2548
|
target: op.target,
|
|
2557
2549
|
resolved: {
|
|
2558
|
-
value:
|
|
2550
|
+
value: validated
|
|
2559
2551
|
}
|
|
2560
2552
|
};
|
|
2561
2553
|
}
|
|
@@ -2616,27 +2608,27 @@ function applyFieldAppend(op, ctx) {
|
|
|
2616
2608
|
...slot !== void 0 ? {
|
|
2617
2609
|
target: slot
|
|
2618
2610
|
} : {}
|
|
2619
|
-
})
|
|
2620
|
-
invariants.validateFieldAppendItem({
|
|
2611
|
+
}), validated = invariants.validateFieldAppendItem({
|
|
2621
2612
|
entryType: entry._type,
|
|
2622
2613
|
entryName: entry.name,
|
|
2623
2614
|
item: item,
|
|
2624
2615
|
types: entry._type === "doc.refs" ? entry.types : void 0,
|
|
2625
2616
|
of: entry._type === "array" ? entry.of : void 0
|
|
2626
|
-
})
|
|
2617
|
+
});
|
|
2618
|
+
assertRuntimeRefsWithinSurface({
|
|
2627
2619
|
entryType: entry._type === "doc.refs" ? "doc.ref" : "object",
|
|
2628
2620
|
entryName: entry.name,
|
|
2629
|
-
value:
|
|
2621
|
+
value: validated,
|
|
2630
2622
|
fields: entry._type === "array" ? entry.of : void 0,
|
|
2631
2623
|
ctx: ctx,
|
|
2632
2624
|
src: op.value
|
|
2633
2625
|
});
|
|
2634
2626
|
const current = Array.isArray(entry.value) ? entry.value : [];
|
|
2635
|
-
return setEntryValue(entry, [ ...current, withRowKey(
|
|
2627
|
+
return setEntryValue(entry, [ ...current, withRowKey(validated) ]), {
|
|
2636
2628
|
opType: op.type,
|
|
2637
2629
|
target: op.target,
|
|
2638
2630
|
resolved: {
|
|
2639
|
-
item:
|
|
2631
|
+
item: validated
|
|
2640
2632
|
}
|
|
2641
2633
|
};
|
|
2642
2634
|
}
|
|
@@ -2664,8 +2656,9 @@ async function applyFieldUpdateWhere(op, ctx) {
|
|
|
2664
2656
|
mode: "value",
|
|
2665
2657
|
issues: [ `field.updateWhere value must resolve to an object of fields to merge (target "${op.target.field}")` ]
|
|
2666
2658
|
});
|
|
2659
|
+
const mergeRecord = merge;
|
|
2667
2660
|
requireNoReservedMergeKeys({
|
|
2668
|
-
merge:
|
|
2661
|
+
merge: mergeRecord,
|
|
2669
2662
|
entry: entry,
|
|
2670
2663
|
op: op
|
|
2671
2664
|
});
|
|
@@ -2675,25 +2668,27 @@ async function applyFieldUpdateWhere(op, ctx) {
|
|
|
2675
2668
|
ctx: ctx
|
|
2676
2669
|
}), next = rows.map((row, index) => matches[index] ? {
|
|
2677
2670
|
...row,
|
|
2678
|
-
...
|
|
2679
|
-
} : row)
|
|
2680
|
-
return invariants.validateFieldValue({
|
|
2671
|
+
...mergeRecord
|
|
2672
|
+
} : row), validated = invariants.validateFieldValue({
|
|
2681
2673
|
entryType: entry._type,
|
|
2682
2674
|
entryName: entry.name,
|
|
2683
2675
|
value: next,
|
|
2684
2676
|
of: entry.of
|
|
2685
|
-
})
|
|
2677
|
+
});
|
|
2678
|
+
assertRuntimeRefsWithinSurface({
|
|
2686
2679
|
entryType: "object",
|
|
2687
2680
|
entryName: entry.name,
|
|
2688
2681
|
value: merge,
|
|
2689
2682
|
fields: entry.of,
|
|
2690
2683
|
ctx: ctx,
|
|
2691
2684
|
src: op.value
|
|
2692
|
-
}), setEntryValue(entry,
|
|
2685
|
+
}), setEntryValue(entry, validated);
|
|
2686
|
+
const firstMatch = matches.indexOf(!0), persistedRows = validated, persistedMerge = firstMatch === -1 ? merge : Object.fromEntries(Object.keys(mergeRecord).map(key => [ key, persistedRows[firstMatch]?.[key] ]));
|
|
2687
|
+
return {
|
|
2693
2688
|
opType: op.type,
|
|
2694
2689
|
target: op.target,
|
|
2695
2690
|
resolved: {
|
|
2696
|
-
merge:
|
|
2691
|
+
merge: persistedMerge
|
|
2697
2692
|
}
|
|
2698
2693
|
};
|
|
2699
2694
|
}
|
|
@@ -2885,8 +2880,8 @@ function validateDefinition(definition) {
|
|
|
2885
2880
|
address: address
|
|
2886
2881
|
}));
|
|
2887
2882
|
}
|
|
2888
|
-
definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter))
|
|
2889
|
-
definition.start?.
|
|
2883
|
+
definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter));
|
|
2884
|
+
for (const [index, requirement] of (definition.start?.requirements ?? []).entries()) requirement.type === "groq" && v2.report(`start.requirements[${index}].query`, startRequirementSyntaxIssues(requirement.query));
|
|
2890
2885
|
for (const entry of definition.fields ?? []) v2.checkEntry(entry, `workflow.fields "${entry.name}"`);
|
|
2891
2886
|
for (const stage of definition.stages) validateStage(v2, stage);
|
|
2892
2887
|
for (const issue of invariants.checkWorkflowInvariants(definition)) v2.errors.push(` · ${invariants.formatIssuePath(issue.path)}: ${issue.message}`);
|
|
@@ -3316,6 +3311,11 @@ function definitionsListGroq(versionOrder) {
|
|
|
3316
3311
|
return `*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}] | order(name asc, version ${versionOrder})`;
|
|
3317
3312
|
}
|
|
3318
3313
|
|
|
3314
|
+
function latestDefinitionsGroq() {
|
|
3315
|
+
const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}`;
|
|
3316
|
+
return `*[${scoped} && version == math::max(*[${scoped} && name == ^.name].version)] | order(name asc)`;
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
3319
|
function latestDeployedDefinitions(rows) {
|
|
3320
3320
|
const byName = /* @__PURE__ */ new Map;
|
|
3321
3321
|
for (const row of rows) {
|
|
@@ -3397,7 +3397,7 @@ function blockedState(input) {
|
|
|
3397
3397
|
if (blocked !== void 0) return {
|
|
3398
3398
|
state: "blocked",
|
|
3399
3399
|
activity: blocked.activity.name,
|
|
3400
|
-
requirements: blocked.unmetRequirements ?? [],
|
|
3400
|
+
requirements: (blocked.unmetRequirements ?? []).map(requirement => requirement.name),
|
|
3401
3401
|
assignees: input.assignees[blocked.activity.name] ?? []
|
|
3402
3402
|
};
|
|
3403
3403
|
}
|
|
@@ -3440,7 +3440,7 @@ function diagnoseInstance(input) {
|
|
|
3440
3440
|
};
|
|
3441
3441
|
}
|
|
3442
3442
|
|
|
3443
|
-
const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects" ]);
|
|
3443
|
+
const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
|
|
3444
3444
|
|
|
3445
3445
|
function remediationsForCause(cause) {
|
|
3446
3446
|
switch (cause.kind) {
|
|
@@ -3942,7 +3942,7 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3942
3942
|
defaultValue: defaultValue
|
|
3943
3943
|
});
|
|
3944
3944
|
if (entry.initialValue?.type === "query") {
|
|
3945
|
-
const
|
|
3945
|
+
const check = invariants.parseFieldValue({
|
|
3946
3946
|
entryType: entry.type,
|
|
3947
3947
|
value: value,
|
|
3948
3948
|
types: entry.types,
|
|
@@ -3951,9 +3951,9 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3951
3951
|
options: entry.options,
|
|
3952
3952
|
validation: entry.validation
|
|
3953
3953
|
});
|
|
3954
|
-
return issues
|
|
3954
|
+
return "issues" in check ? (ctx.recordDiscard?.({
|
|
3955
3955
|
field: entry.name,
|
|
3956
|
-
detail: issues.join("; ")
|
|
3956
|
+
detail: check.issues.join("; ")
|
|
3957
3957
|
}), buildResolvedEntry({
|
|
3958
3958
|
entry: entry,
|
|
3959
3959
|
value: defaultValue,
|
|
@@ -3961,12 +3961,12 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3961
3961
|
now: ctx.now
|
|
3962
3962
|
})) : buildResolvedEntry({
|
|
3963
3963
|
entry: entry,
|
|
3964
|
-
value:
|
|
3964
|
+
value: check.output,
|
|
3965
3965
|
_key: randomKey2(),
|
|
3966
3966
|
now: ctx.now
|
|
3967
3967
|
});
|
|
3968
3968
|
}
|
|
3969
|
-
|
|
3969
|
+
const validated = invariants.validateFieldValue({
|
|
3970
3970
|
entryType: entry.type,
|
|
3971
3971
|
entryName: entry.name,
|
|
3972
3972
|
value: value,
|
|
@@ -3975,16 +3975,17 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3975
3975
|
of: entry.of,
|
|
3976
3976
|
options: entry.options,
|
|
3977
3977
|
validation: entry.validation
|
|
3978
|
-
})
|
|
3978
|
+
});
|
|
3979
|
+
return entry.initialValue?.type === "input" && ctx.inputProvenance !== "definition" && assertRefsWithinSurface({
|
|
3979
3980
|
entryType: entry.type,
|
|
3980
3981
|
entryName: entry.name,
|
|
3981
|
-
value:
|
|
3982
|
+
value: validated,
|
|
3982
3983
|
fields: entry.fields,
|
|
3983
3984
|
of: entry.of,
|
|
3984
3985
|
surface: ctx.refSurface
|
|
3985
3986
|
}), buildResolvedEntry({
|
|
3986
3987
|
entry: entry,
|
|
3987
|
-
value:
|
|
3988
|
+
value: validated,
|
|
3988
3989
|
_key: randomKey2(),
|
|
3989
3990
|
now: ctx.now
|
|
3990
3991
|
});
|
|
@@ -4378,172 +4379,605 @@ function parseInstanceDocument(doc) {
|
|
|
4378
4379
|
});
|
|
4379
4380
|
}
|
|
4380
4381
|
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4382
|
+
const SYNC_COMMIT = {
|
|
4383
|
+
visibility: "sync"
|
|
4384
|
+
}, ENGINE_API_VERSION = "2026-04-29", REQUEST_TAG = {
|
|
4385
|
+
engine: "workflow",
|
|
4386
|
+
deploy: "workflow.deploy",
|
|
4387
|
+
deleteDefinition: "workflow.delete-definition",
|
|
4388
|
+
start: "workflow.start",
|
|
4389
|
+
fireAction: "workflow.fire-action",
|
|
4390
|
+
editField: "workflow.edit-field",
|
|
4391
|
+
completeEffect: "workflow.complete-effect",
|
|
4392
|
+
commitEffectOps: "workflow.commit-effect-ops",
|
|
4393
|
+
tick: "workflow.tick",
|
|
4394
|
+
evaluate: "workflow.evaluate",
|
|
4395
|
+
evaluateStart: "workflow.evaluate-start",
|
|
4396
|
+
diagnose: "workflow.diagnose",
|
|
4397
|
+
availableActions: "workflow.available-actions",
|
|
4398
|
+
setStage: "workflow.set-stage",
|
|
4399
|
+
abort: "workflow.abort",
|
|
4400
|
+
resetActivity: "workflow.reset-activity",
|
|
4401
|
+
getInstance: "workflow.get-instance",
|
|
4402
|
+
children: "workflow.children",
|
|
4403
|
+
instancesForDocument: "workflow.instances-for-document",
|
|
4404
|
+
definitionsForDocument: "workflow.definitions-for-document",
|
|
4405
|
+
query: "workflow.query",
|
|
4406
|
+
discover: "workflow.discover",
|
|
4407
|
+
guardQuery: "workflow.guard.query",
|
|
4408
|
+
guardDeploy: "workflow.guard.deploy",
|
|
4409
|
+
guardRefresh: "workflow.guard.refresh",
|
|
4410
|
+
guardRetract: "workflow.guard.retract",
|
|
4411
|
+
effectList: "workflow.effect.list",
|
|
4412
|
+
effectFind: "workflow.effect.find",
|
|
4413
|
+
drain: "workflow.drain",
|
|
4414
|
+
effect: "workflow.effect",
|
|
4415
|
+
verifyDefinitions: "workflow.verify-definitions",
|
|
4416
|
+
accessResolveActor: "workflow.access.resolve-actor",
|
|
4417
|
+
accessGrants: "workflow.access.grants"
|
|
4418
|
+
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
4385
4419
|
|
|
4386
|
-
function
|
|
4387
|
-
return
|
|
4420
|
+
function unwrapPatch(patch) {
|
|
4421
|
+
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4388
4422
|
}
|
|
4389
4423
|
|
|
4390
|
-
|
|
4391
|
-
const doc = await getInstanceDocument(client, instanceId);
|
|
4392
|
-
if (!doc) throw new invariants.InstanceNotFoundError({
|
|
4393
|
-
instanceId: instanceId
|
|
4394
|
-
});
|
|
4395
|
-
if (doc.tag !== tag) throw new invariants.InstanceNotFoundError({
|
|
4396
|
-
instanceId: instanceId,
|
|
4397
|
-
detail: "not visible to this engine: tag mismatch"
|
|
4398
|
-
});
|
|
4399
|
-
return doc;
|
|
4400
|
-
}
|
|
4424
|
+
const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4401
4425
|
|
|
4402
|
-
function
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
_type: "context.string",
|
|
4407
|
-
name: name,
|
|
4408
|
-
value: value
|
|
4409
|
-
} : typeof value == "number" ? {
|
|
4410
|
-
_key: _key,
|
|
4411
|
-
_type: "context.number",
|
|
4412
|
-
name: name,
|
|
4413
|
-
value: value
|
|
4414
|
-
} : typeof value == "boolean" ? {
|
|
4415
|
-
_key: _key,
|
|
4416
|
-
_type: "context.boolean",
|
|
4417
|
-
name: name,
|
|
4418
|
-
value: value
|
|
4419
|
-
} : {
|
|
4420
|
-
_key: _key,
|
|
4421
|
-
_type: "context.ref",
|
|
4422
|
-
name: name,
|
|
4423
|
-
value: value
|
|
4424
|
-
};
|
|
4426
|
+
function unwrapRequestTag(client) {
|
|
4427
|
+
let current = client;
|
|
4428
|
+
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
4429
|
+
return current;
|
|
4425
4430
|
}
|
|
4426
4431
|
|
|
4427
|
-
function
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4432
|
+
function withRequestTag(client, fallback) {
|
|
4433
|
+
let byTag = wrapperCache.get(client);
|
|
4434
|
+
byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
|
|
4435
|
+
const cached = byTag.get(fallback);
|
|
4436
|
+
if (cached !== void 0) return cached;
|
|
4437
|
+
const wrapped = buildTaggedClient(client, fallback);
|
|
4438
|
+
return byTag.set(fallback, wrapped), wrapped;
|
|
4434
4439
|
}
|
|
4435
4440
|
|
|
4436
|
-
function
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4441
|
+
function effectHandlerClient(client) {
|
|
4442
|
+
const cached = effectHandlerClientCache.get(client);
|
|
4443
|
+
if (cached !== void 0) return cached;
|
|
4444
|
+
let tagged;
|
|
4445
|
+
if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
|
|
4446
|
+
const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
|
|
4447
|
+
tagged = client.withConfig({
|
|
4448
|
+
requestTagPrefix: effectTag
|
|
4449
|
+
});
|
|
4442
4450
|
}
|
|
4443
|
-
|
|
4444
|
-
return json;
|
|
4451
|
+
return effectHandlerClientCache.set(client, tagged), tagged;
|
|
4445
4452
|
}
|
|
4446
4453
|
|
|
4447
|
-
function
|
|
4448
|
-
|
|
4449
|
-
_key: randomKey(),
|
|
4450
|
-
_type: "stageEntered",
|
|
4451
|
-
at: now,
|
|
4452
|
-
stage: args.initialStage,
|
|
4453
|
-
...actor !== void 0 ? {
|
|
4454
|
-
actor: actor
|
|
4455
|
-
} : {}
|
|
4456
|
-
}, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
|
|
4457
|
-
_id: id,
|
|
4458
|
-
_type: invariants.WORKFLOW_INSTANCE_TYPE,
|
|
4459
|
-
_rev: "",
|
|
4460
|
-
_createdAt: now,
|
|
4461
|
-
_updatedAt: now,
|
|
4462
|
-
tag: args.tag,
|
|
4463
|
-
workflowResource: args.workflowResource,
|
|
4464
|
-
definition: args.definitionName,
|
|
4465
|
-
pinnedVersion: args.pinnedVersion,
|
|
4466
|
-
...args.pinnedContentHash !== void 0 ? {
|
|
4467
|
-
pinnedContentHash: args.pinnedContentHash
|
|
4468
|
-
} : {},
|
|
4469
|
-
definitionSnapshot: JSON.stringify(args.definition),
|
|
4470
|
-
fields: args.fields,
|
|
4471
|
-
context: args.context,
|
|
4472
|
-
ancestors: args.ancestors,
|
|
4473
|
-
...perspective !== void 0 ? {
|
|
4474
|
-
perspective: perspective
|
|
4475
|
-
} : {},
|
|
4476
|
-
currentStage: args.initialStage,
|
|
4477
|
-
stages: [],
|
|
4478
|
-
subworkflows: [],
|
|
4479
|
-
pendingEffects: [],
|
|
4480
|
-
effectHistory: [],
|
|
4481
|
-
history: history,
|
|
4482
|
-
startedAt: now,
|
|
4483
|
-
lastChangedAt: now
|
|
4484
|
-
};
|
|
4485
|
-
return {
|
|
4486
|
-
...body,
|
|
4487
|
-
...invariants.modelStampFor({
|
|
4488
|
-
documentType: "instance",
|
|
4489
|
-
document: body
|
|
4490
|
-
})
|
|
4491
|
-
};
|
|
4454
|
+
function effectHandlerResolver(resolver) {
|
|
4455
|
+
return mapResourceClientResolver(resolver, effectHandlerClient);
|
|
4492
4456
|
}
|
|
4493
4457
|
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
}), visited.add(invariants.selfGdr(instance));
|
|
4500
|
-
const {pending: pending, ordered: ordered} = planReads({
|
|
4501
|
-
client: client,
|
|
4502
|
-
clientForGdr: clientForGdr,
|
|
4503
|
-
instance: instance,
|
|
4504
|
-
overlay: overlay,
|
|
4505
|
-
visited: visited
|
|
4506
|
-
}), fetched = await readPending(pending);
|
|
4507
|
-
for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
|
|
4508
|
-
const doc = fetched.get(entry);
|
|
4509
|
-
doc !== void 0 && loaded.push({
|
|
4510
|
-
doc: doc,
|
|
4511
|
-
resource: entry.resource
|
|
4512
|
-
});
|
|
4513
|
-
}
|
|
4514
|
-
return buildSnapshot({
|
|
4515
|
-
docs: loaded
|
|
4516
|
-
});
|
|
4458
|
+
function mapResourceClientResolver(resolver, mapClient) {
|
|
4459
|
+
if (resolver !== void 0) return parsed => {
|
|
4460
|
+
const client = resolver(parsed);
|
|
4461
|
+
return client === void 0 ? void 0 : mapClient(client);
|
|
4462
|
+
};
|
|
4517
4463
|
}
|
|
4518
4464
|
|
|
4519
|
-
function
|
|
4520
|
-
|
|
4521
|
-
for (const ref of collectWatchRefs(instance)) {
|
|
4522
|
-
if (visited.has(ref.id)) continue;
|
|
4523
|
-
visited.add(ref.id);
|
|
4524
|
-
const held = overlay?.get(ref.id);
|
|
4525
|
-
if (held !== void 0) ordered.push(held); else {
|
|
4526
|
-
const read = routeRead({
|
|
4527
|
-
defaultClient: client,
|
|
4528
|
-
clientForGdr: clientForGdr,
|
|
4529
|
-
defaultResource: instance.workflowResource,
|
|
4530
|
-
uri: ref.id,
|
|
4531
|
-
perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
|
|
4532
|
-
});
|
|
4533
|
-
pending.push(read), ordered.push(read);
|
|
4534
|
-
}
|
|
4535
|
-
}
|
|
4536
|
-
return {
|
|
4537
|
-
pending: pending,
|
|
4538
|
-
ordered: ordered
|
|
4539
|
-
};
|
|
4465
|
+
function isWorkflowsFamilyPrefix(prefix) {
|
|
4466
|
+
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4540
4467
|
}
|
|
4541
4468
|
|
|
4542
|
-
function
|
|
4543
|
-
|
|
4469
|
+
function clientRequestTagPrefix(client) {
|
|
4470
|
+
const probe = client;
|
|
4471
|
+
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4544
4472
|
}
|
|
4545
4473
|
|
|
4546
|
-
|
|
4474
|
+
function composeRequestTag(prefix, tag) {
|
|
4475
|
+
if (prefix === void 0) return tag;
|
|
4476
|
+
const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
|
|
4477
|
+
return `${prefix}.${relative}`;
|
|
4478
|
+
}
|
|
4479
|
+
|
|
4480
|
+
function stripWorkflowRoot(tag) {
|
|
4481
|
+
return tag.startsWith("workflow.") ? tag.slice(9) : tag;
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
function buildTaggedClient(client, fallback) {
|
|
4485
|
+
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
|
|
4486
|
+
tag: normalize(fallback)
|
|
4487
|
+
} : options.tag === void 0 ? {
|
|
4488
|
+
...options,
|
|
4489
|
+
tag: normalize(fallback)
|
|
4490
|
+
} : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
|
|
4491
|
+
...options,
|
|
4492
|
+
tag: normalize(options.tag)
|
|
4493
|
+
} : options, wrapPatch = patch => {
|
|
4494
|
+
let target = patch;
|
|
4495
|
+
const wrapped = {
|
|
4496
|
+
get [RAW_PATCH]() {
|
|
4497
|
+
return target;
|
|
4498
|
+
},
|
|
4499
|
+
set: props => (target = target.set(props), wrapped),
|
|
4500
|
+
setIfMissing: props => (target = target.setIfMissing(props), wrapped),
|
|
4501
|
+
unset: paths => (target = target.unset(paths), wrapped),
|
|
4502
|
+
ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
|
|
4503
|
+
commit: options => target.commit(stamp(options))
|
|
4504
|
+
};
|
|
4505
|
+
return wrapped;
|
|
4506
|
+
}, wrapTransaction = tx => {
|
|
4507
|
+
let target = tx;
|
|
4508
|
+
const wrapped = {
|
|
4509
|
+
create: doc => (target = target.create(doc), wrapped),
|
|
4510
|
+
patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
|
|
4511
|
+
delete: id => (target = target.delete(id), wrapped),
|
|
4512
|
+
commit: options => target.commit(stamp(options))
|
|
4513
|
+
};
|
|
4514
|
+
return wrapped;
|
|
4515
|
+
}, overrides = {
|
|
4516
|
+
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
4517
|
+
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
4518
|
+
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
4519
|
+
patch: documentId => wrapPatch(client.patch(documentId)),
|
|
4520
|
+
create: (doc, options) => client.create(doc, stamp(options)),
|
|
4521
|
+
transaction: () => wrapTransaction(client.transaction()),
|
|
4522
|
+
...client.withConfig !== void 0 ? {
|
|
4523
|
+
withConfig: config => withRequestTag(client.withConfig(config), fallback)
|
|
4524
|
+
} : {},
|
|
4525
|
+
...client.action !== void 0 ? {
|
|
4526
|
+
action: (action, options) => client.action(action, stamp(options))
|
|
4527
|
+
} : {},
|
|
4528
|
+
...client.request !== void 0 ? {
|
|
4529
|
+
request: opts => client.request(stamp(opts))
|
|
4530
|
+
} : {}
|
|
4531
|
+
};
|
|
4532
|
+
return new Proxy(client, {
|
|
4533
|
+
has: (target, property) => Object.hasOwn(overrides, property) || property in target,
|
|
4534
|
+
get: (target, property) => {
|
|
4535
|
+
if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
|
|
4536
|
+
const value = Reflect.get(target, property, target);
|
|
4537
|
+
return typeof value == "function" ? value.bind(target) : value;
|
|
4538
|
+
}
|
|
4539
|
+
});
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
4543
|
+
|
|
4544
|
+
function pinApiVersion(client) {
|
|
4545
|
+
const raw = unwrapRequestTag(client);
|
|
4546
|
+
if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
|
|
4547
|
+
let sibling = pinCache.get(raw);
|
|
4548
|
+
return sibling === void 0 && (sibling = raw.withConfig({
|
|
4549
|
+
apiVersion: ENGINE_API_VERSION
|
|
4550
|
+
}), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
function taggedResolver(resolver, fallback) {
|
|
4554
|
+
return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4557
|
+
function taggedScope(args, tag) {
|
|
4558
|
+
const resourceClients = taggedResolver(args.resourceClients, tag);
|
|
4559
|
+
return {
|
|
4560
|
+
...args,
|
|
4561
|
+
client: withRequestTag(pinApiVersion(args.client), tag),
|
|
4562
|
+
...resourceClients !== void 0 ? {
|
|
4563
|
+
resourceClients: resourceClients
|
|
4564
|
+
} : {}
|
|
4565
|
+
};
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
const ACTOR_KIND_SET = new Set(invariants.ACTOR_KINDS), resolutionCache = /* @__PURE__ */ new WeakMap, warnedInstances = /* @__PURE__ */ new WeakMap;
|
|
4569
|
+
|
|
4570
|
+
async function normalizeInstanceIdentities(args) {
|
|
4571
|
+
const {client: client, instance: instance} = args, pending = collectLegacyIds(instance);
|
|
4572
|
+
if (pending.size === 0) return instance;
|
|
4573
|
+
const resolved = await resolveLegacyIds({
|
|
4574
|
+
client: client,
|
|
4575
|
+
instance: instance,
|
|
4576
|
+
pending: pending
|
|
4577
|
+
}), unresolved = [ ...pending ].filter(id => !resolved.has(id));
|
|
4578
|
+
return unresolved.length > 0 ? (warnUnresolvedOnce({
|
|
4579
|
+
client: client,
|
|
4580
|
+
instance: instance,
|
|
4581
|
+
unresolved: unresolved
|
|
4582
|
+
}), instance) : rewriteIdentitySlots(instance, id => resolved.get(id));
|
|
4583
|
+
}
|
|
4584
|
+
|
|
4585
|
+
async function resolveLegacyIds(args) {
|
|
4586
|
+
const resolved = /* @__PURE__ */ new Map, directoryIds = [];
|
|
4587
|
+
for (const id of args.pending) {
|
|
4588
|
+
const {globalId: globalId} = invariants.classifyPrincipalId(id);
|
|
4589
|
+
globalId !== void 0 ? resolved.set(id, globalId) : directoryIds.push(id);
|
|
4590
|
+
}
|
|
4591
|
+
const projectId = anchorProjectId(args.instance.workflowResource);
|
|
4592
|
+
if (directoryIds.length === 0 || projectId === void 0) return resolved;
|
|
4593
|
+
const fromDirectory = await resolveThroughDirectory({
|
|
4594
|
+
client: args.client,
|
|
4595
|
+
projectId: projectId,
|
|
4596
|
+
ids: directoryIds
|
|
4597
|
+
});
|
|
4598
|
+
for (const [id, globalId] of fromDirectory) resolved.set(id, globalId);
|
|
4599
|
+
return resolved;
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
function warnUnresolvedOnce(args) {
|
|
4603
|
+
const key = unwrapRequestTag(args.client);
|
|
4604
|
+
let warned = warnedInstances.get(key);
|
|
4605
|
+
warned === void 0 && (warned = /* @__PURE__ */ new Set, warnedInstances.set(key, warned)),
|
|
4606
|
+
!warned.has(args.instance._id) && (warned.add(args.instance._id), console.warn(`workflow: instance "${args.instance._id}" carries ${args.unresolved.length} legacy project-scoped principal id(s) the project-users directory could not resolve (${args.unresolved.join(", ")}). Its identity values are left as stored — comparisons against them fail closed — and the document does not self-heal until they resolve.`));
|
|
4607
|
+
}
|
|
4608
|
+
|
|
4609
|
+
function anchorProjectId(resource) {
|
|
4610
|
+
if (resource.type === "dataset") return invariants.datasetResourceParts(resource.id).projectId;
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
function collectLegacyIds(instance) {
|
|
4614
|
+
const found = /* @__PURE__ */ new Set;
|
|
4615
|
+
return rewriteIdentitySlots(instance, id => {
|
|
4616
|
+
invariants.classifyPrincipalId(id).namespace === "project" && found.add(id);
|
|
4617
|
+
}), found;
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4620
|
+
function rewriteIdentitySlots(instance, visit) {
|
|
4621
|
+
const record = instance, fields = walkEntries(record.fields, visit), stages = walkStages(record.stages, visit);
|
|
4622
|
+
return fields === record.fields && stages === record.stages ? instance : {
|
|
4623
|
+
...record,
|
|
4624
|
+
fields: fields,
|
|
4625
|
+
stages: stages
|
|
4626
|
+
};
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
function walkStages(stages, visit) {
|
|
4630
|
+
return Array.isArray(stages) ? shareMap(stages, stage => {
|
|
4631
|
+
const walked = walkEntryRow({
|
|
4632
|
+
row: stage,
|
|
4633
|
+
visit: visit
|
|
4634
|
+
});
|
|
4635
|
+
if (walked === null || typeof walked != "object") return walked;
|
|
4636
|
+
const record = walked, activities = walkActivities(record.activities, visit);
|
|
4637
|
+
return activities === record.activities ? walked === stage ? stage : walked : {
|
|
4638
|
+
...record,
|
|
4639
|
+
activities: activities
|
|
4640
|
+
};
|
|
4641
|
+
}) : stages;
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4644
|
+
function walkActivities(activities, visit) {
|
|
4645
|
+
return Array.isArray(activities) ? shareMap(activities, activity => walkEntryRow({
|
|
4646
|
+
row: activity,
|
|
4647
|
+
visit: visit
|
|
4648
|
+
})) : activities;
|
|
4649
|
+
}
|
|
4650
|
+
|
|
4651
|
+
function walkEntryRow(args) {
|
|
4652
|
+
const {row: row, visit: visit} = args;
|
|
4653
|
+
if (row === null || typeof row != "object") return row;
|
|
4654
|
+
const record = row, patch = {}, fields = walkEntries(record.fields, visit);
|
|
4655
|
+
if (fields !== record.fields && (patch.fields = fields), typeof record.completedBy == "string") {
|
|
4656
|
+
const stamped = visit(record.completedBy) ?? record.completedBy;
|
|
4657
|
+
stamped !== record.completedBy && (patch.completedBy = stamped);
|
|
4658
|
+
}
|
|
4659
|
+
return Object.keys(patch).length === 0 ? row : {
|
|
4660
|
+
...record,
|
|
4661
|
+
...patch
|
|
4662
|
+
};
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
function walkEntries(entries, visit) {
|
|
4666
|
+
return Array.isArray(entries) ? shareMap(entries, entry => {
|
|
4667
|
+
if (entry === null || typeof entry != "object") return entry;
|
|
4668
|
+
const record = entry, value = walkDeclaredValue({
|
|
4669
|
+
type: record._type,
|
|
4670
|
+
fields: record.fields,
|
|
4671
|
+
of: record.of,
|
|
4672
|
+
value: record.value,
|
|
4673
|
+
visit: visit
|
|
4674
|
+
});
|
|
4675
|
+
return value === record.value ? entry : {
|
|
4676
|
+
...record,
|
|
4677
|
+
value: value
|
|
4678
|
+
};
|
|
4679
|
+
}) : entries;
|
|
4680
|
+
}
|
|
4681
|
+
|
|
4682
|
+
function collectDeclaredGlobalIds(args) {
|
|
4683
|
+
const found = /* @__PURE__ */ new Set;
|
|
4684
|
+
return walkDeclaredValue({
|
|
4685
|
+
type: args.type,
|
|
4686
|
+
fields: args.fields,
|
|
4687
|
+
of: args.of,
|
|
4688
|
+
value: args.value,
|
|
4689
|
+
visit: id => {
|
|
4690
|
+
invariants.classifyPrincipalId(id).namespace === "global" && found.add(id);
|
|
4691
|
+
}
|
|
4692
|
+
}), found;
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4695
|
+
function rewriteDeclaredPrincipalIds(args) {
|
|
4696
|
+
return walkDeclaredValue({
|
|
4697
|
+
type: args.type,
|
|
4698
|
+
fields: args.fields,
|
|
4699
|
+
of: args.of,
|
|
4700
|
+
value: args.value,
|
|
4701
|
+
visit: id => args.map.get(id)
|
|
4702
|
+
});
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
function walkDeclaredValue(args) {
|
|
4706
|
+
const {type: type, value: value, visit: visit} = args;
|
|
4707
|
+
return type === "actor" || type === "assignee" ? visitPrincipalObject(value, visit) : type === "assignees" ? Array.isArray(value) ? shareMap(value, item => visitPrincipalObject(item, visit)) : value : type === "object" ? walkDeclaredObject({
|
|
4708
|
+
value: value,
|
|
4709
|
+
shapes: args.fields,
|
|
4710
|
+
visit: visit
|
|
4711
|
+
}) : type === "array" && Array.isArray(value) ? shareMap(value, row => walkDeclaredObject({
|
|
4712
|
+
value: row,
|
|
4713
|
+
shapes: args.of,
|
|
4714
|
+
visit: visit
|
|
4715
|
+
})) : value;
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
function walkDeclaredObject(args) {
|
|
4719
|
+
const {value: value, shapes: shapes, visit: visit} = args;
|
|
4720
|
+
if (value === null || typeof value != "object" || Array.isArray(value) || !Array.isArray(shapes)) return value;
|
|
4721
|
+
const record = value, patch = {};
|
|
4722
|
+
for (const shape of shapes) {
|
|
4723
|
+
const step = walkDeclaredProperty({
|
|
4724
|
+
record: record,
|
|
4725
|
+
shape: shape,
|
|
4726
|
+
visit: visit
|
|
4727
|
+
});
|
|
4728
|
+
step !== void 0 && (patch[step.name] = step.value);
|
|
4729
|
+
}
|
|
4730
|
+
return Object.keys(patch).length === 0 ? value : {
|
|
4731
|
+
...record,
|
|
4732
|
+
...patch
|
|
4733
|
+
};
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
function walkDeclaredProperty(args) {
|
|
4737
|
+
const {record: record, shape: shape, visit: visit} = args;
|
|
4738
|
+
if (shape === null || typeof shape != "object") return;
|
|
4739
|
+
const name = shape.name;
|
|
4740
|
+
if (typeof name != "string" || !Object.hasOwn(record, name)) return;
|
|
4741
|
+
const walked = walkDeclaredValue({
|
|
4742
|
+
type: shape.type,
|
|
4743
|
+
fields: shape.fields,
|
|
4744
|
+
of: shape.of,
|
|
4745
|
+
value: record[name],
|
|
4746
|
+
visit: visit
|
|
4747
|
+
});
|
|
4748
|
+
return walked === record[name] ? void 0 : {
|
|
4749
|
+
name: name,
|
|
4750
|
+
value: walked
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
|
|
4754
|
+
function visitPrincipalObject(value, visit) {
|
|
4755
|
+
if (value === null || typeof value != "object" || Array.isArray(value)) return value;
|
|
4756
|
+
const record = value;
|
|
4757
|
+
if (typeof record.id != "string" || record.type !== "user" && !(typeof record.kind == "string" && ACTOR_KIND_SET.has(record.kind))) return value;
|
|
4758
|
+
const stamped = visit(record.id) ?? record.id;
|
|
4759
|
+
return stamped === record.id ? value : {
|
|
4760
|
+
...record,
|
|
4761
|
+
id: stamped
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
|
|
4765
|
+
function shareMap(items, fn) {
|
|
4766
|
+
let changed = !1;
|
|
4767
|
+
const next = items.map(item => {
|
|
4768
|
+
const out = fn(item);
|
|
4769
|
+
return out !== item && (changed = !0), out;
|
|
4770
|
+
});
|
|
4771
|
+
return changed ? next : items;
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4774
|
+
const SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
4775
|
+
|
|
4776
|
+
async function resolveThroughDirectory(args) {
|
|
4777
|
+
const {client: client, projectId: projectId, ids: ids} = args, cache = cacheFor(unwrapRequestTag(client)), out = /* @__PURE__ */ new Map, safeMisses = ids.filter(id => {
|
|
4778
|
+
const hit = cache.get(id);
|
|
4779
|
+
return typeof hit == "string" && out.set(id, hit), hit === void 0;
|
|
4780
|
+
}).filter(id => SAFE_ID.test(id) && SAFE_ID.test(projectId));
|
|
4781
|
+
if (safeMisses.length === 0 || client.request === void 0) return out;
|
|
4782
|
+
try {
|
|
4783
|
+
const response = await client.request({
|
|
4784
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${safeMisses.map(encodeURIComponent).join(",")}`,
|
|
4785
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
4786
|
+
});
|
|
4787
|
+
ingestDirectoryRows({
|
|
4788
|
+
response: response,
|
|
4789
|
+
requested: new Set(safeMisses),
|
|
4790
|
+
cache: cache,
|
|
4791
|
+
out: out
|
|
4792
|
+
});
|
|
4793
|
+
for (const id of safeMisses) out.has(id) || cache.set(id, null);
|
|
4794
|
+
} catch (err) {
|
|
4795
|
+
console.warn(`workflow: project-users directory lookup failed for project "${projectId}" — legacy principal ids stay unresolved this pass. Original error: ${invariants.errorMessage(err)}`);
|
|
4796
|
+
}
|
|
4797
|
+
return out;
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4800
|
+
function cacheFor(client) {
|
|
4801
|
+
let cache = resolutionCache.get(client);
|
|
4802
|
+
return cache === void 0 && (cache = /* @__PURE__ */ new Map, resolutionCache.set(client, cache)),
|
|
4803
|
+
cache;
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
function ingestDirectoryRows(args) {
|
|
4807
|
+
const records = Array.isArray(args.response) ? args.response : [ args.response ];
|
|
4808
|
+
for (const row of records) typeof row?.id != "string" || typeof row.sanityUserId != "string" || args.requested.has(row.id) && invariants.classifyPrincipalId(row.sanityUserId).namespace === "global" && (args.cache.set(row.id, row.sanityUserId),
|
|
4809
|
+
args.out.set(row.id, row.sanityUserId));
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
async function getInstanceDocument(client, instanceId) {
|
|
4813
|
+
const doc = await client.getDocument(instanceId);
|
|
4814
|
+
if (doc) return normalizeInstanceIdentities({
|
|
4815
|
+
client: client,
|
|
4816
|
+
instance: readInstanceDoc(doc)
|
|
4817
|
+
});
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4820
|
+
function readInstanceDoc(doc) {
|
|
4821
|
+
return parseInstanceDocument(invariants.assertReadableModel(doc));
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4824
|
+
async function reload({client: client, instanceId: instanceId, tag: tag}) {
|
|
4825
|
+
const doc = await getInstanceDocument(client, instanceId);
|
|
4826
|
+
if (!doc) throw new invariants.InstanceNotFoundError({
|
|
4827
|
+
instanceId: instanceId
|
|
4828
|
+
});
|
|
4829
|
+
if (doc.tag !== tag) throw new invariants.InstanceNotFoundError({
|
|
4830
|
+
instanceId: instanceId,
|
|
4831
|
+
detail: "not visible to this engine: tag mismatch"
|
|
4832
|
+
});
|
|
4833
|
+
return doc;
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
function contextEntry(name, value) {
|
|
4837
|
+
const _key = randomKey();
|
|
4838
|
+
return typeof value == "string" ? {
|
|
4839
|
+
_key: _key,
|
|
4840
|
+
_type: "context.string",
|
|
4841
|
+
name: name,
|
|
4842
|
+
value: value
|
|
4843
|
+
} : typeof value == "number" ? {
|
|
4844
|
+
_key: _key,
|
|
4845
|
+
_type: "context.number",
|
|
4846
|
+
name: name,
|
|
4847
|
+
value: value
|
|
4848
|
+
} : typeof value == "boolean" ? {
|
|
4849
|
+
_key: _key,
|
|
4850
|
+
_type: "context.boolean",
|
|
4851
|
+
name: name,
|
|
4852
|
+
value: value
|
|
4853
|
+
} : {
|
|
4854
|
+
_key: _key,
|
|
4855
|
+
_type: "context.ref",
|
|
4856
|
+
name: name,
|
|
4857
|
+
value: value
|
|
4858
|
+
};
|
|
4859
|
+
}
|
|
4860
|
+
|
|
4861
|
+
function contextJsonEntry(name, value) {
|
|
4862
|
+
return {
|
|
4863
|
+
_key: randomKey(),
|
|
4864
|
+
_type: "context.json",
|
|
4865
|
+
name: name,
|
|
4866
|
+
value: serializeContextValue(name, value)
|
|
4867
|
+
};
|
|
4868
|
+
}
|
|
4869
|
+
|
|
4870
|
+
function serializeContextValue(name, value) {
|
|
4871
|
+
let json;
|
|
4872
|
+
try {
|
|
4873
|
+
json = JSON.stringify(value);
|
|
4874
|
+
} catch (err) {
|
|
4875
|
+
invariants.rethrowWithContext(err, `context entry "${name}" holds unserializable JSON`);
|
|
4876
|
+
}
|
|
4877
|
+
if (json === void 0) throw new Error(`context entry "${name}" holds a non-JSON value (undefined, a function, or a symbol)`);
|
|
4878
|
+
return json;
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4881
|
+
function buildInstanceBase(args) {
|
|
4882
|
+
const {id: id, now: now, actor: actor, perspective: perspective, executionContext: executionContext} = args, entries = [ {
|
|
4883
|
+
_key: randomKey(),
|
|
4884
|
+
_type: "stageEntered",
|
|
4885
|
+
at: now,
|
|
4886
|
+
stage: args.initialStage,
|
|
4887
|
+
...actor !== void 0 ? {
|
|
4888
|
+
actor: actor
|
|
4889
|
+
} : {}
|
|
4890
|
+
}, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
|
|
4891
|
+
_id: id,
|
|
4892
|
+
_type: invariants.WORKFLOW_INSTANCE_TYPE,
|
|
4893
|
+
_rev: "",
|
|
4894
|
+
_createdAt: now,
|
|
4895
|
+
_updatedAt: now,
|
|
4896
|
+
tag: args.tag,
|
|
4897
|
+
workflowResource: args.workflowResource,
|
|
4898
|
+
definition: args.definitionName,
|
|
4899
|
+
pinnedVersion: args.pinnedVersion,
|
|
4900
|
+
...args.pinnedContentHash !== void 0 ? {
|
|
4901
|
+
pinnedContentHash: args.pinnedContentHash
|
|
4902
|
+
} : {},
|
|
4903
|
+
definitionSnapshot: JSON.stringify(args.definition),
|
|
4904
|
+
fields: args.fields,
|
|
4905
|
+
context: args.context,
|
|
4906
|
+
ancestors: args.ancestors,
|
|
4907
|
+
...perspective !== void 0 ? {
|
|
4908
|
+
perspective: perspective
|
|
4909
|
+
} : {},
|
|
4910
|
+
currentStage: args.initialStage,
|
|
4911
|
+
stages: [],
|
|
4912
|
+
subworkflows: [],
|
|
4913
|
+
pendingEffects: [],
|
|
4914
|
+
effectHistory: [],
|
|
4915
|
+
history: history,
|
|
4916
|
+
startedAt: now,
|
|
4917
|
+
lastChangedAt: now
|
|
4918
|
+
};
|
|
4919
|
+
return {
|
|
4920
|
+
...body,
|
|
4921
|
+
...invariants.modelStampFor({
|
|
4922
|
+
documentType: "instance",
|
|
4923
|
+
document: body
|
|
4924
|
+
})
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4928
|
+
async function hydrateSnapshot(args) {
|
|
4929
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
|
|
4930
|
+
loaded.push({
|
|
4931
|
+
doc: instance,
|
|
4932
|
+
resource: instance.workflowResource
|
|
4933
|
+
}), visited.add(invariants.selfGdr(instance));
|
|
4934
|
+
const {pending: pending, ordered: ordered} = planReads({
|
|
4935
|
+
client: client,
|
|
4936
|
+
clientForGdr: clientForGdr,
|
|
4937
|
+
instance: instance,
|
|
4938
|
+
overlay: overlay,
|
|
4939
|
+
visited: visited
|
|
4940
|
+
}), fetched = await readPending(pending);
|
|
4941
|
+
for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
|
|
4942
|
+
const doc = fetched.get(entry);
|
|
4943
|
+
doc !== void 0 && loaded.push({
|
|
4944
|
+
doc: doc,
|
|
4945
|
+
resource: entry.resource
|
|
4946
|
+
});
|
|
4947
|
+
}
|
|
4948
|
+
return buildSnapshot({
|
|
4949
|
+
docs: loaded
|
|
4950
|
+
});
|
|
4951
|
+
}
|
|
4952
|
+
|
|
4953
|
+
function planReads(args) {
|
|
4954
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay, visited: visited} = args, pending = [], ordered = [];
|
|
4955
|
+
for (const ref of collectWatchRefs(instance)) {
|
|
4956
|
+
if (visited.has(ref.id)) continue;
|
|
4957
|
+
visited.add(ref.id);
|
|
4958
|
+
const held = overlay?.get(ref.id);
|
|
4959
|
+
if (held !== void 0) ordered.push(held); else {
|
|
4960
|
+
const read = routeRead({
|
|
4961
|
+
defaultClient: client,
|
|
4962
|
+
clientForGdr: clientForGdr,
|
|
4963
|
+
defaultResource: instance.workflowResource,
|
|
4964
|
+
uri: ref.id,
|
|
4965
|
+
perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
|
|
4966
|
+
});
|
|
4967
|
+
pending.push(read), ordered.push(read);
|
|
4968
|
+
}
|
|
4969
|
+
}
|
|
4970
|
+
return {
|
|
4971
|
+
pending: pending,
|
|
4972
|
+
ordered: ordered
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
function isPendingRead(entry) {
|
|
4977
|
+
return "client" in entry;
|
|
4978
|
+
}
|
|
4979
|
+
|
|
4980
|
+
const SNAPSHOT_READ_BATCH_SIZE = 100, SNAPSHOT_READ_CONCURRENCY = 4, snapshotDocsQuery = "*[_id in $ids]";
|
|
4547
4981
|
|
|
4548
4982
|
function routeRead({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4549
4983
|
const parsed = invariants.tryParseGdr(uri);
|
|
@@ -4660,29 +5094,31 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
|
|
|
4660
5094
|
if (!instance) throw new invariants.InstanceNotFoundError({
|
|
4661
5095
|
instanceId: instanceId
|
|
4662
5096
|
});
|
|
4663
|
-
|
|
5097
|
+
return buildEngineContext({
|
|
4664
5098
|
client: client,
|
|
4665
|
-
clientForGdr: clientForGdr,
|
|
5099
|
+
clientForGdr: options.clientForGdr,
|
|
5100
|
+
refSurface: options.refSurface,
|
|
4666
5101
|
instance: instance,
|
|
5102
|
+
definition: invariants.parseDefinitionSnapshot(instance),
|
|
5103
|
+
...options.actor !== void 0 ? {
|
|
5104
|
+
actor: options.actor
|
|
5105
|
+
} : {},
|
|
5106
|
+
...options.clock !== void 0 ? {
|
|
5107
|
+
clock: options.clock
|
|
5108
|
+
} : {},
|
|
5109
|
+
...options.executionContext !== void 0 ? {
|
|
5110
|
+
executionContext: options.executionContext
|
|
5111
|
+
} : {},
|
|
5112
|
+
...options.telemetry !== void 0 ? {
|
|
5113
|
+
telemetry: options.telemetry
|
|
5114
|
+
} : {},
|
|
4667
5115
|
...options.overlay !== void 0 ? {
|
|
4668
5116
|
overlay: options.overlay
|
|
5117
|
+
} : {},
|
|
5118
|
+
...options.settlingCohorts !== void 0 ? {
|
|
5119
|
+
settlingCohorts: options.settlingCohorts
|
|
4669
5120
|
} : {}
|
|
4670
5121
|
});
|
|
4671
|
-
return {
|
|
4672
|
-
client: client,
|
|
4673
|
-
clientForGdr: clientForGdr,
|
|
4674
|
-
refSurface: refSurface,
|
|
4675
|
-
clock: clock,
|
|
4676
|
-
now: clock(),
|
|
4677
|
-
executionContext: resolveExecutionContext(options?.executionContext),
|
|
4678
|
-
telemetry: resolveTelemetry(options.telemetry),
|
|
4679
|
-
...options?.actor !== void 0 ? {
|
|
4680
|
-
actor: options.actor
|
|
4681
|
-
} : {},
|
|
4682
|
-
instance: instance,
|
|
4683
|
-
definition: definition,
|
|
4684
|
-
snapshot: snapshot
|
|
4685
|
-
};
|
|
4686
5122
|
}
|
|
4687
5123
|
|
|
4688
5124
|
async function ctxConditionParams(ctx, opts) {
|
|
@@ -4720,6 +5156,9 @@ async function buildEngineContext(args) {
|
|
|
4720
5156
|
now: clock(),
|
|
4721
5157
|
executionContext: resolveExecutionContext(args.executionContext),
|
|
4722
5158
|
telemetry: resolveTelemetry(args.telemetry),
|
|
5159
|
+
...args.settlingCohorts !== void 0 ? {
|
|
5160
|
+
settlingCohorts: args.settlingCohorts
|
|
5161
|
+
} : {},
|
|
4723
5162
|
...args.actor !== void 0 ? {
|
|
4724
5163
|
actor: args.actor
|
|
4725
5164
|
} : {},
|
|
@@ -4728,7 +5167,10 @@ async function buildEngineContext(args) {
|
|
|
4728
5167
|
snapshot: await hydrateSnapshot({
|
|
4729
5168
|
client: client,
|
|
4730
5169
|
clientForGdr: clientForGdr,
|
|
4731
|
-
instance: instance
|
|
5170
|
+
instance: instance,
|
|
5171
|
+
...args.overlay !== void 0 ? {
|
|
5172
|
+
overlay: args.overlay
|
|
5173
|
+
} : {}
|
|
4732
5174
|
})
|
|
4733
5175
|
};
|
|
4734
5176
|
}
|
|
@@ -4851,10 +5293,6 @@ function recordProcessedRequest({mutation: mutation, record: record, now: now})
|
|
|
4851
5293
|
} ];
|
|
4852
5294
|
}
|
|
4853
5295
|
|
|
4854
|
-
const SYNC_COMMIT = {
|
|
4855
|
-
visibility: "sync"
|
|
4856
|
-
}, ENGINE_API_VERSION = "2026-04-29";
|
|
4857
|
-
|
|
4858
5296
|
function resolveGuardRead(args) {
|
|
4859
5297
|
const {expr: expr, ctx: ctx, deref: deref} = args;
|
|
4860
5298
|
if (expr === "$self") return invariants.selfGdr(ctx.instance);
|
|
@@ -4874,66 +5312,345 @@ function resolveGuardRead(args) {
|
|
|
4874
5312
|
const outputs = effectOutputsMap(ctx.instance)[effectsRead[1]];
|
|
4875
5313
|
return effectsRead[2] !== void 0 ? getPath(outputs, effectsRead[2]) : outputs;
|
|
4876
5314
|
}
|
|
4877
|
-
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)`);
|
|
5315
|
+
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)`);
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
function resolveIdRefTarget(expr, ctx) {
|
|
5319
|
+
const value = resolveGuardRead({
|
|
5320
|
+
expr: expr,
|
|
5321
|
+
ctx: ctx,
|
|
5322
|
+
deref: !1
|
|
5323
|
+
});
|
|
5324
|
+
if (typeof value == "string" && invariants.isGdrUri(value)) return {
|
|
5325
|
+
parsed: invariants.parseGdr(value)
|
|
5326
|
+
};
|
|
5327
|
+
if (value && typeof value == "object") {
|
|
5328
|
+
const v2 = value;
|
|
5329
|
+
if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
|
|
5330
|
+
parsed: invariants.parseGdr(v2.id),
|
|
5331
|
+
type: v2.type
|
|
5332
|
+
} : {
|
|
5333
|
+
parsed: invariants.parseGdr(v2.id)
|
|
5334
|
+
};
|
|
5335
|
+
}
|
|
5336
|
+
return null;
|
|
5337
|
+
}
|
|
5338
|
+
|
|
5339
|
+
function resolveIdRefTargets(idRefs, ctx) {
|
|
5340
|
+
const targets = [];
|
|
5341
|
+
for (const expr of idRefs ?? []) {
|
|
5342
|
+
const target = resolveIdRefTarget(expr, ctx);
|
|
5343
|
+
if (target === null) return null;
|
|
5344
|
+
targets.push(target);
|
|
5345
|
+
}
|
|
5346
|
+
return targets.length === 0 ? null : targets;
|
|
5347
|
+
}
|
|
5348
|
+
|
|
5349
|
+
function assertSingleResource(targets) {
|
|
5350
|
+
const resource = invariants.resourceFromParsed(targets[0].parsed);
|
|
5351
|
+
for (const g of targets) {
|
|
5352
|
+
const r = invariants.resourceFromParsed(g.parsed);
|
|
5353
|
+
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.`);
|
|
5354
|
+
}
|
|
5355
|
+
return resource;
|
|
5356
|
+
}
|
|
5357
|
+
|
|
5358
|
+
function bareIdRefs(targets) {
|
|
5359
|
+
return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5362
|
+
function resolveMatchTypes(targets, authorTypes) {
|
|
5363
|
+
if (authorTypes !== void 0) return authorTypes;
|
|
5364
|
+
const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
|
|
5365
|
+
return inferred.length > 0 ? inferred : void 0;
|
|
5366
|
+
}
|
|
5367
|
+
|
|
5368
|
+
function resolveMetadata(metadata, ctx) {
|
|
5369
|
+
const out = {};
|
|
5370
|
+
for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
|
|
5371
|
+
expr: expr,
|
|
5372
|
+
ctx: ctx,
|
|
5373
|
+
deref: !0
|
|
5374
|
+
});
|
|
5375
|
+
return out;
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
function isRecord(value) {
|
|
5379
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
function isClientProjectUser(value) {
|
|
5383
|
+
return isRecord(value) && typeof value.id == "string" && (value.sanityUserId === void 0 || typeof value.sanityUserId == "string") && (value.displayName === void 0 || typeof value.displayName == "string") && (value.email === void 0 || typeof value.email == "string") && (value.imageUrl === void 0 || value.imageUrl === null || typeof value.imageUrl == "string");
|
|
5384
|
+
}
|
|
5385
|
+
|
|
5386
|
+
function objectProperty(value, property) {
|
|
5387
|
+
if (!isRecord(value)) return;
|
|
5388
|
+
const propertyValue = value[property];
|
|
5389
|
+
return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
function stringProperty(value, property) {
|
|
5393
|
+
const propertyValue = Reflect.get(value, property);
|
|
5394
|
+
return typeof propertyValue == "string" ? propertyValue : void 0;
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5397
|
+
function apiErrorType(error) {
|
|
5398
|
+
const response = objectProperty(error, "response"), body = objectProperty(response, "body");
|
|
5399
|
+
if (!body) return;
|
|
5400
|
+
const nestedError = objectProperty(body, "error");
|
|
5401
|
+
return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5404
|
+
function isProjectUserNotFoundError(error) {
|
|
5405
|
+
return apiErrorType(error) === "projectUserNotFoundError";
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
const memberJoinCache = /* @__PURE__ */ new WeakMap;
|
|
5409
|
+
|
|
5410
|
+
function joinCacheFor(client) {
|
|
5411
|
+
let cache = memberJoinCache.get(client);
|
|
5412
|
+
return cache === void 0 && (cache = /* @__PURE__ */ new Map, memberJoinCache.set(client, cache)),
|
|
5413
|
+
cache;
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5416
|
+
async function projectMemberIds(request, projectId) {
|
|
5417
|
+
const project = await request({
|
|
5418
|
+
uri: `/projects/${encodeURIComponent(projectId)}`
|
|
5419
|
+
}), members = isRecord(project) ? project.members : void 0;
|
|
5420
|
+
return Array.isArray(members) ? members.map(member => isRecord(member) ? member.id : void 0).filter(id => typeof id == "string") : [];
|
|
5421
|
+
}
|
|
5422
|
+
|
|
5423
|
+
async function resolveGlobalProjectUser(args) {
|
|
5424
|
+
const {client: client, request: request, projectId: projectId, id: id} = args, cache = joinCacheFor(client), key = `${projectId}:${id}`, hit = cache.get(key);
|
|
5425
|
+
if (hit !== void 0) return hit === null ? {
|
|
5426
|
+
status: "missing"
|
|
5427
|
+
} : {
|
|
5428
|
+
status: "resolved",
|
|
5429
|
+
user: hit
|
|
5430
|
+
};
|
|
5431
|
+
try {
|
|
5432
|
+
await ingestMemberJoin({
|
|
5433
|
+
request: request,
|
|
5434
|
+
projectId: projectId,
|
|
5435
|
+
cache: cache
|
|
5436
|
+
});
|
|
5437
|
+
const found = cache.get(key);
|
|
5438
|
+
return found != null ? {
|
|
5439
|
+
status: "resolved",
|
|
5440
|
+
user: found
|
|
5441
|
+
} : (cache.set(key, null), {
|
|
5442
|
+
status: "missing"
|
|
5443
|
+
});
|
|
5444
|
+
} catch (cause) {
|
|
5445
|
+
return {
|
|
5446
|
+
status: "inaccessible",
|
|
5447
|
+
cause: cause
|
|
5448
|
+
};
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
|
|
5452
|
+
async function ingestMemberJoin(args) {
|
|
5453
|
+
const {request: request, projectId: projectId, cache: cache} = args, memberIds = await projectMemberIds(request, projectId);
|
|
5454
|
+
if (memberIds.length === 0) return;
|
|
5455
|
+
const response = await request({
|
|
5456
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
|
|
5457
|
+
});
|
|
5458
|
+
for (const row of Array.isArray(response) ? response : [ response ]) isClientProjectUser(row) && typeof row.sanityUserId == "string" && cache.set(`${projectId}:${row.sanityUserId}`, row);
|
|
5459
|
+
}
|
|
5460
|
+
|
|
5461
|
+
function clientProjectUserDirectory(client, projectId) {
|
|
5462
|
+
return {
|
|
5463
|
+
findById: async id => {
|
|
5464
|
+
if (!client.request) return {
|
|
5465
|
+
status: "inaccessible",
|
|
5466
|
+
cause: new Error("Project-user resolution requires WorkflowClient.request")
|
|
5467
|
+
};
|
|
5468
|
+
if (invariants.classifyPrincipalId(id).namespace === "global") return resolveGlobalProjectUser({
|
|
5469
|
+
client: client,
|
|
5470
|
+
request: client.request,
|
|
5471
|
+
projectId: projectId,
|
|
5472
|
+
id: id
|
|
5473
|
+
});
|
|
5474
|
+
try {
|
|
5475
|
+
const response = await client.request({
|
|
5476
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
|
|
5477
|
+
}), candidate = Array.isArray(response) ? response[0] : response;
|
|
5478
|
+
return candidate == null ? {
|
|
5479
|
+
status: "missing"
|
|
5480
|
+
} : isClientProjectUser(candidate) ? {
|
|
5481
|
+
status: "resolved",
|
|
5482
|
+
user: candidate
|
|
5483
|
+
} : {
|
|
5484
|
+
status: "inaccessible",
|
|
5485
|
+
cause: new Error("Project-user response had an invalid shape")
|
|
5486
|
+
};
|
|
5487
|
+
} catch (cause) {
|
|
5488
|
+
return isProjectUserNotFoundError(cause) ? {
|
|
5489
|
+
status: "missing"
|
|
5490
|
+
} : {
|
|
5491
|
+
status: "inaccessible",
|
|
5492
|
+
cause: cause
|
|
5493
|
+
};
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
|
|
5499
|
+
function resolveClientActor(client, args) {
|
|
5500
|
+
return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
|
|
5501
|
+
}
|
|
5502
|
+
|
|
5503
|
+
async function resolveActor(directory, actor) {
|
|
5504
|
+
if (actor.kind !== "person") return {
|
|
5505
|
+
status: "not-person",
|
|
5506
|
+
actor: actor
|
|
5507
|
+
};
|
|
5508
|
+
const personActor = {
|
|
5509
|
+
...actor,
|
|
5510
|
+
kind: "person"
|
|
5511
|
+
}, lookup = await directory.findById(personActor.id);
|
|
5512
|
+
return lookup.status === "resolved" ? {
|
|
5513
|
+
status: "resolved",
|
|
5514
|
+
actor: personActor,
|
|
5515
|
+
user: lookup.user
|
|
5516
|
+
} : lookup.status === "inaccessible" ? {
|
|
5517
|
+
status: "inaccessible",
|
|
5518
|
+
actor: personActor,
|
|
5519
|
+
...lookup.cause === void 0 ? {} : {
|
|
5520
|
+
cause: lookup.cause
|
|
5521
|
+
}
|
|
5522
|
+
} : {
|
|
5523
|
+
status: "missing",
|
|
5524
|
+
actor: personActor
|
|
5525
|
+
};
|
|
5526
|
+
}
|
|
5527
|
+
|
|
5528
|
+
const IDENTITY_KINDS = /* @__PURE__ */ new Set([ "actor", "assignee", "assignees" ]);
|
|
5529
|
+
|
|
5530
|
+
async function localizeGuardMetadata(args) {
|
|
5531
|
+
const {doc: doc, guard: guard, client: client, instance: instance, definition: definition} = args;
|
|
5532
|
+
if (doc.resourceType !== "dataset" || client.request === void 0) return doc;
|
|
5533
|
+
const request = client.request, {projectId: projectId} = invariants.datasetResourceParts(doc.resourceId), shapes = metadataShapes({
|
|
5534
|
+
guard: guard,
|
|
5535
|
+
instance: instance,
|
|
5536
|
+
definition: definition
|
|
5537
|
+
}), globals = collectMetadataGlobals({
|
|
5538
|
+
metadata: doc.metadata,
|
|
5539
|
+
shapes: shapes
|
|
5540
|
+
});
|
|
5541
|
+
if (globals.size === 0) return doc;
|
|
5542
|
+
const map = /* @__PURE__ */ new Map;
|
|
5543
|
+
for (const id of globals) {
|
|
5544
|
+
const lookup = await resolveGlobalProjectUser({
|
|
5545
|
+
client: client,
|
|
5546
|
+
request: request,
|
|
5547
|
+
projectId: projectId,
|
|
5548
|
+
id: id
|
|
5549
|
+
});
|
|
5550
|
+
lookup.status === "resolved" && map.set(id, lookup.user.id);
|
|
5551
|
+
}
|
|
5552
|
+
return map.size === 0 ? doc : {
|
|
5553
|
+
...doc,
|
|
5554
|
+
metadata: rewriteMetadata({
|
|
5555
|
+
metadata: doc.metadata,
|
|
5556
|
+
shapes: shapes,
|
|
5557
|
+
map: map
|
|
5558
|
+
})
|
|
5559
|
+
};
|
|
5560
|
+
}
|
|
5561
|
+
|
|
5562
|
+
function metadataShapes(args) {
|
|
5563
|
+
const out = /* @__PURE__ */ new Map;
|
|
5564
|
+
for (const [key, expr] of Object.entries(args.guard.metadata ?? {})) {
|
|
5565
|
+
const shape = shapeOfRead({
|
|
5566
|
+
expr: expr,
|
|
5567
|
+
instance: args.instance,
|
|
5568
|
+
definition: args.definition
|
|
5569
|
+
});
|
|
5570
|
+
shape !== void 0 && out.set(key, shape);
|
|
5571
|
+
}
|
|
5572
|
+
return out;
|
|
4878
5573
|
}
|
|
4879
5574
|
|
|
4880
|
-
function
|
|
4881
|
-
const
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
});
|
|
4886
|
-
if (typeof value == "string" && invariants.isGdrUri(value)) return {
|
|
4887
|
-
parsed: invariants.parseGdr(value)
|
|
4888
|
-
};
|
|
4889
|
-
if (value && typeof value == "object") {
|
|
4890
|
-
const v2 = value;
|
|
4891
|
-
if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
|
|
4892
|
-
parsed: invariants.parseGdr(v2.id),
|
|
4893
|
-
type: v2.type
|
|
4894
|
-
} : {
|
|
4895
|
-
parsed: invariants.parseGdr(v2.id)
|
|
4896
|
-
};
|
|
4897
|
-
}
|
|
4898
|
-
return null;
|
|
5575
|
+
function shapeOfRead(args) {
|
|
5576
|
+
const fieldRead = invariants.FIELD_READ.exec(args.expr);
|
|
5577
|
+
if (fieldRead !== null) return shapeOfFieldRead(args.instance, fieldRead);
|
|
5578
|
+
const effectsRead = invariants.EFFECTS_READ.exec(args.expr);
|
|
5579
|
+
if (effectsRead !== null) return shapeOfEffectsRead(args.definition, effectsRead);
|
|
4899
5580
|
}
|
|
4900
5581
|
|
|
4901
|
-
function
|
|
4902
|
-
const
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
}
|
|
4908
|
-
return targets.length === 0 ? null : targets;
|
|
5582
|
+
function shapeOfFieldRead(instance, fieldRead) {
|
|
5583
|
+
const entry = (instance.fields ?? []).find(s => s.name === fieldRead[1]);
|
|
5584
|
+
if (entry !== void 0) return narrowByPath({
|
|
5585
|
+
type: entry._type,
|
|
5586
|
+
fields: Reflect.get(entry, "fields"),
|
|
5587
|
+
of: Reflect.get(entry, "of")
|
|
5588
|
+
}, fieldRead[2]);
|
|
4909
5589
|
}
|
|
4910
5590
|
|
|
4911
|
-
function
|
|
4912
|
-
const
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
5591
|
+
function shapeOfEffectsRead(definition, effectsRead) {
|
|
5592
|
+
const outputs = findEffect(definition, effectsRead[1])?.outputs ?? [], path = effectsRead[2];
|
|
5593
|
+
if (path === void 0) return;
|
|
5594
|
+
const [head, ...rest] = path.split("."), output = outputs.find(shape => shape.name === head);
|
|
5595
|
+
if (output !== void 0) return narrowByPath({
|
|
5596
|
+
type: output.type,
|
|
5597
|
+
fields: output.fields,
|
|
5598
|
+
of: output.of
|
|
5599
|
+
}, rest.length > 0 ? rest.join(".") : void 0);
|
|
4918
5600
|
}
|
|
4919
5601
|
|
|
4920
|
-
function
|
|
4921
|
-
|
|
5602
|
+
function narrowByPath(shape, path) {
|
|
5603
|
+
if (path === void 0) return shape;
|
|
5604
|
+
if (typeof shape.type != "string" || !IDENTITY_KINDS.has(shape.type)) return;
|
|
5605
|
+
const steps = identityPathSteps(shape.type, path);
|
|
5606
|
+
if (steps === void 0) return;
|
|
5607
|
+
const itemType = shape.type === "assignees" ? "assignee" : shape.type;
|
|
5608
|
+
if (steps.length === 0) return {
|
|
5609
|
+
type: itemType
|
|
5610
|
+
};
|
|
5611
|
+
if (steps.length === 1 && steps[0] === "id") return {
|
|
5612
|
+
type: itemType,
|
|
5613
|
+
idLeaf: !0
|
|
5614
|
+
};
|
|
4922
5615
|
}
|
|
4923
5616
|
|
|
4924
|
-
function
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
return inferred.length > 0 ? inferred : void 0;
|
|
5617
|
+
function identityPathSteps(kind, path) {
|
|
5618
|
+
const segments = path.split(".");
|
|
5619
|
+
return kind !== "assignees" ? segments : /^\d+$/.test(segments[0] ?? "") ? segments.slice(1) : void 0;
|
|
4928
5620
|
}
|
|
4929
5621
|
|
|
4930
|
-
function
|
|
4931
|
-
const
|
|
4932
|
-
for (const [
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
5622
|
+
function collectMetadataGlobals(args) {
|
|
5623
|
+
const found = /* @__PURE__ */ new Set;
|
|
5624
|
+
for (const [key, shape] of args.shapes) {
|
|
5625
|
+
const value = args.metadata[key];
|
|
5626
|
+
if (shape.idLeaf === !0) {
|
|
5627
|
+
typeof value == "string" && invariants.classifyPrincipalId(value).namespace === "global" && found.add(value);
|
|
5628
|
+
continue;
|
|
5629
|
+
}
|
|
5630
|
+
for (const id of collectDeclaredGlobalIds({
|
|
5631
|
+
...shape,
|
|
5632
|
+
value: value
|
|
5633
|
+
})) found.add(id);
|
|
5634
|
+
}
|
|
5635
|
+
return found;
|
|
5636
|
+
}
|
|
5637
|
+
|
|
5638
|
+
function rewriteMetadata(args) {
|
|
5639
|
+
const out = {
|
|
5640
|
+
...args.metadata
|
|
5641
|
+
};
|
|
5642
|
+
for (const [key, shape] of args.shapes) {
|
|
5643
|
+
const value = out[key];
|
|
5644
|
+
if (shape.idLeaf === !0) {
|
|
5645
|
+
typeof value == "string" && (out[key] = args.map.get(value) ?? value);
|
|
5646
|
+
continue;
|
|
5647
|
+
}
|
|
5648
|
+
out[key] = rewriteDeclaredPrincipalIds({
|
|
5649
|
+
...shape,
|
|
5650
|
+
value: value,
|
|
5651
|
+
map: args.map
|
|
5652
|
+
});
|
|
5653
|
+
}
|
|
4937
5654
|
return out;
|
|
4938
5655
|
}
|
|
4939
5656
|
|
|
@@ -4969,189 +5686,6 @@ function parseGuardDocument(doc) {
|
|
|
4969
5686
|
});
|
|
4970
5687
|
}
|
|
4971
5688
|
|
|
4972
|
-
const REQUEST_TAG = {
|
|
4973
|
-
engine: "workflow",
|
|
4974
|
-
deploy: "workflow.deploy",
|
|
4975
|
-
deleteDefinition: "workflow.delete-definition",
|
|
4976
|
-
start: "workflow.start",
|
|
4977
|
-
fireAction: "workflow.fire-action",
|
|
4978
|
-
editField: "workflow.edit-field",
|
|
4979
|
-
completeEffect: "workflow.complete-effect",
|
|
4980
|
-
commitEffectOps: "workflow.commit-effect-ops",
|
|
4981
|
-
tick: "workflow.tick",
|
|
4982
|
-
evaluate: "workflow.evaluate",
|
|
4983
|
-
evaluateStart: "workflow.evaluate-start",
|
|
4984
|
-
diagnose: "workflow.diagnose",
|
|
4985
|
-
availableActions: "workflow.available-actions",
|
|
4986
|
-
setStage: "workflow.set-stage",
|
|
4987
|
-
abort: "workflow.abort",
|
|
4988
|
-
getInstance: "workflow.get-instance",
|
|
4989
|
-
children: "workflow.children",
|
|
4990
|
-
instancesForDocument: "workflow.instances-for-document",
|
|
4991
|
-
definitionsForDocument: "workflow.definitions-for-document",
|
|
4992
|
-
query: "workflow.query",
|
|
4993
|
-
discover: "workflow.discover",
|
|
4994
|
-
guardQuery: "workflow.guard.query",
|
|
4995
|
-
guardDeploy: "workflow.guard.deploy",
|
|
4996
|
-
guardRefresh: "workflow.guard.refresh",
|
|
4997
|
-
guardRetract: "workflow.guard.retract",
|
|
4998
|
-
effectList: "workflow.effect.list",
|
|
4999
|
-
effectFind: "workflow.effect.find",
|
|
5000
|
-
drain: "workflow.drain",
|
|
5001
|
-
effect: "workflow.effect",
|
|
5002
|
-
verifyDefinitions: "workflow.verify-definitions",
|
|
5003
|
-
accessResolveActor: "workflow.access.resolve-actor",
|
|
5004
|
-
accessGrants: "workflow.access.grants"
|
|
5005
|
-
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
5006
|
-
|
|
5007
|
-
function unwrapPatch(patch) {
|
|
5008
|
-
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
5009
|
-
}
|
|
5010
|
-
|
|
5011
|
-
const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
5012
|
-
|
|
5013
|
-
function unwrapRequestTag(client) {
|
|
5014
|
-
let current = client;
|
|
5015
|
-
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
5016
|
-
return current;
|
|
5017
|
-
}
|
|
5018
|
-
|
|
5019
|
-
function withRequestTag(client, fallback) {
|
|
5020
|
-
let byTag = wrapperCache.get(client);
|
|
5021
|
-
byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
|
|
5022
|
-
const cached = byTag.get(fallback);
|
|
5023
|
-
if (cached !== void 0) return cached;
|
|
5024
|
-
const wrapped = buildTaggedClient(client, fallback);
|
|
5025
|
-
return byTag.set(fallback, wrapped), wrapped;
|
|
5026
|
-
}
|
|
5027
|
-
|
|
5028
|
-
function effectHandlerClient(client) {
|
|
5029
|
-
const cached = effectHandlerClientCache.get(client);
|
|
5030
|
-
if (cached !== void 0) return cached;
|
|
5031
|
-
let tagged;
|
|
5032
|
-
if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
|
|
5033
|
-
const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
|
|
5034
|
-
tagged = client.withConfig({
|
|
5035
|
-
requestTagPrefix: effectTag
|
|
5036
|
-
});
|
|
5037
|
-
}
|
|
5038
|
-
return effectHandlerClientCache.set(client, tagged), tagged;
|
|
5039
|
-
}
|
|
5040
|
-
|
|
5041
|
-
function effectHandlerResolver(resolver) {
|
|
5042
|
-
return mapResourceClientResolver(resolver, effectHandlerClient);
|
|
5043
|
-
}
|
|
5044
|
-
|
|
5045
|
-
function mapResourceClientResolver(resolver, mapClient) {
|
|
5046
|
-
if (resolver !== void 0) return parsed => {
|
|
5047
|
-
const client = resolver(parsed);
|
|
5048
|
-
return client === void 0 ? void 0 : mapClient(client);
|
|
5049
|
-
};
|
|
5050
|
-
}
|
|
5051
|
-
|
|
5052
|
-
function isWorkflowsFamilyPrefix(prefix) {
|
|
5053
|
-
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
5054
|
-
}
|
|
5055
|
-
|
|
5056
|
-
function clientRequestTagPrefix(client) {
|
|
5057
|
-
const probe = client;
|
|
5058
|
-
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
5059
|
-
}
|
|
5060
|
-
|
|
5061
|
-
function composeRequestTag(prefix, tag) {
|
|
5062
|
-
if (prefix === void 0) return tag;
|
|
5063
|
-
const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
|
|
5064
|
-
return `${prefix}.${relative}`;
|
|
5065
|
-
}
|
|
5066
|
-
|
|
5067
|
-
function stripWorkflowRoot(tag) {
|
|
5068
|
-
return tag.startsWith("workflow.") ? tag.slice(9) : tag;
|
|
5069
|
-
}
|
|
5070
|
-
|
|
5071
|
-
function buildTaggedClient(client, fallback) {
|
|
5072
|
-
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
|
|
5073
|
-
tag: normalize(fallback)
|
|
5074
|
-
} : options.tag === void 0 ? {
|
|
5075
|
-
...options,
|
|
5076
|
-
tag: normalize(fallback)
|
|
5077
|
-
} : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
|
|
5078
|
-
...options,
|
|
5079
|
-
tag: normalize(options.tag)
|
|
5080
|
-
} : options, wrapPatch = patch => {
|
|
5081
|
-
let target = patch;
|
|
5082
|
-
const wrapped = {
|
|
5083
|
-
get [RAW_PATCH]() {
|
|
5084
|
-
return target;
|
|
5085
|
-
},
|
|
5086
|
-
set: props => (target = target.set(props), wrapped),
|
|
5087
|
-
setIfMissing: props => (target = target.setIfMissing(props), wrapped),
|
|
5088
|
-
unset: paths => (target = target.unset(paths), wrapped),
|
|
5089
|
-
ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
|
|
5090
|
-
commit: options => target.commit(stamp(options))
|
|
5091
|
-
};
|
|
5092
|
-
return wrapped;
|
|
5093
|
-
}, wrapTransaction = tx => {
|
|
5094
|
-
let target = tx;
|
|
5095
|
-
const wrapped = {
|
|
5096
|
-
create: doc => (target = target.create(doc), wrapped),
|
|
5097
|
-
patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
|
|
5098
|
-
delete: id => (target = target.delete(id), wrapped),
|
|
5099
|
-
commit: options => target.commit(stamp(options))
|
|
5100
|
-
};
|
|
5101
|
-
return wrapped;
|
|
5102
|
-
}, overrides = {
|
|
5103
|
-
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
5104
|
-
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
5105
|
-
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
5106
|
-
patch: documentId => wrapPatch(client.patch(documentId)),
|
|
5107
|
-
create: (doc, options) => client.create(doc, stamp(options)),
|
|
5108
|
-
transaction: () => wrapTransaction(client.transaction()),
|
|
5109
|
-
...client.withConfig !== void 0 ? {
|
|
5110
|
-
withConfig: config => withRequestTag(client.withConfig(config), fallback)
|
|
5111
|
-
} : {},
|
|
5112
|
-
...client.action !== void 0 ? {
|
|
5113
|
-
action: (action, options) => client.action(action, stamp(options))
|
|
5114
|
-
} : {},
|
|
5115
|
-
...client.request !== void 0 ? {
|
|
5116
|
-
request: opts => client.request(stamp(opts))
|
|
5117
|
-
} : {}
|
|
5118
|
-
};
|
|
5119
|
-
return new Proxy(client, {
|
|
5120
|
-
has: (target, property) => Object.hasOwn(overrides, property) || property in target,
|
|
5121
|
-
get: (target, property) => {
|
|
5122
|
-
if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
|
|
5123
|
-
const value = Reflect.get(target, property, target);
|
|
5124
|
-
return typeof value == "function" ? value.bind(target) : value;
|
|
5125
|
-
}
|
|
5126
|
-
});
|
|
5127
|
-
}
|
|
5128
|
-
|
|
5129
|
-
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
5130
|
-
|
|
5131
|
-
function pinApiVersion(client) {
|
|
5132
|
-
const raw = unwrapRequestTag(client);
|
|
5133
|
-
if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
|
|
5134
|
-
let sibling = pinCache.get(raw);
|
|
5135
|
-
return sibling === void 0 && (sibling = raw.withConfig({
|
|
5136
|
-
apiVersion: ENGINE_API_VERSION
|
|
5137
|
-
}), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
|
|
5138
|
-
}
|
|
5139
|
-
|
|
5140
|
-
function taggedResolver(resolver, fallback) {
|
|
5141
|
-
return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
|
|
5142
|
-
}
|
|
5143
|
-
|
|
5144
|
-
function taggedScope(args, tag) {
|
|
5145
|
-
const resourceClients = taggedResolver(args.resourceClients, tag);
|
|
5146
|
-
return {
|
|
5147
|
-
...args,
|
|
5148
|
-
client: withRequestTag(pinApiVersion(args.client), tag),
|
|
5149
|
-
...resourceClients !== void 0 ? {
|
|
5150
|
-
resourceClients: resourceClients
|
|
5151
|
-
} : {}
|
|
5152
|
-
};
|
|
5153
|
-
}
|
|
5154
|
-
|
|
5155
5689
|
async function fetchGuards(args) {
|
|
5156
5690
|
return (await args.client.fetch(args.query, args.params, {
|
|
5157
5691
|
tag: REQUEST_TAG.guardQuery
|
|
@@ -5365,7 +5899,8 @@ function resolvedStageGuards(args) {
|
|
|
5365
5899
|
resolved !== null && out.push({
|
|
5366
5900
|
client: args.clientForGdr(resolved.routeGdr),
|
|
5367
5901
|
resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(resolved.routeGdr)),
|
|
5368
|
-
value: resolved.doc
|
|
5902
|
+
value: resolved.doc,
|
|
5903
|
+
guard: guard
|
|
5369
5904
|
});
|
|
5370
5905
|
}
|
|
5371
5906
|
return out;
|
|
@@ -5439,11 +5974,18 @@ async function deployStageGuards(args) {
|
|
|
5439
5974
|
if (live === void 0 || live.currentStage !== args.stageName || live.abortedAt !== void 0) return;
|
|
5440
5975
|
const routed = resolvedStageGuards(args), existingByResource = await existingGuardIds(groupByResource(routed));
|
|
5441
5976
|
let deployed = 0;
|
|
5442
|
-
for (const {client: client, resourceKey: resourceKey, value: doc} of routed) {
|
|
5977
|
+
for (const {client: client, resourceKey: resourceKey, value: doc, guard: guard} of routed) {
|
|
5443
5978
|
try {
|
|
5979
|
+
const localized = await localizeGuardMetadata({
|
|
5980
|
+
doc: doc,
|
|
5981
|
+
guard: guard,
|
|
5982
|
+
client: client,
|
|
5983
|
+
instance: args.instance,
|
|
5984
|
+
definition: args.definition
|
|
5985
|
+
});
|
|
5444
5986
|
await upsertGuard({
|
|
5445
5987
|
client: client,
|
|
5446
|
-
doc:
|
|
5988
|
+
doc: localized,
|
|
5447
5989
|
exists: existingByResource.get(resourceKey)?.has(doc._id) ?? !1
|
|
5448
5990
|
});
|
|
5449
5991
|
} catch (cause) {
|
|
@@ -5563,7 +6105,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5563
6105
|
...actor !== void 0 ? {
|
|
5564
6106
|
actor: actor
|
|
5565
6107
|
} : {}
|
|
5566
|
-
}), mutation.completedAt = at, mutation.abortedAt = at
|
|
6108
|
+
}), mutation.completedAt = at, mutation.abortedAt = at;
|
|
6109
|
+
const instance = readInstanceDoc(await persist(ctx, mutation));
|
|
5567
6110
|
await retractStageGuards({
|
|
5568
6111
|
client: ctx.client,
|
|
5569
6112
|
clientForGdr: ctx.clientForGdr,
|
|
@@ -5583,7 +6126,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5583
6126
|
});
|
|
5584
6127
|
return {
|
|
5585
6128
|
fired: !0,
|
|
5586
|
-
stage: stage.name
|
|
6129
|
+
stage: stage.name,
|
|
6130
|
+
instance: instance
|
|
5587
6131
|
};
|
|
5588
6132
|
}
|
|
5589
6133
|
|
|
@@ -6335,18 +6879,42 @@ async function fetchGrants(args) {
|
|
|
6335
6879
|
});
|
|
6336
6880
|
}
|
|
6337
6881
|
|
|
6338
|
-
async function
|
|
6882
|
+
async function advisoryCanForCall(args) {
|
|
6883
|
+
const actor = args.options?.actor;
|
|
6884
|
+
if (!(args.options?.grants === void 0 || actor === void 0)) return advisoryCan({
|
|
6885
|
+
instance: args.instance,
|
|
6886
|
+
identity: invariants.lakePrincipalId({
|
|
6887
|
+
actor: actor,
|
|
6888
|
+
localPrincipalId: args.options.localPrincipalId
|
|
6889
|
+
}),
|
|
6890
|
+
grants: args.options.grants
|
|
6891
|
+
});
|
|
6892
|
+
}
|
|
6893
|
+
|
|
6894
|
+
async function advisoryCan({instance: instance, identity: identity, grants: grants}) {
|
|
6339
6895
|
if (grants === void 0) return;
|
|
6340
6896
|
const can = {};
|
|
6341
6897
|
for (const permission of invariants.DOCUMENT_VALUE_PERMISSIONS) can[permission] = await grantsPermissionOn({
|
|
6342
6898
|
document: instance,
|
|
6343
6899
|
grants: grants,
|
|
6344
6900
|
permission: permission,
|
|
6345
|
-
userId:
|
|
6901
|
+
userId: identity
|
|
6346
6902
|
});
|
|
6347
6903
|
return can;
|
|
6348
6904
|
}
|
|
6349
6905
|
|
|
6906
|
+
function requirementDescriptor(requirement) {
|
|
6907
|
+
return {
|
|
6908
|
+
name: requirement.name,
|
|
6909
|
+
...requirement.title !== void 0 ? {
|
|
6910
|
+
title: requirement.title
|
|
6911
|
+
} : {},
|
|
6912
|
+
...requirement.description !== void 0 ? {
|
|
6913
|
+
description: requirement.description
|
|
6914
|
+
} : {}
|
|
6915
|
+
};
|
|
6916
|
+
}
|
|
6917
|
+
|
|
6350
6918
|
function subjectDenialLabels(denied) {
|
|
6351
6919
|
return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
|
|
6352
6920
|
}
|
|
@@ -6367,10 +6935,10 @@ class ActionDisabledError extends invariants.WorkflowError {
|
|
|
6367
6935
|
|
|
6368
6936
|
class StartNotAllowedError extends invariants.WorkflowError {
|
|
6369
6937
|
definition;
|
|
6370
|
-
|
|
6938
|
+
unmetRequirements;
|
|
6371
6939
|
constructor(args) {
|
|
6372
|
-
super("start-not-allowed", `startInstance refused
|
|
6373
|
-
this.name = "StartNotAllowedError", this.definition = args.definition, this.
|
|
6940
|
+
super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
|
|
6941
|
+
this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
|
|
6374
6942
|
}
|
|
6375
6943
|
}
|
|
6376
6944
|
|
|
@@ -6386,7 +6954,7 @@ const disabledReasonDetail = {
|
|
|
6386
6954
|
"stage-terminal": r => `stage "${r.stage}" is terminal`,
|
|
6387
6955
|
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6388
6956
|
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6389
|
-
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
|
|
6957
|
+
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
|
|
6390
6958
|
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
6391
6959
|
};
|
|
6392
6960
|
|
|
@@ -6455,11 +7023,10 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
|
|
|
6455
7023
|
}
|
|
6456
7024
|
});
|
|
6457
7025
|
if (action.filter !== void 0) {
|
|
6458
|
-
const can =
|
|
7026
|
+
const can = await advisoryCanForCall({
|
|
6459
7027
|
instance: ctx.instance,
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
}) : void 0;
|
|
7028
|
+
options: options
|
|
7029
|
+
});
|
|
6463
7030
|
if (!await ctxEvaluateCondition({
|
|
6464
7031
|
ctx: ctx,
|
|
6465
7032
|
condition: action.filter,
|
|
@@ -6712,30 +7279,12 @@ async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: acti
|
|
|
6712
7279
|
};
|
|
6713
7280
|
}
|
|
6714
7281
|
|
|
6715
|
-
async function primeInitialStage(
|
|
6716
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
7282
|
+
async function primeInitialStage(args) {
|
|
7283
|
+
const {client: client, instanceId: instanceId, refSurface: refSurface, clientForGdr: clientForGdr} = args, instance = await getInstanceDocument(client, instanceId);
|
|
6717
7284
|
if (!instance || instance.stages.length > 0) return;
|
|
6718
|
-
const
|
|
7285
|
+
const ctx = await buildCascadeStepContext(args, instance), {definition: definition} = ctx, stage = definition.stages.find(s => s.name === instance.currentStage);
|
|
6719
7286
|
if (stage === void 0) return;
|
|
6720
|
-
const ctx =
|
|
6721
|
-
client: client,
|
|
6722
|
-
clientForGdr: clientForGdr,
|
|
6723
|
-
refSurface: refSurface,
|
|
6724
|
-
instance: instance,
|
|
6725
|
-
definition: definition,
|
|
6726
|
-
...clock ? {
|
|
6727
|
-
clock: clock
|
|
6728
|
-
} : {},
|
|
6729
|
-
...actor ? {
|
|
6730
|
-
actor: actor
|
|
6731
|
-
} : {},
|
|
6732
|
-
...executionContext ? {
|
|
6733
|
-
executionContext: executionContext
|
|
6734
|
-
} : {},
|
|
6735
|
-
...telemetry ? {
|
|
6736
|
-
telemetry: telemetry
|
|
6737
|
-
} : {}
|
|
6738
|
-
}), now = ctx.now, discards = [], initialStageEntry = {
|
|
7287
|
+
const now = ctx.now, discards = [], initialStageEntry = {
|
|
6739
7288
|
_key: randomKey(),
|
|
6740
7289
|
name: stage.name,
|
|
6741
7290
|
enteredAt: now,
|
|
@@ -6804,29 +7353,37 @@ async function primeInitialStage({client: client, instanceId: instanceId, actor:
|
|
|
6804
7353
|
|
|
6805
7354
|
const CASCADE_LIMIT = 100;
|
|
6806
7355
|
|
|
6807
|
-
async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
6808
|
-
const
|
|
7356
|
+
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}) {
|
|
7357
|
+
const contextOptions = {
|
|
7358
|
+
clientForGdr: clientForGdr,
|
|
7359
|
+
refSurface: refSurface,
|
|
7360
|
+
...actor ? {
|
|
7361
|
+
actor: actor
|
|
7362
|
+
} : {},
|
|
7363
|
+
...clock ? {
|
|
7364
|
+
clock: clock
|
|
7365
|
+
} : {},
|
|
7366
|
+
...executionContext ? {
|
|
7367
|
+
executionContext: executionContext
|
|
7368
|
+
} : {},
|
|
7369
|
+
...telemetry ? {
|
|
7370
|
+
telemetry: telemetry
|
|
7371
|
+
} : {},
|
|
7372
|
+
...overlay ? {
|
|
7373
|
+
overlay: overlay
|
|
7374
|
+
} : {},
|
|
7375
|
+
...settlingCohorts ? {
|
|
7376
|
+
settlingCohorts: settlingCohorts
|
|
7377
|
+
} : {}
|
|
7378
|
+
}, ctx = instance === void 0 ? await loadContext({
|
|
6809
7379
|
client: client,
|
|
6810
7380
|
instanceId: instanceId,
|
|
6811
|
-
options:
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
...clock ? {
|
|
6818
|
-
clock: clock
|
|
6819
|
-
} : {},
|
|
6820
|
-
...executionContext ? {
|
|
6821
|
-
executionContext: executionContext
|
|
6822
|
-
} : {},
|
|
6823
|
-
...telemetry ? {
|
|
6824
|
-
telemetry: telemetry
|
|
6825
|
-
} : {},
|
|
6826
|
-
...overlay ? {
|
|
6827
|
-
overlay: overlay
|
|
6828
|
-
} : {}
|
|
6829
|
-
}
|
|
7381
|
+
options: contextOptions
|
|
7382
|
+
}) : await buildEngineContext({
|
|
7383
|
+
client: client,
|
|
7384
|
+
instance: instance,
|
|
7385
|
+
definition: invariants.parseDefinitionSnapshot(instance),
|
|
7386
|
+
...contextOptions
|
|
6830
7387
|
});
|
|
6831
7388
|
if (isTerminal(ctx)) return {
|
|
6832
7389
|
moved: !1
|
|
@@ -6856,10 +7413,10 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
|
|
|
6856
7413
|
});
|
|
6857
7414
|
}
|
|
6858
7415
|
|
|
6859
|
-
async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
7416
|
+
async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts}) {
|
|
6860
7417
|
let count = 0;
|
|
6861
7418
|
for (;;) {
|
|
6862
|
-
|
|
7419
|
+
const drained = await drainCondemnedChildren({
|
|
6863
7420
|
client: client,
|
|
6864
7421
|
instanceId: instanceId,
|
|
6865
7422
|
actor: actor,
|
|
@@ -6868,7 +7425,8 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6868
7425
|
clock: clock,
|
|
6869
7426
|
executionContext: executionContext,
|
|
6870
7427
|
telemetry: telemetry
|
|
6871
|
-
})
|
|
7428
|
+
});
|
|
7429
|
+
if (!(await runCascadeHop({
|
|
6872
7430
|
client: client,
|
|
6873
7431
|
instanceId: instanceId,
|
|
6874
7432
|
actor: actor,
|
|
@@ -6877,7 +7435,11 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6877
7435
|
clock: clock,
|
|
6878
7436
|
executionContext: executionContext,
|
|
6879
7437
|
telemetry: telemetry,
|
|
6880
|
-
overlay: overlay
|
|
7438
|
+
overlay: overlay,
|
|
7439
|
+
settlingCohorts: settlingCohorts,
|
|
7440
|
+
...drained.drained ? {} : {
|
|
7441
|
+
instance: drained.instance
|
|
7442
|
+
}
|
|
6881
7443
|
})).moved) return count;
|
|
6882
7444
|
if (count++, count >= CASCADE_LIMIT) throw new CascadeLimitError({
|
|
6883
7445
|
instanceId: instanceId,
|
|
@@ -6886,39 +7448,50 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6886
7448
|
}
|
|
6887
7449
|
}
|
|
6888
7450
|
|
|
6889
|
-
async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set}) {
|
|
6890
|
-
if (draining.has(instanceId)) return
|
|
7451
|
+
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}) {
|
|
7452
|
+
if (draining.has(instanceId)) return {
|
|
7453
|
+
instance: preloadedInstance,
|
|
7454
|
+
drained: !1
|
|
7455
|
+
};
|
|
6891
7456
|
draining.add(instanceId);
|
|
6892
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
6893
|
-
if (!instance) return
|
|
7457
|
+
const instance = preloadedInstance ?? await getInstanceDocument(client, instanceId);
|
|
7458
|
+
if (!instance) return {
|
|
7459
|
+
instance: void 0,
|
|
7460
|
+
drained: !1
|
|
7461
|
+
};
|
|
6894
7462
|
const condemned = condemnedSubworkflows(instance);
|
|
6895
|
-
if (condemned.length
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
7463
|
+
if (condemned.length === 0) return {
|
|
7464
|
+
instance: instance,
|
|
7465
|
+
drained: !1
|
|
7466
|
+
};
|
|
7467
|
+
for (const row of condemned) await settleCondemnedRow({
|
|
7468
|
+
client: client,
|
|
7469
|
+
ownerId: instanceId,
|
|
7470
|
+
row: row,
|
|
7471
|
+
actor: actor,
|
|
7472
|
+
clientForGdr: clientForGdr,
|
|
7473
|
+
refSurface: refSurface,
|
|
7474
|
+
clock: clock,
|
|
7475
|
+
executionContext: executionContext,
|
|
7476
|
+
telemetry: telemetry,
|
|
7477
|
+
draining: draining
|
|
7478
|
+
});
|
|
7479
|
+
return await stampDrainedRows({
|
|
7480
|
+
client: client,
|
|
7481
|
+
instance: instance,
|
|
7482
|
+
condemned: condemned,
|
|
7483
|
+
clock: clock,
|
|
7484
|
+
executionContext: executionContext
|
|
7485
|
+
}), {
|
|
7486
|
+
instance: instance,
|
|
7487
|
+
drained: !0
|
|
7488
|
+
};
|
|
6916
7489
|
}
|
|
6917
7490
|
|
|
6918
7491
|
async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
|
|
6919
7492
|
const childId = invariants.toBareId(row.ref.id);
|
|
6920
7493
|
try {
|
|
6921
|
-
await abortInstance({
|
|
7494
|
+
const result = await abortInstance({
|
|
6922
7495
|
client: client,
|
|
6923
7496
|
instanceId: childId,
|
|
6924
7497
|
reason: row.abortPending?.reason ?? "condemned by parent",
|
|
@@ -6938,7 +7511,8 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6938
7511
|
telemetry: telemetry
|
|
6939
7512
|
} : {}
|
|
6940
7513
|
}
|
|
6941
|
-
})
|
|
7514
|
+
});
|
|
7515
|
+
await drainCondemnedChildren({
|
|
6942
7516
|
client: client,
|
|
6943
7517
|
instanceId: childId,
|
|
6944
7518
|
actor: actor,
|
|
@@ -6947,7 +7521,10 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6947
7521
|
clock: clock,
|
|
6948
7522
|
executionContext: executionContext,
|
|
6949
7523
|
telemetry: telemetry,
|
|
6950
|
-
draining: draining
|
|
7524
|
+
draining: draining,
|
|
7525
|
+
...result.fired ? {
|
|
7526
|
+
instance: result.instance
|
|
7527
|
+
} : {}
|
|
6951
7528
|
});
|
|
6952
7529
|
} catch (cause) {
|
|
6953
7530
|
if (cause instanceof invariants.InstanceNotFoundError) return;
|
|
@@ -6960,9 +7537,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6960
7537
|
}
|
|
6961
7538
|
|
|
6962
7539
|
async function stampDrainedRows({client: client, instance: instance, condemned: condemned, clock: clock, executionContext: executionContext}) {
|
|
6963
|
-
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)),
|
|
6964
|
-
ids: ids
|
|
6965
|
-
}), byId = new Map(children.map(c => [ invariants.assertReadableModel(c)._id, c ])), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
|
|
7540
|
+
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)), byId = await loadInstancesById(client, ids), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
|
|
6966
7541
|
if (row.resolved !== void 0 || !condemnedKeys.has(row._key)) return row;
|
|
6967
7542
|
const child = byId.get(invariants.toBareId(row.ref.id)), resolved = child !== void 0 ? terminalResolution(child) : {
|
|
6968
7543
|
at: now,
|
|
@@ -6984,6 +7559,16 @@ async function stampDrainedRows({client: client, instance: instance, condemned:
|
|
|
6984
7559
|
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
6985
7560
|
}
|
|
6986
7561
|
|
|
7562
|
+
async function loadInstancesById(client, ids) {
|
|
7563
|
+
const children = await client.fetch("*[_id in $ids]", {
|
|
7564
|
+
ids: ids
|
|
7565
|
+
});
|
|
7566
|
+
return new Map(children.filter(child => child._type === invariants.WORKFLOW_INSTANCE_TYPE).map(child => {
|
|
7567
|
+
const instance = readInstanceDoc(child);
|
|
7568
|
+
return [ instance._id, instance ];
|
|
7569
|
+
}));
|
|
7570
|
+
}
|
|
7571
|
+
|
|
6987
7572
|
function terminalResolution(child) {
|
|
6988
7573
|
const status = resolvedChildStatus(child);
|
|
6989
7574
|
if (!(status === void 0 || child.completedAt === void 0 || child.completedAt === null)) return {
|
|
@@ -7006,28 +7591,18 @@ function subworkflowResolvedEntry({row: row, at: at, status: status}) {
|
|
|
7006
7591
|
};
|
|
7007
7592
|
}
|
|
7008
7593
|
|
|
7009
|
-
async function propagateToAncestors(
|
|
7010
|
-
const loaded = await loadPropagationPair(
|
|
7011
|
-
if (loaded === void 0) return;
|
|
7012
|
-
const {child: child, parent: parent} = loaded, definition = invariants.parseDefinitionSnapshot(parent), ctx = await buildEngineContext({
|
|
7594
|
+
async function propagateToAncestors(args) {
|
|
7595
|
+
const {instance: instance, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, loaded = await loadPropagationPair({
|
|
7013
7596
|
client: client,
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
definition: definition,
|
|
7018
|
-
...clock ? {
|
|
7019
|
-
clock: clock
|
|
7020
|
-
} : {},
|
|
7021
|
-
...actor ? {
|
|
7022
|
-
actor: actor
|
|
7023
|
-
} : {},
|
|
7024
|
-
...executionContext ? {
|
|
7025
|
-
executionContext: executionContext
|
|
7026
|
-
} : {},
|
|
7027
|
-
...telemetry ? {
|
|
7028
|
-
telemetry: telemetry
|
|
7597
|
+
instanceId: instanceId,
|
|
7598
|
+
...instance !== void 0 ? {
|
|
7599
|
+
instance: instance
|
|
7029
7600
|
} : {}
|
|
7030
|
-
})
|
|
7601
|
+
});
|
|
7602
|
+
if (loaded === void 0) return;
|
|
7603
|
+
const {child: child, parent: parent} = loaded;
|
|
7604
|
+
if (stepArgs.settlingCohorts?.has(parent._id)) return;
|
|
7605
|
+
const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent), row = mutation.subworkflows.find(r => invariants.toBareId(r.ref.id) === child._id);
|
|
7031
7606
|
if (row === void 0) {
|
|
7032
7607
|
await recordOrphanedPropagation({
|
|
7033
7608
|
ctx: ctx,
|
|
@@ -7042,29 +7617,11 @@ async function propagateToAncestors({client: client, instanceId: instanceId, act
|
|
|
7042
7617
|
child: child,
|
|
7043
7618
|
now: ctx.now
|
|
7044
7619
|
}), parentTerminal = parent.completedAt !== void 0;
|
|
7045
|
-
changed && await persist(ctx, mutation), !parentTerminal &&
|
|
7046
|
-
client: client,
|
|
7047
|
-
instanceId: parent._id,
|
|
7048
|
-
actor: actor,
|
|
7049
|
-
clientForGdr: clientForGdr,
|
|
7050
|
-
refSurface: refSurface,
|
|
7051
|
-
clock: clock,
|
|
7052
|
-
executionContext: executionContext,
|
|
7053
|
-
telemetry: telemetry
|
|
7054
|
-
}), await propagateToAncestors({
|
|
7055
|
-
client: client,
|
|
7056
|
-
instanceId: parent._id,
|
|
7057
|
-
actor: actor,
|
|
7058
|
-
clientForGdr: clientForGdr,
|
|
7059
|
-
refSurface: refSurface,
|
|
7060
|
-
clock: clock,
|
|
7061
|
-
executionContext: executionContext,
|
|
7062
|
-
telemetry: telemetry
|
|
7063
|
-
}));
|
|
7620
|
+
changed && await persist(ctx, mutation), !parentTerminal && await cascadeAndPropagateParent(stepArgs, parent);
|
|
7064
7621
|
}
|
|
7065
7622
|
|
|
7066
|
-
async function loadPropagationPair(client, instanceId) {
|
|
7067
|
-
const child = await getInstanceDocument(client, instanceId);
|
|
7623
|
+
async function loadPropagationPair({client: client, instanceId: instanceId, instance: instance}) {
|
|
7624
|
+
const child = instance ?? await getInstanceDocument(client, instanceId);
|
|
7068
7625
|
if (!child) return;
|
|
7069
7626
|
const parentGdr = invariants.parentRef(child);
|
|
7070
7627
|
if (parentGdr === void 0) return;
|
|
@@ -7075,6 +7632,83 @@ async function loadPropagationPair(client, instanceId) {
|
|
|
7075
7632
|
};
|
|
7076
7633
|
}
|
|
7077
7634
|
|
|
7635
|
+
async function propagateSpawnBatch(args) {
|
|
7636
|
+
const {childIds: childIds, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, parent = await getInstanceDocument(client, instanceId);
|
|
7637
|
+
if (parent === void 0) return;
|
|
7638
|
+
const children = await loadInstancesById(client, childIds);
|
|
7639
|
+
if (children.size !== childIds.length) throw new Error(`Spawn batch for ${instanceId} could not reload every child`);
|
|
7640
|
+
const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent);
|
|
7641
|
+
stampSpawnBatch({
|
|
7642
|
+
mutation: mutation,
|
|
7643
|
+
parent: parent,
|
|
7644
|
+
children: children,
|
|
7645
|
+
childIds: childIds,
|
|
7646
|
+
now: ctx.now
|
|
7647
|
+
}) && await persist(ctx, mutation), parent.completedAt === void 0 && await cascadeAndPropagateParent(stepArgs, parent);
|
|
7648
|
+
}
|
|
7649
|
+
|
|
7650
|
+
async function buildCascadeStepContext(args, instance) {
|
|
7651
|
+
return buildEngineContext({
|
|
7652
|
+
client: args.client,
|
|
7653
|
+
clientForGdr: args.clientForGdr,
|
|
7654
|
+
refSurface: args.refSurface,
|
|
7655
|
+
instance: instance,
|
|
7656
|
+
definition: invariants.parseDefinitionSnapshot(instance),
|
|
7657
|
+
...args.clock ? {
|
|
7658
|
+
clock: args.clock
|
|
7659
|
+
} : {},
|
|
7660
|
+
...args.actor ? {
|
|
7661
|
+
actor: args.actor
|
|
7662
|
+
} : {},
|
|
7663
|
+
...args.executionContext ? {
|
|
7664
|
+
executionContext: args.executionContext
|
|
7665
|
+
} : {},
|
|
7666
|
+
...args.telemetry ? {
|
|
7667
|
+
telemetry: args.telemetry
|
|
7668
|
+
} : {},
|
|
7669
|
+
...args.settlingCohorts ? {
|
|
7670
|
+
settlingCohorts: args.settlingCohorts
|
|
7671
|
+
} : {}
|
|
7672
|
+
});
|
|
7673
|
+
}
|
|
7674
|
+
|
|
7675
|
+
async function cascadeAndPropagateParent(args, parent) {
|
|
7676
|
+
await cascadeAutoTransitions({
|
|
7677
|
+
...args,
|
|
7678
|
+
instanceId: parent._id
|
|
7679
|
+
}), await propagateToAncestors({
|
|
7680
|
+
...args,
|
|
7681
|
+
instanceId: parent._id
|
|
7682
|
+
});
|
|
7683
|
+
}
|
|
7684
|
+
|
|
7685
|
+
function stampSpawnBatch({mutation: mutation, parent: parent, children: children, childIds: childIds, now: now}) {
|
|
7686
|
+
let changed = !1;
|
|
7687
|
+
for (const childId of childIds) {
|
|
7688
|
+
const child = requireSpawnBatchChild({
|
|
7689
|
+
parent: parent,
|
|
7690
|
+
children: children,
|
|
7691
|
+
childId: childId
|
|
7692
|
+
}), row = mutation.subworkflows.find(entry => invariants.toBareId(entry.ref.id) === childId);
|
|
7693
|
+
if (row === void 0) throw new Error(`Spawn batch child ${childId} has no registry row on parent ${parent._id}`);
|
|
7694
|
+
changed = stampResolvedChild({
|
|
7695
|
+
mutation: mutation,
|
|
7696
|
+
row: row,
|
|
7697
|
+
child: child,
|
|
7698
|
+
now: now
|
|
7699
|
+
}) || changed;
|
|
7700
|
+
}
|
|
7701
|
+
return changed;
|
|
7702
|
+
}
|
|
7703
|
+
|
|
7704
|
+
function requireSpawnBatchChild({parent: parent, children: children, childId: childId}) {
|
|
7705
|
+
const child = children.get(childId);
|
|
7706
|
+
if (child === void 0) throw new Error(`Spawn batch child ${childId} disappeared`);
|
|
7707
|
+
const expectedParent = invariants.parentRef(child);
|
|
7708
|
+
if (expectedParent === void 0 || invariants.toBareId(expectedParent.id) !== parent._id) throw new Error(`Spawn batch child ${childId} does not belong to parent ${parent._id}`);
|
|
7709
|
+
return child;
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7078
7712
|
function stampResolvedChild({mutation: mutation, row: row, child: child, now: now}) {
|
|
7079
7713
|
if (row.resolved !== void 0) return !1;
|
|
7080
7714
|
const resolved = terminalResolution(child);
|
|
@@ -7210,36 +7844,14 @@ async function persist(ctx, mutation) {
|
|
|
7210
7844
|
for (const {body: body} of pendingCreates) tx.create(body);
|
|
7211
7845
|
tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
|
|
7212
7846
|
await tx.commit(), mutation.pendingCreates = [];
|
|
7213
|
-
const actorForPriming = ctx.actor;
|
|
7214
|
-
for (const {body: body
|
|
7215
|
-
|
|
7216
|
-
client: ctx.client,
|
|
7217
|
-
instanceId: body._id,
|
|
7218
|
-
actor: actorForPriming,
|
|
7219
|
-
clientForGdr: ctx.clientForGdr,
|
|
7220
|
-
refSurface: ctx.refSurface,
|
|
7221
|
-
clock: ctx.clock,
|
|
7222
|
-
executionContext: ctx.executionContext,
|
|
7223
|
-
telemetry: ctx.telemetry
|
|
7224
|
-
}), await cascadeAutoTransitions({
|
|
7225
|
-
client: ctx.client,
|
|
7226
|
-
instanceId: body._id,
|
|
7227
|
-
actor: actorForPriming,
|
|
7228
|
-
clientForGdr: ctx.clientForGdr,
|
|
7229
|
-
refSurface: ctx.refSurface,
|
|
7230
|
-
clock: ctx.clock,
|
|
7231
|
-
executionContext: ctx.executionContext,
|
|
7232
|
-
telemetry: ctx.telemetry
|
|
7233
|
-
}), await propagateToAncestors({
|
|
7234
|
-
client: ctx.client,
|
|
7847
|
+
const actorForPriming = ctx.actor, settlingCohorts = new Set(ctx.settlingCohorts).add(ctx.instance._id);
|
|
7848
|
+
for (const {body: body} of pendingCreates) try {
|
|
7849
|
+
const stepArgs = spawnStepArgs(ctx, {
|
|
7235
7850
|
instanceId: body._id,
|
|
7236
7851
|
actor: actorForPriming,
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
executionContext: ctx.executionContext,
|
|
7241
|
-
telemetry: ctx.telemetry
|
|
7242
|
-
}), ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7852
|
+
settlingCohorts: settlingCohorts
|
|
7853
|
+
});
|
|
7854
|
+
await primeInitialStage(stepArgs), await cascadeAutoTransitions(stepArgs);
|
|
7243
7855
|
} catch (cause) {
|
|
7244
7856
|
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7245
7857
|
instanceId: ctx.instance._id,
|
|
@@ -7247,11 +7859,50 @@ async function persist(ctx, mutation) {
|
|
|
7247
7859
|
reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
|
|
7248
7860
|
});
|
|
7249
7861
|
}
|
|
7862
|
+
await settleSpawnBatch(ctx, {
|
|
7863
|
+
pendingCreates: pendingCreates,
|
|
7864
|
+
actor: actorForPriming,
|
|
7865
|
+
settlingCohorts: settlingCohorts
|
|
7866
|
+
});
|
|
7867
|
+
for (const {started: started} of pendingCreates) ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7250
7868
|
const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
|
|
7251
7869
|
if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
|
|
7252
7870
|
return reloaded;
|
|
7253
7871
|
}
|
|
7254
7872
|
|
|
7873
|
+
async function settleSpawnBatch(ctx, args) {
|
|
7874
|
+
try {
|
|
7875
|
+
await propagateSpawnBatch({
|
|
7876
|
+
...spawnStepArgs(ctx, {
|
|
7877
|
+
instanceId: ctx.instance._id,
|
|
7878
|
+
actor: args.actor,
|
|
7879
|
+
settlingCohorts: args.settlingCohorts
|
|
7880
|
+
}),
|
|
7881
|
+
childIds: args.pendingCreates.map(({body: body}) => body._id)
|
|
7882
|
+
});
|
|
7883
|
+
} catch (cause) {
|
|
7884
|
+
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7885
|
+
instanceId: ctx.instance._id,
|
|
7886
|
+
guardError: cause,
|
|
7887
|
+
reason: "spawned children failed to propagate after the spawn transaction committed"
|
|
7888
|
+
});
|
|
7889
|
+
}
|
|
7890
|
+
}
|
|
7891
|
+
|
|
7892
|
+
function spawnStepArgs(ctx, args) {
|
|
7893
|
+
return {
|
|
7894
|
+
client: ctx.client,
|
|
7895
|
+
instanceId: args.instanceId,
|
|
7896
|
+
actor: args.actor,
|
|
7897
|
+
clientForGdr: ctx.clientForGdr,
|
|
7898
|
+
refSurface: ctx.refSurface,
|
|
7899
|
+
clock: ctx.clock,
|
|
7900
|
+
executionContext: ctx.executionContext,
|
|
7901
|
+
telemetry: ctx.telemetry,
|
|
7902
|
+
settlingCohorts: args.settlingCohorts ?? ctx.settlingCohorts
|
|
7903
|
+
};
|
|
7904
|
+
}
|
|
7905
|
+
|
|
7255
7906
|
function stampExecutionContext(ctx, mutation) {
|
|
7256
7907
|
const stamp = ctx.executionContext, appended = mutation.history.slice(ctx.instance.history.length);
|
|
7257
7908
|
mutation.history = [ ...mutation.history.slice(0, ctx.instance.history.length), ...stampHistoryEntries(appended, stamp) ];
|
|
@@ -7379,24 +8030,25 @@ function buildEffectSettlement(pending, outcome) {
|
|
|
7379
8030
|
}
|
|
7380
8031
|
|
|
7381
8032
|
function validateEffectOutputs(args) {
|
|
7382
|
-
const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [];
|
|
8033
|
+
const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [], normalized = {};
|
|
7383
8034
|
for (const [key, value] of Object.entries(outputs)) {
|
|
7384
8035
|
const shape = byName.get(key);
|
|
7385
8036
|
if (shape === void 0) {
|
|
7386
8037
|
issues.push(`"${key}" is not a declared output`);
|
|
7387
8038
|
continue;
|
|
7388
8039
|
}
|
|
7389
|
-
const
|
|
7390
|
-
|
|
8040
|
+
const check = effectOutputCheck(shape, value);
|
|
8041
|
+
"issues" in check ? issues.push(...check.issues.map(i => `"${key}": ${i}`)) : normalized[key] = check.output;
|
|
7391
8042
|
}
|
|
7392
8043
|
if (issues.length > 0) throw new EffectOutputsInvalidError({
|
|
7393
8044
|
effect: effectName,
|
|
7394
8045
|
issues: issues
|
|
7395
8046
|
});
|
|
8047
|
+
return normalized;
|
|
7396
8048
|
}
|
|
7397
8049
|
|
|
7398
|
-
function
|
|
7399
|
-
return invariants.
|
|
8050
|
+
function effectOutputCheck(shape, value) {
|
|
8051
|
+
return invariants.parseFieldValue({
|
|
7400
8052
|
entryType: shape.type,
|
|
7401
8053
|
value: value,
|
|
7402
8054
|
...shape.fields !== void 0 ? {
|
|
@@ -7442,15 +8094,15 @@ function validateCompletionInput({pending: pending, definition: definition, stat
|
|
|
7442
8094
|
effect: pending.name,
|
|
7443
8095
|
issues: [ "outputs cannot accompany a failed completion — report outputs on a done completion instead" ]
|
|
7444
8096
|
});
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
8097
|
+
const normalizedOutputs = outputs !== void 0 ? validateEffectOutputs({
|
|
8098
|
+
outputs: outputs,
|
|
8099
|
+
declared: findEffect(definition, pending.name)?.outputs ?? [],
|
|
8100
|
+
effectName: pending.name
|
|
8101
|
+
}) : void 0;
|
|
8102
|
+
return {
|
|
8103
|
+
ops: ops !== void 0 ? validateEffectOps(ops, pending.name) : [],
|
|
8104
|
+
outputs: normalizedOutputs
|
|
8105
|
+
};
|
|
7454
8106
|
}
|
|
7455
8107
|
|
|
7456
8108
|
async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, actor: actor}) {
|
|
@@ -7459,7 +8111,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7459
8111
|
record: requestRecord,
|
|
7460
8112
|
now: ctx.now
|
|
7461
8113
|
});
|
|
7462
|
-
const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
|
|
8114
|
+
const pending = requirePendingEffect(ctx.instance, effectKey), {ops: validatedOps, outputs: validatedOutputs} = validateCompletionInput({
|
|
7463
8115
|
pending: pending,
|
|
7464
8116
|
definition: ctx.definition,
|
|
7465
8117
|
status: status,
|
|
@@ -7478,7 +8130,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7478
8130
|
detail: detail,
|
|
7479
8131
|
error: error,
|
|
7480
8132
|
durationMs: durationMs,
|
|
7481
|
-
outputs:
|
|
8133
|
+
outputs: validatedOutputs
|
|
7482
8134
|
});
|
|
7483
8135
|
mutation.effectHistory.push(settlement.run);
|
|
7484
8136
|
const wroteEffectOutputs = status === "done" && outputs !== void 0;
|
|
@@ -7676,6 +8328,64 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
|
|
|
7676
8328
|
};
|
|
7677
8329
|
}
|
|
7678
8330
|
|
|
8331
|
+
const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
|
|
8332
|
+
|
|
8333
|
+
function isResetActivityTarget(value) {
|
|
8334
|
+
return RESET_ACTIVITY_TARGETS.includes(value);
|
|
8335
|
+
}
|
|
8336
|
+
|
|
8337
|
+
async function resetActivity(args) {
|
|
8338
|
+
const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
|
|
8339
|
+
client: client,
|
|
8340
|
+
instanceId: instanceId,
|
|
8341
|
+
options: options
|
|
8342
|
+
});
|
|
8343
|
+
return commitResetActivity({
|
|
8344
|
+
ctx: ctx,
|
|
8345
|
+
activity: activity,
|
|
8346
|
+
to: to,
|
|
8347
|
+
requestRecord: requestRecord,
|
|
8348
|
+
actor: options?.actor
|
|
8349
|
+
});
|
|
8350
|
+
}
|
|
8351
|
+
|
|
8352
|
+
async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
|
|
8353
|
+
if (assertRequestUnprocessed({
|
|
8354
|
+
instance: ctx.instance,
|
|
8355
|
+
record: requestRecord,
|
|
8356
|
+
now: ctx.now
|
|
8357
|
+
}), isTerminal(ctx)) return {
|
|
8358
|
+
fired: !1
|
|
8359
|
+
};
|
|
8360
|
+
const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
|
|
8361
|
+
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}"`);
|
|
8362
|
+
const from = entry.status;
|
|
8363
|
+
if (from === to) return {
|
|
8364
|
+
fired: !1
|
|
8365
|
+
};
|
|
8366
|
+
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.`);
|
|
8367
|
+
return recordProcessedRequest({
|
|
8368
|
+
mutation: mutation,
|
|
8369
|
+
record: requestRecord,
|
|
8370
|
+
now: ctx.now
|
|
8371
|
+
}), applyActivityStatusChange({
|
|
8372
|
+
entry: entry,
|
|
8373
|
+
history: mutation.history,
|
|
8374
|
+
stage: openStage2.name,
|
|
8375
|
+
to: to,
|
|
8376
|
+
at: ctx.now,
|
|
8377
|
+
...actor !== void 0 ? {
|
|
8378
|
+
actor: actor
|
|
8379
|
+
} : {}
|
|
8380
|
+
}), await persist(ctx, mutation), {
|
|
8381
|
+
fired: !0,
|
|
8382
|
+
stage: openStage2.name,
|
|
8383
|
+
activity: activity,
|
|
8384
|
+
from: from,
|
|
8385
|
+
to: to
|
|
8386
|
+
};
|
|
8387
|
+
}
|
|
8388
|
+
|
|
7679
8389
|
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
|
|
7680
8390
|
|
|
7681
8391
|
async function resolveAccess(taggedClient, args = {}) {
|
|
@@ -7685,10 +8395,13 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7685
8395
|
client: client,
|
|
7686
8396
|
requestFn: requestFn,
|
|
7687
8397
|
resourcePath: args.grantsFromPath
|
|
7688
|
-
}) : Promise.resolve(void 0), [
|
|
7689
|
-
if (
|
|
8398
|
+
}) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
8399
|
+
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.");
|
|
7690
8400
|
return {
|
|
7691
|
-
actor: actor,
|
|
8401
|
+
actor: identity.actor,
|
|
8402
|
+
...identity.localPrincipalId !== void 0 ? {
|
|
8403
|
+
localPrincipalId: identity.localPrincipalId
|
|
8404
|
+
} : {},
|
|
7692
8405
|
...grants !== void 0 ? {
|
|
7693
8406
|
grants: grants
|
|
7694
8407
|
} : {}
|
|
@@ -7698,7 +8411,7 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7698
8411
|
function cachedActor(client, requestFn) {
|
|
7699
8412
|
const cached = actorCache.get(client);
|
|
7700
8413
|
if (cached !== void 0) return cached;
|
|
7701
|
-
const pending = fetchActor(requestFn).catch(err => {
|
|
8414
|
+
const pending = fetchActor(client, requestFn).catch(err => {
|
|
7702
8415
|
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
7703
8416
|
});
|
|
7704
8417
|
return actorCache.set(client, pending), pending;
|
|
@@ -7725,27 +8438,90 @@ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resou
|
|
|
7725
8438
|
byPath.set(resourcePath, cached)), cached;
|
|
7726
8439
|
}
|
|
7727
8440
|
|
|
7728
|
-
async function fetchActor(requestFn) {
|
|
7729
|
-
|
|
8441
|
+
async function fetchActor(client, requestFn) {
|
|
8442
|
+
const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalId = usableId(globalUser.user), id = globalId ?? resourceId;
|
|
8443
|
+
if (id === void 0) return;
|
|
8444
|
+
refuseProjectPrincipalWithoutGlobal({
|
|
8445
|
+
resourceId: resourceId,
|
|
8446
|
+
globalId: globalId,
|
|
8447
|
+
globalUser: globalUser
|
|
8448
|
+
});
|
|
8449
|
+
const roleNames = (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
8450
|
+
return {
|
|
8451
|
+
actor: {
|
|
8452
|
+
kind: "person",
|
|
8453
|
+
id: id,
|
|
8454
|
+
...roleNames.length > 0 ? {
|
|
8455
|
+
roles: roleNames
|
|
8456
|
+
} : {}
|
|
8457
|
+
},
|
|
8458
|
+
...resourceId !== void 0 && resourceId !== id ? {
|
|
8459
|
+
localPrincipalId: resourceId
|
|
8460
|
+
} : {}
|
|
8461
|
+
};
|
|
8462
|
+
}
|
|
8463
|
+
|
|
8464
|
+
function refuseProjectPrincipalWithoutGlobal(args) {
|
|
8465
|
+
const {resourceId: resourceId, globalId: globalId, globalUser: globalUser} = args;
|
|
8466
|
+
if (globalId !== void 0 || resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project") return;
|
|
8467
|
+
const reason = "reason" in globalUser ? globalUser.reason : "no record";
|
|
8468
|
+
throw new Error(`workflow: the caller's identity on the workflow resource host is project-scoped ("${resourceId}") and the account-global record could not be resolved (${reason}). The engine speaks account-global user ids only and never acts as a project-scoped principal.`, "cause" in globalUser ? {
|
|
8469
|
+
cause: globalUser.cause
|
|
8470
|
+
} : void 0);
|
|
8471
|
+
}
|
|
8472
|
+
|
|
8473
|
+
function usableId(user) {
|
|
8474
|
+
if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
|
|
8475
|
+
}
|
|
8476
|
+
|
|
8477
|
+
async function fetchCurrentUser(requestFn, hostDescription) {
|
|
7730
8478
|
try {
|
|
7731
|
-
|
|
8479
|
+
return await requestFn({
|
|
7732
8480
|
uri: "/users/me",
|
|
7733
8481
|
tag: REQUEST_TAG.accessResolveActor
|
|
7734
8482
|
});
|
|
7735
8483
|
} catch (err) {
|
|
7736
|
-
throw new Error(
|
|
8484
|
+
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.`, {
|
|
7737
8485
|
cause: err
|
|
7738
8486
|
});
|
|
7739
8487
|
}
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
8488
|
+
}
|
|
8489
|
+
|
|
8490
|
+
async function fetchGlobalUser(client) {
|
|
8491
|
+
if (typeof client.withConfig != "function") return {
|
|
8492
|
+
user: void 0,
|
|
8493
|
+
reason: "the client cannot reach the global API host (no withConfig)"
|
|
8494
|
+
};
|
|
8495
|
+
let globalRequest, globalClient;
|
|
8496
|
+
try {
|
|
8497
|
+
globalClient = client.withConfig({
|
|
8498
|
+
useProjectHostname: !1
|
|
8499
|
+
}), globalRequest = lazyRequest(globalClient);
|
|
8500
|
+
} catch (err) {
|
|
8501
|
+
return {
|
|
8502
|
+
user: void 0,
|
|
8503
|
+
reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
|
|
8504
|
+
cause: err
|
|
8505
|
+
};
|
|
8506
|
+
}
|
|
8507
|
+
if (globalRequest === void 0) return {
|
|
8508
|
+
user: void 0,
|
|
8509
|
+
reason: "the global-host sibling client cannot issue requests"
|
|
7748
8510
|
};
|
|
8511
|
+
try {
|
|
8512
|
+
return {
|
|
8513
|
+
user: await globalRequest({
|
|
8514
|
+
uri: "/users/me",
|
|
8515
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
8516
|
+
})
|
|
8517
|
+
};
|
|
8518
|
+
} catch (err) {
|
|
8519
|
+
return {
|
|
8520
|
+
user: void 0,
|
|
8521
|
+
reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
|
|
8522
|
+
cause: err
|
|
8523
|
+
};
|
|
8524
|
+
}
|
|
7749
8525
|
}
|
|
7750
8526
|
|
|
7751
8527
|
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
@@ -7921,12 +8697,25 @@ async function subjectResourceGrants(args) {
|
|
|
7921
8697
|
const resolved = await Promise.all([ ...clients.entries() ].map(async ([key, entry]) => {
|
|
7922
8698
|
const path = aclPathForResource(entry.resource);
|
|
7923
8699
|
if (path === void 0) return;
|
|
7924
|
-
const grants = await grantsForClientPath(entry.client, path);
|
|
7925
|
-
|
|
8700
|
+
const [grants, actorId] = await Promise.all([ grantsForClientPath(entry.client, path), resourceActorId(entry.client) ]);
|
|
8701
|
+
if (!(grants === void 0 || actorId === void 0)) return [ key, {
|
|
8702
|
+
grants: grants,
|
|
8703
|
+
actorId: actorId
|
|
8704
|
+
} ];
|
|
7926
8705
|
}));
|
|
7927
8706
|
return new Map(resolved.filter(entry => entry !== void 0));
|
|
7928
8707
|
}
|
|
7929
8708
|
|
|
8709
|
+
async function resourceActorId(client) {
|
|
8710
|
+
try {
|
|
8711
|
+
const access = await resolveAccess(client);
|
|
8712
|
+
return invariants.lakePrincipalId(access);
|
|
8713
|
+
} catch (err) {
|
|
8714
|
+
console.warn(`workflow: failed to resolve the actor identity on a subject resource; the subject-write forecast omits this resource (degrade open — the lake still enforces writes). Original error: ${invariants.errorMessage(err)}`);
|
|
8715
|
+
return;
|
|
8716
|
+
}
|
|
8717
|
+
}
|
|
8718
|
+
|
|
7930
8719
|
async function evaluateInstance(args) {
|
|
7931
8720
|
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
7932
8721
|
invariants.validateTag(tag);
|
|
@@ -7938,7 +8727,7 @@ async function evaluateInstance(args) {
|
|
|
7938
8727
|
client: client,
|
|
7939
8728
|
instanceId: instanceId,
|
|
7940
8729
|
tag: tag
|
|
7941
|
-
}) ]), {actor: actor, grants: grants} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
8730
|
+
}) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7942
8731
|
client: client,
|
|
7943
8732
|
workflowResource: workflowResource,
|
|
7944
8733
|
resourceClients: resourceClients
|
|
@@ -7958,6 +8747,9 @@ async function evaluateInstance(args) {
|
|
|
7958
8747
|
guards: guards,
|
|
7959
8748
|
now: now,
|
|
7960
8749
|
resourceGrants: resourceGrants,
|
|
8750
|
+
...localPrincipalId !== void 0 ? {
|
|
8751
|
+
localPrincipalId: localPrincipalId
|
|
8752
|
+
} : {},
|
|
7961
8753
|
...grants !== void 0 ? {
|
|
7962
8754
|
grants: grants
|
|
7963
8755
|
} : {}
|
|
@@ -8013,9 +8805,12 @@ async function evaluateFromSnapshot(args) {
|
|
|
8013
8805
|
definition: definition,
|
|
8014
8806
|
snapshot: snapshot,
|
|
8015
8807
|
now: now
|
|
8016
|
-
},
|
|
8017
|
-
instance: instance,
|
|
8808
|
+
}, anchorIdentity = invariants.lakePrincipalId({
|
|
8018
8809
|
actor: actor,
|
|
8810
|
+
localPrincipalId: args.localPrincipalId
|
|
8811
|
+
}), can = await advisoryCan({
|
|
8812
|
+
instance: instance,
|
|
8813
|
+
identity: anchorIdentity,
|
|
8019
8814
|
grants: grants
|
|
8020
8815
|
}), scope = await renderConditionScope(scopeSource, {
|
|
8021
8816
|
actor: actor,
|
|
@@ -8032,11 +8827,10 @@ async function evaluateFromSnapshot(args) {
|
|
|
8032
8827
|
activityName: activityName
|
|
8033
8828
|
})), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
|
|
8034
8829
|
instance: instance,
|
|
8035
|
-
|
|
8830
|
+
identity: anchorIdentity,
|
|
8036
8831
|
guards: args.guards
|
|
8037
8832
|
}), subjectDenials = await forecastSubjectDenials({
|
|
8038
8833
|
instance: instance,
|
|
8039
|
-
actor: actor,
|
|
8040
8834
|
snapshot: snapshot,
|
|
8041
8835
|
resourceGrants: args.resourceGrants
|
|
8042
8836
|
}), subjectPermissionReason = subjectDenials.length > 0 ? {
|
|
@@ -8180,20 +8974,20 @@ async function editPredicateInsight(args) {
|
|
|
8180
8974
|
}
|
|
8181
8975
|
|
|
8182
8976
|
async function forecastSubjectDenials(args) {
|
|
8183
|
-
const {instance: instance,
|
|
8977
|
+
const {instance: instance, snapshot: snapshot, resourceGrants: resourceGrants} = args;
|
|
8184
8978
|
if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
|
|
8185
8979
|
const denials = [], seen = /* @__PURE__ */ new Set;
|
|
8186
8980
|
for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
|
|
8187
8981
|
if (seen.has(ref.id)) continue;
|
|
8188
8982
|
seen.add(ref.id);
|
|
8189
|
-
const
|
|
8190
|
-
if (
|
|
8983
|
+
const access = resourceGrants.get(invariants.resourceGdr(resource));
|
|
8984
|
+
if (access === void 0) continue;
|
|
8191
8985
|
const doc = snapshot.docs.find(d => d._id === ref.id);
|
|
8192
8986
|
doc !== void 0 && await subjectUpdateAllowed({
|
|
8193
8987
|
doc: doc,
|
|
8194
8988
|
parsed: parsed,
|
|
8195
|
-
grants: grants,
|
|
8196
|
-
actorId:
|
|
8989
|
+
grants: access.grants,
|
|
8990
|
+
actorId: access.actorId
|
|
8197
8991
|
}) === !1 && denials.push({
|
|
8198
8992
|
subject: ref.id,
|
|
8199
8993
|
resource: invariants.resourceGdr(resource),
|
|
@@ -8274,12 +9068,12 @@ async function explainActivityConditions({activity: activity, activityScope: act
|
|
|
8274
9068
|
snapshot: snapshot,
|
|
8275
9069
|
sites: sites
|
|
8276
9070
|
}), requirementEntries = [];
|
|
8277
|
-
for (const
|
|
9071
|
+
for (const requirement of activity.requirements ?? []) requirementEntries.push([ requirement, await explainAt({
|
|
8278
9072
|
kind: "requirement",
|
|
8279
9073
|
activity: activity.name,
|
|
8280
|
-
requirement: name
|
|
8281
|
-
},
|
|
8282
|
-
const requirementInsights = Object.fromEntries(requirementEntries), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([
|
|
9074
|
+
requirement: requirement.name
|
|
9075
|
+
}, requirement.query) ]);
|
|
9076
|
+
const requirementInsights = Object.fromEntries(requirementEntries.map(([requirement, insight]) => [ requirement.name, insight ])), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([requirement]) => requirementDescriptor(requirement)), filterInsight = activity.filter !== void 0 ? await explainSite({
|
|
8283
9077
|
site: {
|
|
8284
9078
|
kind: "activity-filter",
|
|
8285
9079
|
activity: activity.name
|
|
@@ -8425,12 +9219,12 @@ function actionEvaluationIdentity(action) {
|
|
|
8425
9219
|
};
|
|
8426
9220
|
}
|
|
8427
9221
|
|
|
8428
|
-
async function instanceGuardReason({instance: instance,
|
|
9222
|
+
async function instanceGuardReason({instance: instance, identity: identity, guards: guards}) {
|
|
8429
9223
|
if (guards === void 0 || guards.length === 0) return;
|
|
8430
9224
|
const denied = await instanceWriteDenials({
|
|
8431
9225
|
instance: instance,
|
|
8432
9226
|
guards: guards,
|
|
8433
|
-
identity:
|
|
9227
|
+
identity: identity
|
|
8434
9228
|
});
|
|
8435
9229
|
if (denied.length !== 0) return {
|
|
8436
9230
|
kind: "mutation-guard-denied",
|
|
@@ -8469,12 +9263,12 @@ function inFlightFilter() {
|
|
|
8469
9263
|
return "!defined(completedAt)";
|
|
8470
9264
|
}
|
|
8471
9265
|
|
|
8472
|
-
const FIELD_REFS_DOC = "count(fields[value.id in $documents]) > 0 || count(fields[count(value[id in $documents]) > 0]) > 0",
|
|
9266
|
+
const FIELD_REFS_DOC = "count(fields[value.id in $documents]) > 0 || count(fields[count(value[id in $documents]) > 0]) > 0", OPEN_STAGE_REFS_DOC = `count(stages[!defined(exitedAt) && (${FIELD_REFS_DOC} || count(activities[${FIELD_REFS_DOC}]) > 0)]) > 0`, LIVE_SUBWORKFLOW_REFS_DOC = "count(subworkflows[!defined(resolved) && ref.id in $documents]) > 0";
|
|
8473
9267
|
|
|
8474
9268
|
function documentPrefilter(documents, params) {
|
|
8475
9269
|
for (const document of documents) if (!invariants.isGdrUri(document)) throw new invariants.ContractViolationError(`every document must be a resource-qualified GDR URI (e.g. "dataset:project:dataset:doc-id"); got: ${JSON.stringify(document)}`);
|
|
8476
9270
|
return params.documents = [ ...documents ], params.bareIds = documents.map(invariants.extractDocumentId),
|
|
8477
|
-
`_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${
|
|
9271
|
+
`_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${LIVE_SUBWORKFLOW_REFS_DOC} || ${FIELD_REFS_DOC} || ${OPEN_STAGE_REFS_DOC}`;
|
|
8478
9272
|
}
|
|
8479
9273
|
|
|
8480
9274
|
function documentArm(filter, params) {
|
|
@@ -8900,11 +9694,10 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
|
|
|
8900
9694
|
}
|
|
8901
9695
|
|
|
8902
9696
|
async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
|
|
8903
|
-
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can =
|
|
9697
|
+
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
|
|
8904
9698
|
instance: ctx.instance,
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
}) : void 0, predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
|
|
9699
|
+
options: options
|
|
9700
|
+
}), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
|
|
8908
9701
|
ctx: ctx,
|
|
8909
9702
|
condition: site.effective,
|
|
8910
9703
|
opts: {
|
|
@@ -9262,8 +10055,7 @@ async function abortAndPropagate(args) {
|
|
|
9262
10055
|
executionContext: executionContext,
|
|
9263
10056
|
telemetry: telemetry
|
|
9264
10057
|
})
|
|
9265
|
-
})
|
|
9266
|
-
return await drainCondemnedChildren({
|
|
10058
|
+
}), drained = await drainCondemnedChildren({
|
|
9267
10059
|
client: client,
|
|
9268
10060
|
instanceId: instanceId,
|
|
9269
10061
|
actor: actor,
|
|
@@ -9275,8 +10067,12 @@ async function abortAndPropagate(args) {
|
|
|
9275
10067
|
} : {},
|
|
9276
10068
|
...telemetry !== void 0 ? {
|
|
9277
10069
|
telemetry: telemetry
|
|
10070
|
+
} : {},
|
|
10071
|
+
...result.fired ? {
|
|
10072
|
+
instance: result.instance
|
|
9278
10073
|
} : {}
|
|
9279
|
-
})
|
|
10074
|
+
});
|
|
10075
|
+
return await propagateToAncestors({
|
|
9280
10076
|
client: client,
|
|
9281
10077
|
instanceId: instanceId,
|
|
9282
10078
|
actor: actor,
|
|
@@ -9288,6 +10084,9 @@ async function abortAndPropagate(args) {
|
|
|
9288
10084
|
} : {},
|
|
9289
10085
|
...telemetry !== void 0 ? {
|
|
9290
10086
|
telemetry: telemetry
|
|
10087
|
+
} : {},
|
|
10088
|
+
...result.fired && !drained.drained ? {
|
|
10089
|
+
instance: drained.instance
|
|
9291
10090
|
} : {}
|
|
9292
10091
|
}), result.fired;
|
|
9293
10092
|
}
|
|
@@ -9395,6 +10194,9 @@ function buildEngineCallOptions(args) {
|
|
|
9395
10194
|
actor: args.actor,
|
|
9396
10195
|
clientForGdr: args.clientForGdr,
|
|
9397
10196
|
refSurface: args.refSurface,
|
|
10197
|
+
...args.localPrincipalId !== void 0 ? {
|
|
10198
|
+
localPrincipalId: args.localPrincipalId
|
|
10199
|
+
} : {},
|
|
9398
10200
|
...args.grants !== void 0 ? {
|
|
9399
10201
|
grants: args.grants
|
|
9400
10202
|
} : {},
|
|
@@ -9536,6 +10338,15 @@ async function abortInstances(args) {
|
|
|
9536
10338
|
return aborted;
|
|
9537
10339
|
}
|
|
9538
10340
|
|
|
10341
|
+
function projectStartSliceRow(instance) {
|
|
10342
|
+
const subject = (instance.fields ?? []).find(field => field._type === "subject")?.value;
|
|
10343
|
+
return {
|
|
10344
|
+
definition: instance.definition,
|
|
10345
|
+
subject: typeof subject == "object" && subject !== null && "id" in subject && invariants.isGdrUri(subject.id) ? subject.id : null,
|
|
10346
|
+
completedAt: instance.completedAt ?? null
|
|
10347
|
+
};
|
|
10348
|
+
}
|
|
10349
|
+
|
|
9539
10350
|
async function fetchStartSlice(args) {
|
|
9540
10351
|
const {client: client, tag: tag} = args, {query: query, params: params} = instancesQuery({
|
|
9541
10352
|
tag: tag,
|
|
@@ -9543,7 +10354,7 @@ async function fetchStartSlice(args) {
|
|
|
9543
10354
|
includeCompleted: !0
|
|
9544
10355
|
}
|
|
9545
10356
|
});
|
|
9546
|
-
return (await client.fetch(query, params)).map(invariants.assertReadableModel);
|
|
10357
|
+
return (await client.fetch(query, params)).map(invariants.assertReadableModel).map(projectStartSliceRow);
|
|
9547
10358
|
}
|
|
9548
10359
|
|
|
9549
10360
|
const workflow = {
|
|
@@ -9692,6 +10503,9 @@ const workflow = {
|
|
|
9692
10503
|
...access.grants !== void 0 ? {
|
|
9693
10504
|
grants: access.grants
|
|
9694
10505
|
} : {},
|
|
10506
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10507
|
+
localPrincipalId: access.localPrincipalId
|
|
10508
|
+
} : {},
|
|
9695
10509
|
clock: clock,
|
|
9696
10510
|
clientForGdr: clientForGdr,
|
|
9697
10511
|
refSurface: refSurface,
|
|
@@ -9760,6 +10574,9 @@ const workflow = {
|
|
|
9760
10574
|
...access.grants !== void 0 ? {
|
|
9761
10575
|
grants: access.grants
|
|
9762
10576
|
} : {},
|
|
10577
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10578
|
+
localPrincipalId: access.localPrincipalId
|
|
10579
|
+
} : {},
|
|
9763
10580
|
clock: clock,
|
|
9764
10581
|
clientForGdr: clientForGdr,
|
|
9765
10582
|
refSurface: refSurface,
|
|
@@ -9919,7 +10736,7 @@ const workflow = {
|
|
|
9919
10736
|
});
|
|
9920
10737
|
},
|
|
9921
10738
|
tick: async rawArgs => {
|
|
9922
|
-
const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, current = await reload({
|
|
10739
|
+
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({
|
|
9923
10740
|
client: client,
|
|
9924
10741
|
instanceId: instanceId,
|
|
9925
10742
|
tag: tag
|
|
@@ -9927,7 +10744,7 @@ const workflow = {
|
|
|
9927
10744
|
await assertInstanceWriteAllowed({
|
|
9928
10745
|
instance: current,
|
|
9929
10746
|
guards: guards,
|
|
9930
|
-
identity:
|
|
10747
|
+
identity: invariants.lakePrincipalId(access)
|
|
9931
10748
|
});
|
|
9932
10749
|
const {cascaded: cascaded, instance: instance} = await cascadeAndReload({
|
|
9933
10750
|
client: client,
|
|
@@ -10044,6 +10861,59 @@ const workflow = {
|
|
|
10044
10861
|
}
|
|
10045
10862
|
});
|
|
10046
10863
|
},
|
|
10864
|
+
resetActivity: async rawArgs => {
|
|
10865
|
+
const args = taggedScope(rawArgs, REQUEST_TAG.resetActivity), {client: client, tag: tag, instanceId: instanceId, activity: activity, executionContext: executionContext} = args, to = args.to ?? "active";
|
|
10866
|
+
if (!isResetActivityTarget(to)) throw new invariants.ContractViolationError(`resetActivity: "to" must be "active" or "skipped"; got ${JSON.stringify(args.to)}`);
|
|
10867
|
+
return runCommitVerb({
|
|
10868
|
+
args: args,
|
|
10869
|
+
op: "resetActivity",
|
|
10870
|
+
run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
|
|
10871
|
+
const result = await resetActivity({
|
|
10872
|
+
client: client,
|
|
10873
|
+
instanceId: instanceId,
|
|
10874
|
+
activity: activity,
|
|
10875
|
+
to: to,
|
|
10876
|
+
...record !== void 0 ? {
|
|
10877
|
+
requestRecord: record
|
|
10878
|
+
} : {},
|
|
10879
|
+
options: engineOptionsForActor({
|
|
10880
|
+
actor: actor,
|
|
10881
|
+
clock: clock,
|
|
10882
|
+
clientForGdr: clientForGdr,
|
|
10883
|
+
refSurface: refSurface,
|
|
10884
|
+
executionContext: executionContext,
|
|
10885
|
+
telemetry: args.telemetry
|
|
10886
|
+
})
|
|
10887
|
+
}), cascaded = result.fired ? await cascade({
|
|
10888
|
+
client: client,
|
|
10889
|
+
instanceId: instanceId,
|
|
10890
|
+
actor: actor,
|
|
10891
|
+
clientForGdr: clientForGdr,
|
|
10892
|
+
refSurface: refSurface,
|
|
10893
|
+
clock: clock,
|
|
10894
|
+
...executionContext !== void 0 ? {
|
|
10895
|
+
executionContext: executionContext
|
|
10896
|
+
} : {},
|
|
10897
|
+
...args.telemetry !== void 0 ? {
|
|
10898
|
+
telemetry: args.telemetry
|
|
10899
|
+
} : {}
|
|
10900
|
+
}) : 0;
|
|
10901
|
+
return resolveTelemetry(args.telemetry).log(WorkflowActivityReset, {
|
|
10902
|
+
...definitionHashFragment(before.pinnedContentHash),
|
|
10903
|
+
instanceId: instanceId,
|
|
10904
|
+
changed: result.fired
|
|
10905
|
+
}), {
|
|
10906
|
+
instance: await reload({
|
|
10907
|
+
client: client,
|
|
10908
|
+
instanceId: instanceId,
|
|
10909
|
+
tag: tag
|
|
10910
|
+
}),
|
|
10911
|
+
cascaded: cascaded,
|
|
10912
|
+
changed: result.fired
|
|
10913
|
+
};
|
|
10914
|
+
}
|
|
10915
|
+
});
|
|
10916
|
+
},
|
|
10047
10917
|
getInstance: async rawArgs => {
|
|
10048
10918
|
const args = taggedScope(rawArgs, REQUEST_TAG.getInstance), {client: client, tag: tag, instanceId: instanceId} = args;
|
|
10049
10919
|
return invariants.validateTag(tag), reload({
|
|
@@ -10190,21 +11060,18 @@ const workflow = {
|
|
|
10190
11060
|
return (await client.fetch(query, params)).map(readInstanceDoc).filter(instance => instanceWatchesDocument(instance, document));
|
|
10191
11061
|
},
|
|
10192
11062
|
definitionsForDocument: async rawArgs => {
|
|
10193
|
-
const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document
|
|
11063
|
+
const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document} = args;
|
|
10194
11064
|
invariants.validateTag(tag);
|
|
10195
|
-
const clock = args.clock ?? wallClock, deployed = (await client.fetch(
|
|
11065
|
+
const clock = args.clock ?? wallClock, deployed = (await client.fetch(latestDefinitionsGroq(), {
|
|
10196
11066
|
tag: tag
|
|
10197
|
-
})).map(invariants.assertReadableModel)
|
|
11067
|
+
})).map(invariants.assertReadableModel);
|
|
10198
11068
|
let slice;
|
|
10199
11069
|
return applicableDefinitions({
|
|
10200
|
-
definitions:
|
|
11070
|
+
definitions: deployed,
|
|
10201
11071
|
document: document,
|
|
10202
11072
|
scope: {
|
|
10203
11073
|
tag: tag,
|
|
10204
11074
|
now: clock(),
|
|
10205
|
-
...subject !== void 0 ? {
|
|
10206
|
-
subject: subject
|
|
10207
|
-
} : {},
|
|
10208
11075
|
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10209
11076
|
client: client,
|
|
10210
11077
|
tag: tag
|
|
@@ -10227,34 +11094,17 @@ const workflow = {
|
|
|
10227
11094
|
}), missingRequired = missingRequiredInputs({
|
|
10228
11095
|
entryDefs: definition.fields ?? [],
|
|
10229
11096
|
initialFields: initialFields ?? []
|
|
10230
|
-
}),
|
|
10231
|
-
if (allowed === void 0) return {
|
|
10232
|
-
allowed: invalidInitialFields.length === 0,
|
|
10233
|
-
outcome: "satisfied",
|
|
10234
|
-
unboundReads: [],
|
|
10235
|
-
missingRequired: missingRequired,
|
|
10236
|
-
invalidInitialFields: invalidInitialFields
|
|
10237
|
-
};
|
|
10238
|
-
const unboundReads = unboundAllowedReadsWithSubject({
|
|
10239
|
-
allowed: allowed,
|
|
10240
|
-
fields: startFieldsParam({
|
|
10241
|
-
entryDefs: definition.fields ?? [],
|
|
10242
|
-
initialFields: initialFields ?? []
|
|
10243
|
-
}),
|
|
10244
|
-
definition: definition
|
|
10245
|
-
}), insight = await startAllowedInsight({
|
|
11097
|
+
}), verdict = await startRequirementVerdict({
|
|
10246
11098
|
client: client,
|
|
10247
11099
|
tag: tag,
|
|
10248
11100
|
definition: definition,
|
|
10249
|
-
allowed: allowed,
|
|
10250
11101
|
initialFields: initialFields ?? [],
|
|
10251
|
-
now: clock()
|
|
10252
|
-
|
|
11102
|
+
now: clock(),
|
|
11103
|
+
preflight: !0
|
|
11104
|
+
});
|
|
10253
11105
|
return {
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
insight: insight,
|
|
10257
|
-
unboundReads: unboundReads,
|
|
11106
|
+
...verdict,
|
|
11107
|
+
allowed: invalidInitialFields.length === 0 && verdict.allowed,
|
|
10258
11108
|
missingRequired: missingRequired,
|
|
10259
11109
|
invalidInitialFields: invalidInitialFields
|
|
10260
11110
|
};
|
|
@@ -10266,11 +11116,10 @@ const workflow = {
|
|
|
10266
11116
|
}
|
|
10267
11117
|
};
|
|
10268
11118
|
|
|
10269
|
-
|
|
10270
|
-
const {client: client, tag: tag, definition: definition,
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
definition: definition,
|
|
11119
|
+
function startPredicateContext(args) {
|
|
11120
|
+
const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now} = args;
|
|
11121
|
+
let slice;
|
|
11122
|
+
return {
|
|
10274
11123
|
fields: startFieldsParam({
|
|
10275
11124
|
entryDefs: definition.fields ?? [],
|
|
10276
11125
|
initialFields: initialFields
|
|
@@ -10278,12 +11127,71 @@ async function startAllowedInsight(args) {
|
|
|
10278
11127
|
scope: {
|
|
10279
11128
|
tag: tag,
|
|
10280
11129
|
now: now,
|
|
10281
|
-
fetchDataset: () => fetchStartSlice({
|
|
11130
|
+
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10282
11131
|
client: client,
|
|
10283
11132
|
tag: tag
|
|
10284
11133
|
})
|
|
10285
11134
|
}
|
|
10286
|
-
}
|
|
11135
|
+
};
|
|
11136
|
+
}
|
|
11137
|
+
|
|
11138
|
+
async function startRequirementVerdict(args) {
|
|
11139
|
+
const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now, preflight: preflight = !1} = args, declared = definition.start?.requirements ?? [];
|
|
11140
|
+
if (declared.length === 0) return {
|
|
11141
|
+
allowed: !0,
|
|
11142
|
+
outcome: "satisfied",
|
|
11143
|
+
requirements: [],
|
|
11144
|
+
unboundReads: []
|
|
11145
|
+
};
|
|
11146
|
+
const {fields: fields, scope: scope} = startPredicateContext({
|
|
11147
|
+
client: client,
|
|
11148
|
+
tag: tag,
|
|
11149
|
+
definition: definition,
|
|
11150
|
+
initialFields: initialFields,
|
|
11151
|
+
now: now
|
|
11152
|
+
}), subjectEntry = (definition.fields ?? []).find(invariants.isSubjectEntry)?.name, requirements = [], unbound = /* @__PURE__ */ new Set;
|
|
11153
|
+
for (const requirement of declared) {
|
|
11154
|
+
const descriptor = requirementDescriptor(requirement);
|
|
11155
|
+
if (requirement.type === "singleSubject") {
|
|
11156
|
+
if (preflight && subjectEntry !== void 0 && !Object.hasOwn(fields, subjectEntry)) unbound.add(subjectEntry),
|
|
11157
|
+
requirements.push({
|
|
11158
|
+
...descriptor,
|
|
11159
|
+
outcome: "unevaluable"
|
|
11160
|
+
}); else {
|
|
11161
|
+
const refused = await singleSubjectRequirementRefused({
|
|
11162
|
+
definition: definition,
|
|
11163
|
+
fields: fields,
|
|
11164
|
+
scope: scope
|
|
11165
|
+
});
|
|
11166
|
+
requirements.push({
|
|
11167
|
+
...descriptor,
|
|
11168
|
+
outcome: refused ? "unsatisfied" : "satisfied"
|
|
11169
|
+
});
|
|
11170
|
+
}
|
|
11171
|
+
continue;
|
|
11172
|
+
}
|
|
11173
|
+
const missing = unboundRequirementReads(requirement.query, fields);
|
|
11174
|
+
missing.forEach(name => unbound.add(name));
|
|
11175
|
+
const insight = await explainStartRequirement({
|
|
11176
|
+
query: requirement.query,
|
|
11177
|
+
definition: definition,
|
|
11178
|
+
fields: fields,
|
|
11179
|
+
scope: scope
|
|
11180
|
+
});
|
|
11181
|
+
requirements.push({
|
|
11182
|
+
...descriptor,
|
|
11183
|
+
outcome: preflight && missing.length > 0 ? "unevaluable" : insight.outcome,
|
|
11184
|
+
insight: insight
|
|
11185
|
+
});
|
|
11186
|
+
}
|
|
11187
|
+
let outcome = "satisfied";
|
|
11188
|
+
return requirements.some(requirement => requirement.outcome === "unsatisfied") ? outcome = "unsatisfied" : requirements.some(requirement => requirement.outcome === "unevaluable") && (outcome = "unevaluable"),
|
|
11189
|
+
{
|
|
11190
|
+
allowed: outcome === "satisfied",
|
|
11191
|
+
outcome: outcome,
|
|
11192
|
+
requirements: requirements,
|
|
11193
|
+
unboundReads: [ ...unbound ]
|
|
11194
|
+
};
|
|
10287
11195
|
}
|
|
10288
11196
|
|
|
10289
11197
|
async function startFreshInstance(args) {
|
|
@@ -10383,19 +11291,16 @@ async function assertStartInputs(args) {
|
|
|
10383
11291
|
initialFields: initialFields,
|
|
10384
11292
|
definitionName: definition.name
|
|
10385
11293
|
});
|
|
10386
|
-
const
|
|
10387
|
-
if (allowed === void 0) return;
|
|
10388
|
-
const insight = await startAllowedInsight({
|
|
11294
|
+
const unmetRequirements = (await startRequirementVerdict({
|
|
10389
11295
|
client: client,
|
|
10390
11296
|
tag: tag,
|
|
10391
11297
|
definition: definition,
|
|
10392
|
-
allowed: allowed,
|
|
10393
11298
|
initialFields: initialFields,
|
|
10394
11299
|
now: now
|
|
10395
|
-
});
|
|
10396
|
-
if (
|
|
11300
|
+
})).requirements.filter(requirement => requirement.outcome !== "satisfied").map(requirementDescriptor);
|
|
11301
|
+
if (unmetRequirements.length > 0) throw new StartNotAllowedError({
|
|
10397
11302
|
definition: definition.name,
|
|
10398
|
-
|
|
11303
|
+
unmetRequirements: unmetRequirements
|
|
10399
11304
|
});
|
|
10400
11305
|
}
|
|
10401
11306
|
|
|
@@ -10428,97 +11333,6 @@ async function resolveStartFields(args) {
|
|
|
10428
11333
|
};
|
|
10429
11334
|
}
|
|
10430
11335
|
|
|
10431
|
-
function isRecord(value) {
|
|
10432
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
10433
|
-
}
|
|
10434
|
-
|
|
10435
|
-
function isClientProjectUser(value) {
|
|
10436
|
-
return isRecord(value) && typeof value.id == "string" && (value.displayName === void 0 || typeof value.displayName == "string") && (value.email === void 0 || typeof value.email == "string") && (value.imageUrl === void 0 || value.imageUrl === null || typeof value.imageUrl == "string");
|
|
10437
|
-
}
|
|
10438
|
-
|
|
10439
|
-
function objectProperty(value, property) {
|
|
10440
|
-
if (!isRecord(value)) return;
|
|
10441
|
-
const propertyValue = value[property];
|
|
10442
|
-
return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
|
|
10443
|
-
}
|
|
10444
|
-
|
|
10445
|
-
function stringProperty(value, property) {
|
|
10446
|
-
const propertyValue = Reflect.get(value, property);
|
|
10447
|
-
return typeof propertyValue == "string" ? propertyValue : void 0;
|
|
10448
|
-
}
|
|
10449
|
-
|
|
10450
|
-
function apiErrorType(error) {
|
|
10451
|
-
const response = objectProperty(error, "response"), body = objectProperty(response, "body");
|
|
10452
|
-
if (!body) return;
|
|
10453
|
-
const nestedError = objectProperty(body, "error");
|
|
10454
|
-
return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
|
|
10455
|
-
}
|
|
10456
|
-
|
|
10457
|
-
function isProjectUserNotFoundError(error) {
|
|
10458
|
-
return apiErrorType(error) === "projectUserNotFoundError";
|
|
10459
|
-
}
|
|
10460
|
-
|
|
10461
|
-
function clientProjectUserDirectory(client, projectId) {
|
|
10462
|
-
return {
|
|
10463
|
-
findById: async id => {
|
|
10464
|
-
if (!client.request) return {
|
|
10465
|
-
status: "inaccessible",
|
|
10466
|
-
cause: new Error("Project-user resolution requires WorkflowClient.request")
|
|
10467
|
-
};
|
|
10468
|
-
try {
|
|
10469
|
-
const response = await client.request({
|
|
10470
|
-
uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
|
|
10471
|
-
}), candidate = Array.isArray(response) ? response[0] : response;
|
|
10472
|
-
return candidate == null ? {
|
|
10473
|
-
status: "missing"
|
|
10474
|
-
} : isClientProjectUser(candidate) ? {
|
|
10475
|
-
status: "resolved",
|
|
10476
|
-
user: candidate
|
|
10477
|
-
} : {
|
|
10478
|
-
status: "inaccessible",
|
|
10479
|
-
cause: new Error("Project-user response had an invalid shape")
|
|
10480
|
-
};
|
|
10481
|
-
} catch (cause) {
|
|
10482
|
-
return isProjectUserNotFoundError(cause) ? {
|
|
10483
|
-
status: "missing"
|
|
10484
|
-
} : {
|
|
10485
|
-
status: "inaccessible",
|
|
10486
|
-
cause: cause
|
|
10487
|
-
};
|
|
10488
|
-
}
|
|
10489
|
-
}
|
|
10490
|
-
};
|
|
10491
|
-
}
|
|
10492
|
-
|
|
10493
|
-
function resolveClientActor(client, args) {
|
|
10494
|
-
return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
|
|
10495
|
-
}
|
|
10496
|
-
|
|
10497
|
-
async function resolveActor(directory, actor) {
|
|
10498
|
-
if (actor.kind !== "person") return {
|
|
10499
|
-
status: "not-person",
|
|
10500
|
-
actor: actor
|
|
10501
|
-
};
|
|
10502
|
-
const personActor = {
|
|
10503
|
-
...actor,
|
|
10504
|
-
kind: "person"
|
|
10505
|
-
}, lookup = await directory.findById(personActor.id);
|
|
10506
|
-
return lookup.status === "resolved" ? {
|
|
10507
|
-
status: "resolved",
|
|
10508
|
-
actor: personActor,
|
|
10509
|
-
user: lookup.user
|
|
10510
|
-
} : lookup.status === "inaccessible" ? {
|
|
10511
|
-
status: "inaccessible",
|
|
10512
|
-
actor: personActor,
|
|
10513
|
-
...lookup.cause === void 0 ? {} : {
|
|
10514
|
-
cause: lookup.cause
|
|
10515
|
-
}
|
|
10516
|
-
} : {
|
|
10517
|
-
status: "missing",
|
|
10518
|
-
actor: personActor
|
|
10519
|
-
};
|
|
10520
|
-
}
|
|
10521
|
-
|
|
10522
11336
|
const EFFECT_COMMIT_QUEUE_DEPTH = 32, EFFECT_COMMIT_DISPATCH_CAP = 200;
|
|
10523
11337
|
|
|
10524
11338
|
class EffectCommitQueueOverflowError extends invariants.WorkflowError {
|
|
@@ -11144,17 +11958,23 @@ function createInstanceSession(args) {
|
|
|
11144
11958
|
refSurface: evalScope.refSurface
|
|
11145
11959
|
});
|
|
11146
11960
|
}, evaluateWith = async ({held: held, guards: guards, self: self}) => {
|
|
11147
|
-
const {actor: actor, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
11961
|
+
const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
11148
11962
|
clientForGdr: evalScope.clientForGdr,
|
|
11149
11963
|
instance: instance
|
|
11964
|
+
}), normalizedSelf = await normalizeInstanceIdentities({
|
|
11965
|
+
client: evalScope.client,
|
|
11966
|
+
instance: self
|
|
11150
11967
|
});
|
|
11151
11968
|
return evaluateFromSnapshot({
|
|
11152
|
-
instance:
|
|
11969
|
+
instance: normalizedSelf,
|
|
11153
11970
|
definition: definitionOf(),
|
|
11154
11971
|
actor: actor,
|
|
11155
|
-
snapshot: snapshotFrom(held,
|
|
11972
|
+
snapshot: snapshotFrom(held, normalizedSelf),
|
|
11156
11973
|
guards: guards,
|
|
11157
11974
|
resourceGrants: resourceGrants,
|
|
11975
|
+
...localPrincipalId !== void 0 ? {
|
|
11976
|
+
localPrincipalId: localPrincipalId
|
|
11977
|
+
} : {},
|
|
11158
11978
|
...clock !== void 0 ? {
|
|
11159
11979
|
now: clock()
|
|
11160
11980
|
} : {},
|
|
@@ -11200,8 +12020,13 @@ function createInstanceSession(args) {
|
|
|
11200
12020
|
committing = !0;
|
|
11201
12021
|
const held = new Map(overlay);
|
|
11202
12022
|
try {
|
|
11203
|
-
const {actor: actor} = await access();
|
|
11204
|
-
return await run(
|
|
12023
|
+
const {actor: actor, localPrincipalId: localPrincipalId} = await access();
|
|
12024
|
+
return await run({
|
|
12025
|
+
actor: actor,
|
|
12026
|
+
...localPrincipalId !== void 0 ? {
|
|
12027
|
+
localPrincipalId: localPrincipalId
|
|
12028
|
+
} : {}
|
|
12029
|
+
}, held);
|
|
11205
12030
|
} finally {
|
|
11206
12031
|
if (committing = !1, buffered !== void 0) {
|
|
11207
12032
|
const next = buffered;
|
|
@@ -11276,11 +12101,14 @@ function createInstanceSession(args) {
|
|
|
11276
12101
|
site !== void 0 && previews.delete(siteKey(site));
|
|
11277
12102
|
},
|
|
11278
12103
|
tick() {
|
|
11279
|
-
return commit(async (actor, held) => {
|
|
12104
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11280
12105
|
await assertInstanceWriteAllowed({
|
|
11281
12106
|
instance: instance,
|
|
11282
12107
|
guards: heldGuards,
|
|
11283
|
-
identity:
|
|
12108
|
+
identity: invariants.lakePrincipalId({
|
|
12109
|
+
actor: actor,
|
|
12110
|
+
localPrincipalId: localPrincipalId
|
|
12111
|
+
})
|
|
11284
12112
|
});
|
|
11285
12113
|
const before = await reload({
|
|
11286
12114
|
client: tickScope.client,
|
|
@@ -11307,7 +12135,7 @@ function createInstanceSession(args) {
|
|
|
11307
12135
|
});
|
|
11308
12136
|
},
|
|
11309
12137
|
fireAction({activity: activity, action: action, params: params}) {
|
|
11310
|
-
return commit(async (actor, held) => {
|
|
12138
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11311
12139
|
assertActionAllowed({
|
|
11312
12140
|
evaluation: await evaluateWith({
|
|
11313
12141
|
held: held,
|
|
@@ -11323,6 +12151,9 @@ function createInstanceSession(args) {
|
|
|
11323
12151
|
activity: activity,
|
|
11324
12152
|
action: action,
|
|
11325
12153
|
actor: actor,
|
|
12154
|
+
...localPrincipalId !== void 0 ? {
|
|
12155
|
+
localPrincipalId: localPrincipalId
|
|
12156
|
+
} : {},
|
|
11326
12157
|
clientForGdr: fireScope.clientForGdr,
|
|
11327
12158
|
refSurface: fireScope.refSurface,
|
|
11328
12159
|
...grants !== void 0 ? {
|
|
@@ -11365,7 +12196,7 @@ function createInstanceSession(args) {
|
|
|
11365
12196
|
} catch (err) {
|
|
11366
12197
|
return Promise.reject(err);
|
|
11367
12198
|
}
|
|
11368
|
-
return commit(async (actor, held) => {
|
|
12199
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11369
12200
|
assertEditAllowed(await evaluateWith({
|
|
11370
12201
|
held: held,
|
|
11371
12202
|
guards: heldGuards,
|
|
@@ -11382,6 +12213,9 @@ function createInstanceSession(args) {
|
|
|
11382
12213
|
value: value
|
|
11383
12214
|
} : {},
|
|
11384
12215
|
actor: actor,
|
|
12216
|
+
...localPrincipalId !== void 0 ? {
|
|
12217
|
+
localPrincipalId: localPrincipalId
|
|
12218
|
+
} : {},
|
|
11385
12219
|
clientForGdr: editScope.clientForGdr,
|
|
11386
12220
|
refSurface: editScope.refSurface,
|
|
11387
12221
|
...grants !== void 0 ? {
|
|
@@ -11492,6 +12326,7 @@ function createEngine(args) {
|
|
|
11492
12326
|
availableActions: rest => workflow.availableActions(withScope(rest)),
|
|
11493
12327
|
setStage: rest => workflow.setStage(withScope(rest)),
|
|
11494
12328
|
abortInstance: rest => workflow.abortInstance(withScope(rest)),
|
|
12329
|
+
resetActivity: rest => workflow.resetActivity(withScope(rest)),
|
|
11495
12330
|
deleteDefinition: rest => workflow.deleteDefinition(withScope(rest)),
|
|
11496
12331
|
getInstance: rest => workflow.getInstance(withScope(rest)),
|
|
11497
12332
|
subscriptionDocumentsForInstance: rest => workflow.getInstance(withScope(rest)).then(subscriptionDocumentsForInstance),
|
|
@@ -12064,6 +12899,8 @@ exports.ACTIVITY_KINDS = invariants.ACTIVITY_KINDS;
|
|
|
12064
12899
|
|
|
12065
12900
|
exports.ACTOR_KINDS = invariants.ACTOR_KINDS;
|
|
12066
12901
|
|
|
12902
|
+
exports.ANONYMOUS_IDENTITY = invariants.ANONYMOUS_IDENTITY;
|
|
12903
|
+
|
|
12067
12904
|
exports.CONDITION_VARS = invariants.CONDITION_VARS;
|
|
12068
12905
|
|
|
12069
12906
|
exports.ContractViolationError = invariants.ContractViolationError;
|
|
@@ -12106,10 +12943,12 @@ exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
|
|
|
12106
12943
|
|
|
12107
12944
|
exports.ReaderModelAcknowledgementError = invariants.ReaderModelAcknowledgementError;
|
|
12108
12945
|
|
|
12109
|
-
exports.START_ALLOWED_VARS = invariants.START_ALLOWED_VARS;
|
|
12110
|
-
|
|
12111
12946
|
exports.START_FILTER_VARS = invariants.START_FILTER_VARS;
|
|
12112
12947
|
|
|
12948
|
+
exports.START_REQUIREMENT_VARS = invariants.START_REQUIREMENT_VARS;
|
|
12949
|
+
|
|
12950
|
+
exports.SYSTEM_IDENTITY = invariants.SYSTEM_IDENTITY;
|
|
12951
|
+
|
|
12113
12952
|
exports.SpawnContractsInvalidError = invariants.SpawnContractsInvalidError;
|
|
12114
12953
|
|
|
12115
12954
|
exports.WORKFLOW_DEFINITION_TYPE = invariants.WORKFLOW_DEFINITION_TYPE;
|
|
@@ -12122,6 +12961,8 @@ exports.assertReadableModel = invariants.assertReadableModel;
|
|
|
12122
12961
|
|
|
12123
12962
|
exports.assertReaderModelAcknowledgement = invariants.assertReaderModelAcknowledgement;
|
|
12124
12963
|
|
|
12964
|
+
exports.classifyPrincipalId = invariants.classifyPrincipalId;
|
|
12965
|
+
|
|
12125
12966
|
exports.clientConfigFromResource = invariants.clientConfigFromResource;
|
|
12126
12967
|
|
|
12127
12968
|
exports.conditionFieldReadNames = invariants.conditionFieldReadNames;
|
|
@@ -12172,6 +13013,8 @@ exports.isTodoListItem = invariants.isTodoListItem;
|
|
|
12172
13013
|
|
|
12173
13014
|
exports.isUnprimed = invariants.isUnprimed;
|
|
12174
13015
|
|
|
13016
|
+
exports.lakePrincipalId = invariants.lakePrincipalId;
|
|
13017
|
+
|
|
12175
13018
|
exports.minReaderModelOf = invariants.minReaderModelOf;
|
|
12176
13019
|
|
|
12177
13020
|
exports.modelVersionOf = invariants.modelVersionOf;
|
|
@@ -12398,6 +13241,8 @@ exports.StartNotSettledError = StartNotSettledError;
|
|
|
12398
13241
|
|
|
12399
13242
|
exports.WorkflowActionFired = WorkflowActionFired;
|
|
12400
13243
|
|
|
13244
|
+
exports.WorkflowActivityReset = WorkflowActivityReset;
|
|
13245
|
+
|
|
12401
13246
|
exports.WorkflowDefinitionDeleted = WorkflowDefinitionDeleted;
|
|
12402
13247
|
|
|
12403
13248
|
exports.WorkflowDefinitionDeployed = WorkflowDefinitionDeployed;
|
|
@@ -12530,7 +13375,7 @@ exports.evaluateStartFilter = evaluateStartFilter;
|
|
|
12530
13375
|
|
|
12531
13376
|
exports.expandResourceAliases = expandResourceAliases;
|
|
12532
13377
|
|
|
12533
|
-
exports.
|
|
13378
|
+
exports.explainStartRequirement = explainStartRequirement;
|
|
12534
13379
|
|
|
12535
13380
|
exports.findCurrentActivityEntry = findCurrentActivityEntry;
|
|
12536
13381
|
|
|
@@ -12546,6 +13391,8 @@ exports.guardsForInstance = guardsForInstance;
|
|
|
12546
13391
|
|
|
12547
13392
|
exports.guardsForResource = guardsForResource;
|
|
12548
13393
|
|
|
13394
|
+
exports.hasSingleSubjectRequirement = hasSingleSubjectRequirement;
|
|
13395
|
+
|
|
12549
13396
|
exports.hashDefinitionContent = hashDefinitionContent;
|
|
12550
13397
|
|
|
12551
13398
|
exports.inFlightFilter = inFlightFilter;
|
|
@@ -12578,6 +13425,8 @@ exports.isTerminalStage = isTerminalStage;
|
|
|
12578
13425
|
|
|
12579
13426
|
exports.lakeGuardId = lakeGuardId;
|
|
12580
13427
|
|
|
13428
|
+
exports.latestDefinitionsGroq = latestDefinitionsGroq;
|
|
13429
|
+
|
|
12581
13430
|
exports.latestDeployedDefinitions = latestDeployedDefinitions;
|
|
12582
13431
|
|
|
12583
13432
|
exports.lintEffectOutputs = lintEffectOutputs;
|
|
@@ -12596,6 +13445,8 @@ exports.parseInstanceDocument = parseInstanceDocument;
|
|
|
12596
13445
|
|
|
12597
13446
|
exports.processShellUserProperties = processShellUserProperties;
|
|
12598
13447
|
|
|
13448
|
+
exports.projectStartSliceRow = projectStartSliceRow;
|
|
13449
|
+
|
|
12599
13450
|
exports.projectToWatchRef = projectToWatchRef;
|
|
12600
13451
|
|
|
12601
13452
|
exports.readInstanceDoc = readInstanceDoc;
|
|
@@ -12618,6 +13469,8 @@ exports.retractStageGuards = retractStageGuards;
|
|
|
12618
13469
|
|
|
12619
13470
|
exports.silentLogger = silentLogger;
|
|
12620
13471
|
|
|
13472
|
+
exports.singleSubjectRequirementRefused = singleSubjectRequirementRefused;
|
|
13473
|
+
|
|
12621
13474
|
exports.stageAutonomyOf = stageAutonomyOf;
|
|
12622
13475
|
|
|
12623
13476
|
exports.startFieldsParam = startFieldsParam;
|
|
@@ -12634,7 +13487,7 @@ exports.subscriptionDocumentsForInstance = subscriptionDocumentsForInstance;
|
|
|
12634
13487
|
|
|
12635
13488
|
exports.sweepStaleClaims = sweepStaleClaims;
|
|
12636
13489
|
|
|
12637
|
-
exports.
|
|
13490
|
+
exports.unboundRequirementReads = unboundRequirementReads;
|
|
12638
13491
|
|
|
12639
13492
|
exports.unsatisfiedTransitionSummaries = unsatisfiedTransitionSummaries;
|
|
12640
13493
|
|