@sanity/workflow-engine 0.19.0 → 0.21.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 +196 -0
- package/DATAMODEL.md +168 -0
- package/dist/_chunks-cjs/invariants.cjs +275 -94
- package/dist/_chunks-es/invariants.js +264 -89
- package/dist/define.d.cts +58 -40
- package/dist/define.d.ts +58 -40
- package/dist/index.cjs +1940 -901
- package/dist/index.d.cts +524 -236
- package/dist/index.d.ts +524 -236
- package/dist/index.js +1928 -911
- package/package.json +3 -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
|
});
|
|
@@ -4016,12 +4017,27 @@ function assertInputValueShape(entry, value) {
|
|
|
4016
4017
|
function assertGdrShape(value, context) {
|
|
4017
4018
|
if (typeof value != "object" || value === null) throw new invariants.ContractViolationError(`Invalid GDR for ${context}: expected { id: "<scheme>:...", type: "<schema>" }, got ${typeof value}.`);
|
|
4018
4019
|
const v2 = value;
|
|
4019
|
-
if (typeof v2.id != "string"
|
|
4020
|
+
if (typeof v2.id != "string") throw invalidGdrUriError(context, v2.id);
|
|
4021
|
+
try {
|
|
4022
|
+
invariants.parseGdr(v2.id);
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
throw error instanceof invariants.VersionSpecificDatasetGdrError ? new invariants.ContractViolationError(`Invalid GDR for ${context}: ${error.message}`) : invalidGdrUriError(context, v2.id);
|
|
4025
|
+
}
|
|
4020
4026
|
if (typeof v2.type != "string" || v2.type.length === 0) throw new invariants.ContractViolationError(`Invalid GDR for ${context}: \`type\` (schema name) must be a non-empty string. Got ${JSON.stringify(v2.type)}.`);
|
|
4021
4027
|
}
|
|
4022
4028
|
|
|
4029
|
+
function invalidGdrUriError(context, id) {
|
|
4030
|
+
return new invariants.ContractViolationError(`Invalid GDR for ${context}: \`id\` must be a GDR URI ("<scheme>:<...id-parts>" with scheme dataset|canvas|media-library|dashboard). Got ${JSON.stringify(id)}. Construct via \`gdrFromResource\` / \`refDataset\` / \`refCanvas\` etc. — bare document ids are not accepted.`);
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4023
4033
|
function normalizeQueryResult({entryType: entryType, raw: raw, workflowResource: workflowResource}) {
|
|
4024
|
-
|
|
4034
|
+
if (raw == null) return raw;
|
|
4035
|
+
try {
|
|
4036
|
+
return invariants.isSingleDocRefKind(entryType) ? coerceToGdr(raw, workflowResource) : entryType === "doc.refs" ? Array.isArray(raw) ? raw.map(item => coerceToGdr(item, workflowResource)).filter(v2 => v2 !== null) : [] : raw;
|
|
4037
|
+
} catch (error) {
|
|
4038
|
+
if (error instanceof invariants.VersionSpecificDatasetGdrError) return raw;
|
|
4039
|
+
throw error;
|
|
4040
|
+
}
|
|
4025
4041
|
}
|
|
4026
4042
|
|
|
4027
4043
|
function coerceGdrShape(raw, workflowResource) {
|
|
@@ -4363,219 +4379,706 @@ function parseInstanceDocument(doc) {
|
|
|
4363
4379
|
});
|
|
4364
4380
|
}
|
|
4365
4381
|
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
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");
|
|
4370
4419
|
|
|
4371
|
-
function
|
|
4372
|
-
return
|
|
4420
|
+
function unwrapPatch(patch) {
|
|
4421
|
+
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4373
4422
|
}
|
|
4374
4423
|
|
|
4375
|
-
|
|
4376
|
-
const doc = await getInstanceDocument(client, instanceId);
|
|
4377
|
-
if (!doc) throw new invariants.InstanceNotFoundError({
|
|
4378
|
-
instanceId: instanceId
|
|
4379
|
-
});
|
|
4380
|
-
if (doc.tag !== tag) throw new invariants.InstanceNotFoundError({
|
|
4381
|
-
instanceId: instanceId,
|
|
4382
|
-
detail: "not visible to this engine: tag mismatch"
|
|
4383
|
-
});
|
|
4384
|
-
return doc;
|
|
4385
|
-
}
|
|
4424
|
+
const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4386
4425
|
|
|
4387
|
-
function
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
_type: "context.string",
|
|
4392
|
-
name: name,
|
|
4393
|
-
value: value
|
|
4394
|
-
} : typeof value == "number" ? {
|
|
4395
|
-
_key: _key,
|
|
4396
|
-
_type: "context.number",
|
|
4397
|
-
name: name,
|
|
4398
|
-
value: value
|
|
4399
|
-
} : typeof value == "boolean" ? {
|
|
4400
|
-
_key: _key,
|
|
4401
|
-
_type: "context.boolean",
|
|
4402
|
-
name: name,
|
|
4403
|
-
value: value
|
|
4404
|
-
} : {
|
|
4405
|
-
_key: _key,
|
|
4406
|
-
_type: "context.ref",
|
|
4407
|
-
name: name,
|
|
4408
|
-
value: value
|
|
4409
|
-
};
|
|
4426
|
+
function unwrapRequestTag(client) {
|
|
4427
|
+
let current = client;
|
|
4428
|
+
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
4429
|
+
return current;
|
|
4410
4430
|
}
|
|
4411
4431
|
|
|
4412
|
-
function
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
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;
|
|
4419
4439
|
}
|
|
4420
4440
|
|
|
4421
|
-
function
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
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
|
+
});
|
|
4427
4450
|
}
|
|
4428
|
-
|
|
4429
|
-
return json;
|
|
4451
|
+
return effectHandlerClientCache.set(client, tagged), tagged;
|
|
4430
4452
|
}
|
|
4431
4453
|
|
|
4432
|
-
function
|
|
4433
|
-
|
|
4434
|
-
_key: randomKey(),
|
|
4435
|
-
_type: "stageEntered",
|
|
4436
|
-
at: now,
|
|
4437
|
-
stage: args.initialStage,
|
|
4438
|
-
...actor !== void 0 ? {
|
|
4439
|
-
actor: actor
|
|
4440
|
-
} : {}
|
|
4441
|
-
}, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
|
|
4442
|
-
_id: id,
|
|
4443
|
-
_type: invariants.WORKFLOW_INSTANCE_TYPE,
|
|
4444
|
-
_rev: "",
|
|
4445
|
-
_createdAt: now,
|
|
4446
|
-
_updatedAt: now,
|
|
4447
|
-
tag: args.tag,
|
|
4448
|
-
workflowResource: args.workflowResource,
|
|
4449
|
-
definition: args.definitionName,
|
|
4450
|
-
pinnedVersion: args.pinnedVersion,
|
|
4451
|
-
...args.pinnedContentHash !== void 0 ? {
|
|
4452
|
-
pinnedContentHash: args.pinnedContentHash
|
|
4453
|
-
} : {},
|
|
4454
|
-
definitionSnapshot: JSON.stringify(args.definition),
|
|
4455
|
-
fields: args.fields,
|
|
4456
|
-
context: args.context,
|
|
4457
|
-
ancestors: args.ancestors,
|
|
4458
|
-
...perspective !== void 0 ? {
|
|
4459
|
-
perspective: perspective
|
|
4460
|
-
} : {},
|
|
4461
|
-
currentStage: args.initialStage,
|
|
4462
|
-
stages: [],
|
|
4463
|
-
subworkflows: [],
|
|
4464
|
-
pendingEffects: [],
|
|
4465
|
-
effectHistory: [],
|
|
4466
|
-
history: history,
|
|
4467
|
-
startedAt: now,
|
|
4468
|
-
lastChangedAt: now
|
|
4469
|
-
};
|
|
4470
|
-
return {
|
|
4471
|
-
...body,
|
|
4472
|
-
...invariants.modelStampFor({
|
|
4473
|
-
documentType: "instance",
|
|
4474
|
-
document: body
|
|
4475
|
-
})
|
|
4476
|
-
};
|
|
4454
|
+
function effectHandlerResolver(resolver) {
|
|
4455
|
+
return mapResourceClientResolver(resolver, effectHandlerClient);
|
|
4477
4456
|
}
|
|
4478
4457
|
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
if (held !== void 0) {
|
|
4484
|
-
loaded.push(held), visited.add(uri);
|
|
4485
|
-
return;
|
|
4486
|
-
}
|
|
4487
|
-
const fetched = await loadByGdr({
|
|
4488
|
-
defaultClient: client,
|
|
4489
|
-
clientForGdr: clientForGdr,
|
|
4490
|
-
defaultResource: instance.workflowResource,
|
|
4491
|
-
uri: uri,
|
|
4492
|
-
perspective: perspective
|
|
4493
|
-
});
|
|
4494
|
-
fetched && (loaded.push(fetched), visited.add(uri));
|
|
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);
|
|
4495
4462
|
};
|
|
4496
|
-
loaded.push({
|
|
4497
|
-
doc: instance,
|
|
4498
|
-
resource: instance.workflowResource
|
|
4499
|
-
}), visited.add(invariants.selfGdr(instance));
|
|
4500
|
-
for (const ref of collectWatchRefs(instance)) await loadInto(ref.id, readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE);
|
|
4501
|
-
return buildSnapshot({
|
|
4502
|
-
docs: loaded
|
|
4503
|
-
});
|
|
4504
|
-
}
|
|
4505
|
-
|
|
4506
|
-
async function loadByGdr({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4507
|
-
const parsed = invariants.tryParseGdr(uri);
|
|
4508
|
-
if (parsed === void 0) {
|
|
4509
|
-
const doc2 = await readDoc({
|
|
4510
|
-
client: defaultClient,
|
|
4511
|
-
id: uri,
|
|
4512
|
-
perspective: perspective
|
|
4513
|
-
});
|
|
4514
|
-
return doc2 ? {
|
|
4515
|
-
doc: doc2,
|
|
4516
|
-
resource: defaultResource
|
|
4517
|
-
} : null;
|
|
4518
|
-
}
|
|
4519
|
-
const routed = clientForGdr(parsed), doc = await readDoc({
|
|
4520
|
-
client: routed,
|
|
4521
|
-
id: parsed.documentId,
|
|
4522
|
-
perspective: perspective
|
|
4523
|
-
});
|
|
4524
|
-
return doc ? {
|
|
4525
|
-
doc: doc,
|
|
4526
|
-
resource: invariants.resourceFromParsed(parsed)
|
|
4527
|
-
} : null;
|
|
4528
4463
|
}
|
|
4529
4464
|
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
const doc2 = await client.getDocument(id) ?? null;
|
|
4533
|
-
return doc2 ? doc2._type === invariants.WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc2) : invariants.assertReadableModel(doc2) : null;
|
|
4534
|
-
}
|
|
4535
|
-
const {query: query, params: params} = contentDocQuery(id);
|
|
4536
|
-
return await client.fetch(query, params, {
|
|
4537
|
-
perspective: perspective
|
|
4538
|
-
}) ?? null;
|
|
4465
|
+
function isWorkflowsFamilyPrefix(prefix) {
|
|
4466
|
+
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4539
4467
|
}
|
|
4540
4468
|
|
|
4541
|
-
function
|
|
4542
|
-
|
|
4469
|
+
function clientRequestTagPrefix(client) {
|
|
4470
|
+
const probe = client;
|
|
4471
|
+
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4543
4472
|
}
|
|
4544
4473
|
|
|
4545
|
-
function
|
|
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}`;
|
|
4547
4478
|
}
|
|
4548
4479
|
|
|
4549
|
-
function
|
|
4550
|
-
return
|
|
4551
|
-
client: client,
|
|
4552
|
-
instanceId: instanceId,
|
|
4553
|
-
options: {
|
|
4554
|
-
clientForGdr: options.clientForGdr,
|
|
4555
|
-
refSurface: options.refSurface,
|
|
4556
|
-
...options.actor ? {
|
|
4557
|
-
actor: options.actor
|
|
4558
|
-
} : {},
|
|
4559
|
-
...options.clock ? {
|
|
4560
|
-
clock: options.clock
|
|
4561
|
-
} : {},
|
|
4562
|
-
...options.executionContext ? {
|
|
4563
|
-
executionContext: options.executionContext
|
|
4564
|
-
} : {},
|
|
4565
|
-
...options.telemetry ? {
|
|
4566
|
-
telemetry: options.telemetry
|
|
4567
|
-
} : {}
|
|
4568
|
-
}
|
|
4569
|
-
});
|
|
4480
|
+
function stripWorkflowRoot(tag) {
|
|
4481
|
+
return tag.startsWith("workflow.") ? tag.slice(9) : tag;
|
|
4570
4482
|
}
|
|
4571
4483
|
|
|
4572
|
-
|
|
4573
|
-
const
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
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]";
|
|
4981
|
+
|
|
4982
|
+
function routeRead({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4983
|
+
const parsed = invariants.tryParseGdr(uri);
|
|
4984
|
+
return parsed === void 0 ? {
|
|
4985
|
+
client: defaultClient,
|
|
4986
|
+
id: uri,
|
|
4987
|
+
perspective: perspective,
|
|
4988
|
+
resource: defaultResource
|
|
4989
|
+
} : {
|
|
4990
|
+
client: clientForGdr(parsed),
|
|
4991
|
+
id: parsed.documentId,
|
|
4992
|
+
perspective: perspective,
|
|
4993
|
+
resource: invariants.resourceFromParsed(parsed)
|
|
4994
|
+
};
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4997
|
+
async function readPending(reads) {
|
|
4998
|
+
const batches = groupReads(reads).flatMap(group => chunks(group.reads, SNAPSHOT_READ_BATCH_SIZE).map(batch => ({
|
|
4999
|
+
group: group,
|
|
5000
|
+
batch: batch
|
|
5001
|
+
}))), results = [];
|
|
5002
|
+
for (const wave of chunks(batches, SNAPSHOT_READ_CONCURRENCY)) results.push(...await Promise.all(wave.map(readBatch)));
|
|
5003
|
+
return new Map(results.flat());
|
|
5004
|
+
}
|
|
5005
|
+
|
|
5006
|
+
async function readBatch(args) {
|
|
5007
|
+
const {group: group, batch: batch} = args, ids = batch.map(read => read.id), docs = await group.client.fetch(snapshotDocsQuery, {
|
|
5008
|
+
ids: ids
|
|
5009
|
+
}, {
|
|
5010
|
+
perspective: group.perspective
|
|
5011
|
+
}), byId = new Map(docs.map(doc => [ doc._id, validateRawDoc(doc, group.perspective) ]));
|
|
5012
|
+
return batch.flatMap(read => {
|
|
5013
|
+
const doc = byId.get(read.id);
|
|
5014
|
+
return doc === void 0 ? [] : [ [ read, doc ] ];
|
|
5015
|
+
});
|
|
5016
|
+
}
|
|
5017
|
+
|
|
5018
|
+
function validateRawDoc(doc, perspective) {
|
|
5019
|
+
return perspective !== "raw" ? doc : doc._type === invariants.WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc) : invariants.assertReadableModel(doc);
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
function groupReads(reads) {
|
|
5023
|
+
const byClient = /* @__PURE__ */ new Map;
|
|
5024
|
+
for (const read of reads) {
|
|
5025
|
+
let clientGroups = byClient.get(read.client);
|
|
5026
|
+
clientGroups === void 0 && (clientGroups = /* @__PURE__ */ new Map, byClient.set(read.client, clientGroups));
|
|
5027
|
+
const key = JSON.stringify(read.perspective);
|
|
5028
|
+
let group = clientGroups.get(key);
|
|
5029
|
+
group === void 0 && (group = {
|
|
5030
|
+
client: read.client,
|
|
5031
|
+
perspective: read.perspective,
|
|
5032
|
+
reads: []
|
|
5033
|
+
}, clientGroups.set(key, group)), group.reads.push(read);
|
|
5034
|
+
}
|
|
5035
|
+
return [ ...byClient.values() ].flatMap(groups => [ ...groups.values() ]);
|
|
5036
|
+
}
|
|
5037
|
+
|
|
5038
|
+
function chunks(values, size) {
|
|
5039
|
+
return Array.from({
|
|
5040
|
+
length: Math.ceil(values.length / size)
|
|
5041
|
+
}, (_, index) => values.slice(index * size, (index + 1) * size));
|
|
5042
|
+
}
|
|
5043
|
+
|
|
5044
|
+
function collectEntryDocUris(resolvedFieldEntries) {
|
|
5045
|
+
return entryDocRefs(resolvedFieldEntries).map(ref => ref.id);
|
|
5046
|
+
}
|
|
5047
|
+
|
|
5048
|
+
function isEngineContext(ctx) {
|
|
5049
|
+
return "client" in ctx;
|
|
5050
|
+
}
|
|
5051
|
+
|
|
5052
|
+
function loadCallContext({client: client, instanceId: instanceId, options: options}) {
|
|
5053
|
+
return loadContext({
|
|
5054
|
+
client: client,
|
|
5055
|
+
instanceId: instanceId,
|
|
5056
|
+
options: {
|
|
5057
|
+
clientForGdr: options.clientForGdr,
|
|
5058
|
+
refSurface: options.refSurface,
|
|
5059
|
+
...options.actor ? {
|
|
5060
|
+
actor: options.actor
|
|
5061
|
+
} : {},
|
|
5062
|
+
...options.clock ? {
|
|
5063
|
+
clock: options.clock
|
|
5064
|
+
} : {},
|
|
5065
|
+
...options.executionContext ? {
|
|
5066
|
+
executionContext: options.executionContext
|
|
5067
|
+
} : {},
|
|
5068
|
+
...options.telemetry ? {
|
|
5069
|
+
telemetry: options.telemetry
|
|
5070
|
+
} : {}
|
|
5071
|
+
}
|
|
5072
|
+
});
|
|
5073
|
+
}
|
|
5074
|
+
|
|
5075
|
+
async function retryOnRevisionConflict(args) {
|
|
5076
|
+
const {client: client, instanceId: instanceId, options: options, commit: commit, onExhausted: onExhausted} = args;
|
|
5077
|
+
for (let attempt = 1; attempt <= CONCURRENT_COMMIT_MAX_ATTEMPTS; attempt++) {
|
|
5078
|
+
const ctx = await loadCallContext({
|
|
5079
|
+
client: client,
|
|
5080
|
+
instanceId: instanceId,
|
|
5081
|
+
options: options
|
|
4579
5082
|
});
|
|
4580
5083
|
try {
|
|
4581
5084
|
return await commit(ctx);
|
|
@@ -4591,29 +5094,31 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
|
|
|
4591
5094
|
if (!instance) throw new invariants.InstanceNotFoundError({
|
|
4592
5095
|
instanceId: instanceId
|
|
4593
5096
|
});
|
|
4594
|
-
|
|
5097
|
+
return buildEngineContext({
|
|
4595
5098
|
client: client,
|
|
4596
|
-
clientForGdr: clientForGdr,
|
|
5099
|
+
clientForGdr: options.clientForGdr,
|
|
5100
|
+
refSurface: options.refSurface,
|
|
4597
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
|
+
} : {},
|
|
4598
5115
|
...options.overlay !== void 0 ? {
|
|
4599
5116
|
overlay: options.overlay
|
|
5117
|
+
} : {},
|
|
5118
|
+
...options.settlingCohorts !== void 0 ? {
|
|
5119
|
+
settlingCohorts: options.settlingCohorts
|
|
4600
5120
|
} : {}
|
|
4601
5121
|
});
|
|
4602
|
-
return {
|
|
4603
|
-
client: client,
|
|
4604
|
-
clientForGdr: clientForGdr,
|
|
4605
|
-
refSurface: refSurface,
|
|
4606
|
-
clock: clock,
|
|
4607
|
-
now: clock(),
|
|
4608
|
-
executionContext: resolveExecutionContext(options?.executionContext),
|
|
4609
|
-
telemetry: resolveTelemetry(options.telemetry),
|
|
4610
|
-
...options?.actor !== void 0 ? {
|
|
4611
|
-
actor: options.actor
|
|
4612
|
-
} : {},
|
|
4613
|
-
instance: instance,
|
|
4614
|
-
definition: definition,
|
|
4615
|
-
snapshot: snapshot
|
|
4616
|
-
};
|
|
4617
5122
|
}
|
|
4618
5123
|
|
|
4619
5124
|
async function ctxConditionParams(ctx, opts) {
|
|
@@ -4651,6 +5156,9 @@ async function buildEngineContext(args) {
|
|
|
4651
5156
|
now: clock(),
|
|
4652
5157
|
executionContext: resolveExecutionContext(args.executionContext),
|
|
4653
5158
|
telemetry: resolveTelemetry(args.telemetry),
|
|
5159
|
+
...args.settlingCohorts !== void 0 ? {
|
|
5160
|
+
settlingCohorts: args.settlingCohorts
|
|
5161
|
+
} : {},
|
|
4654
5162
|
...args.actor !== void 0 ? {
|
|
4655
5163
|
actor: args.actor
|
|
4656
5164
|
} : {},
|
|
@@ -4659,7 +5167,10 @@ async function buildEngineContext(args) {
|
|
|
4659
5167
|
snapshot: await hydrateSnapshot({
|
|
4660
5168
|
client: client,
|
|
4661
5169
|
clientForGdr: clientForGdr,
|
|
4662
|
-
instance: instance
|
|
5170
|
+
instance: instance,
|
|
5171
|
+
...args.overlay !== void 0 ? {
|
|
5172
|
+
overlay: args.overlay
|
|
5173
|
+
} : {}
|
|
4663
5174
|
})
|
|
4664
5175
|
};
|
|
4665
5176
|
}
|
|
@@ -4782,10 +5293,6 @@ function recordProcessedRequest({mutation: mutation, record: record, now: now})
|
|
|
4782
5293
|
} ];
|
|
4783
5294
|
}
|
|
4784
5295
|
|
|
4785
|
-
const SYNC_COMMIT = {
|
|
4786
|
-
visibility: "sync"
|
|
4787
|
-
}, ENGINE_API_VERSION = "2026-04-29";
|
|
4788
|
-
|
|
4789
5296
|
function resolveGuardRead(args) {
|
|
4790
5297
|
const {expr: expr, ctx: ctx, deref: deref} = args;
|
|
4791
5298
|
if (expr === "$self") return invariants.selfGdr(ctx.instance);
|
|
@@ -4839,32 +5346,311 @@ function resolveIdRefTargets(idRefs, ctx) {
|
|
|
4839
5346
|
return targets.length === 0 ? null : targets;
|
|
4840
5347
|
}
|
|
4841
5348
|
|
|
4842
|
-
function assertSingleResource(targets) {
|
|
4843
|
-
const resource = invariants.resourceFromParsed(targets[0].parsed);
|
|
4844
|
-
for (const g of targets) {
|
|
4845
|
-
const r = invariants.resourceFromParsed(g.parsed);
|
|
4846
|
-
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.`);
|
|
4847
|
-
}
|
|
4848
|
-
return resource;
|
|
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;
|
|
5573
|
+
}
|
|
5574
|
+
|
|
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);
|
|
5580
|
+
}
|
|
5581
|
+
|
|
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]);
|
|
4849
5589
|
}
|
|
4850
5590
|
|
|
4851
|
-
function
|
|
4852
|
-
|
|
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);
|
|
4853
5600
|
}
|
|
4854
5601
|
|
|
4855
|
-
function
|
|
4856
|
-
if (
|
|
4857
|
-
|
|
4858
|
-
|
|
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
|
+
};
|
|
4859
5615
|
}
|
|
4860
5616
|
|
|
4861
|
-
function
|
|
4862
|
-
const
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
5617
|
+
function identityPathSteps(kind, path) {
|
|
5618
|
+
const segments = path.split(".");
|
|
5619
|
+
return kind !== "assignees" ? segments : /^\d+$/.test(segments[0] ?? "") ? segments.slice(1) : void 0;
|
|
5620
|
+
}
|
|
5621
|
+
|
|
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
|
+
}
|
|
4868
5654
|
return out;
|
|
4869
5655
|
}
|
|
4870
5656
|
|
|
@@ -4900,151 +5686,6 @@ function parseGuardDocument(doc) {
|
|
|
4900
5686
|
});
|
|
4901
5687
|
}
|
|
4902
5688
|
|
|
4903
|
-
const REQUEST_TAG = {
|
|
4904
|
-
engine: "workflow",
|
|
4905
|
-
deploy: "workflow.deploy",
|
|
4906
|
-
deleteDefinition: "workflow.delete-definition",
|
|
4907
|
-
start: "workflow.start",
|
|
4908
|
-
fireAction: "workflow.fire-action",
|
|
4909
|
-
editField: "workflow.edit-field",
|
|
4910
|
-
completeEffect: "workflow.complete-effect",
|
|
4911
|
-
commitEffectOps: "workflow.commit-effect-ops",
|
|
4912
|
-
tick: "workflow.tick",
|
|
4913
|
-
evaluate: "workflow.evaluate",
|
|
4914
|
-
evaluateStart: "workflow.evaluate-start",
|
|
4915
|
-
diagnose: "workflow.diagnose",
|
|
4916
|
-
availableActions: "workflow.available-actions",
|
|
4917
|
-
setStage: "workflow.set-stage",
|
|
4918
|
-
abort: "workflow.abort",
|
|
4919
|
-
getInstance: "workflow.get-instance",
|
|
4920
|
-
children: "workflow.children",
|
|
4921
|
-
instancesForDocument: "workflow.instances-for-document",
|
|
4922
|
-
definitionsForDocument: "workflow.definitions-for-document",
|
|
4923
|
-
query: "workflow.query",
|
|
4924
|
-
discover: "workflow.discover",
|
|
4925
|
-
guardQuery: "workflow.guard.query",
|
|
4926
|
-
guardDeploy: "workflow.guard.deploy",
|
|
4927
|
-
guardRefresh: "workflow.guard.refresh",
|
|
4928
|
-
guardRetract: "workflow.guard.retract",
|
|
4929
|
-
effectList: "workflow.effect.list",
|
|
4930
|
-
effectFind: "workflow.effect.find",
|
|
4931
|
-
drain: "workflow.drain",
|
|
4932
|
-
effect: "workflow.effect",
|
|
4933
|
-
verifyDefinitions: "workflow.verify-definitions",
|
|
4934
|
-
accessResolveActor: "workflow.access.resolve-actor",
|
|
4935
|
-
accessGrants: "workflow.access.grants"
|
|
4936
|
-
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
4937
|
-
|
|
4938
|
-
function unwrapPatch(patch) {
|
|
4939
|
-
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4940
|
-
}
|
|
4941
|
-
|
|
4942
|
-
const wrapperCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4943
|
-
|
|
4944
|
-
function unwrapRequestTag(client) {
|
|
4945
|
-
let current = client;
|
|
4946
|
-
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
4947
|
-
return current;
|
|
4948
|
-
}
|
|
4949
|
-
|
|
4950
|
-
function withRequestTag(client, fallback) {
|
|
4951
|
-
let byTag = wrapperCache.get(client);
|
|
4952
|
-
byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
|
|
4953
|
-
const cached = byTag.get(fallback);
|
|
4954
|
-
if (cached !== void 0) return cached;
|
|
4955
|
-
const wrapped = buildTaggedClient(client, fallback);
|
|
4956
|
-
return byTag.set(fallback, wrapped), wrapped;
|
|
4957
|
-
}
|
|
4958
|
-
|
|
4959
|
-
function isWorkflowsFamilyPrefix(prefix) {
|
|
4960
|
-
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4961
|
-
}
|
|
4962
|
-
|
|
4963
|
-
function clientRequestTagPrefix(client) {
|
|
4964
|
-
const probe = client;
|
|
4965
|
-
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4966
|
-
}
|
|
4967
|
-
|
|
4968
|
-
function buildTaggedClient(client, fallback) {
|
|
4969
|
-
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip && tag.startsWith("workflow.") ? tag.slice(9) : tag, stamp = options => options === void 0 ? {
|
|
4970
|
-
tag: normalize(fallback)
|
|
4971
|
-
} : options.tag === void 0 ? {
|
|
4972
|
-
...options,
|
|
4973
|
-
tag: normalize(fallback)
|
|
4974
|
-
} : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
|
|
4975
|
-
...options,
|
|
4976
|
-
tag: normalize(options.tag)
|
|
4977
|
-
} : options, wrapPatch = patch => {
|
|
4978
|
-
let target = patch;
|
|
4979
|
-
const wrapped = {
|
|
4980
|
-
get [RAW_PATCH]() {
|
|
4981
|
-
return target;
|
|
4982
|
-
},
|
|
4983
|
-
set: props => (target = target.set(props), wrapped),
|
|
4984
|
-
setIfMissing: props => (target = target.setIfMissing(props), wrapped),
|
|
4985
|
-
unset: paths => (target = target.unset(paths), wrapped),
|
|
4986
|
-
ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
|
|
4987
|
-
commit: options => target.commit(stamp(options))
|
|
4988
|
-
};
|
|
4989
|
-
return wrapped;
|
|
4990
|
-
}, wrapTransaction = tx => {
|
|
4991
|
-
let target = tx;
|
|
4992
|
-
const wrapped = {
|
|
4993
|
-
create: doc => (target = target.create(doc), wrapped),
|
|
4994
|
-
patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
|
|
4995
|
-
delete: id => (target = target.delete(id), wrapped),
|
|
4996
|
-
commit: options => target.commit(stamp(options))
|
|
4997
|
-
};
|
|
4998
|
-
return wrapped;
|
|
4999
|
-
};
|
|
5000
|
-
return {
|
|
5001
|
-
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
5002
|
-
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
5003
|
-
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
5004
|
-
patch: documentId => wrapPatch(client.patch(documentId)),
|
|
5005
|
-
create: (doc, options) => client.create(doc, stamp(options)),
|
|
5006
|
-
transaction: () => wrapTransaction(client.transaction()),
|
|
5007
|
-
...client.withConfig !== void 0 ? {
|
|
5008
|
-
withConfig: config => withRequestTag(client.withConfig(config), fallback)
|
|
5009
|
-
} : {},
|
|
5010
|
-
...client.action !== void 0 ? {
|
|
5011
|
-
action: (action, options) => client.action(action, stamp(options))
|
|
5012
|
-
} : {},
|
|
5013
|
-
...client.request !== void 0 ? {
|
|
5014
|
-
request: opts => client.request(stamp(opts))
|
|
5015
|
-
} : {}
|
|
5016
|
-
};
|
|
5017
|
-
}
|
|
5018
|
-
|
|
5019
|
-
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
5020
|
-
|
|
5021
|
-
function pinApiVersion(client) {
|
|
5022
|
-
const raw = unwrapRequestTag(client);
|
|
5023
|
-
if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
|
|
5024
|
-
let sibling = pinCache.get(raw);
|
|
5025
|
-
return sibling === void 0 && (sibling = raw.withConfig({
|
|
5026
|
-
apiVersion: ENGINE_API_VERSION
|
|
5027
|
-
}), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
|
|
5028
|
-
}
|
|
5029
|
-
|
|
5030
|
-
function taggedResolver(resolver, fallback) {
|
|
5031
|
-
if (resolver !== void 0) return parsed => {
|
|
5032
|
-
const client = resolver(parsed);
|
|
5033
|
-
return client === void 0 ? void 0 : withRequestTag(pinApiVersion(client), fallback);
|
|
5034
|
-
};
|
|
5035
|
-
}
|
|
5036
|
-
|
|
5037
|
-
function taggedScope(args, tag) {
|
|
5038
|
-
const resourceClients = taggedResolver(args.resourceClients, tag);
|
|
5039
|
-
return {
|
|
5040
|
-
...args,
|
|
5041
|
-
client: withRequestTag(pinApiVersion(args.client), tag),
|
|
5042
|
-
...resourceClients !== void 0 ? {
|
|
5043
|
-
resourceClients: resourceClients
|
|
5044
|
-
} : {}
|
|
5045
|
-
};
|
|
5046
|
-
}
|
|
5047
|
-
|
|
5048
5689
|
async function fetchGuards(args) {
|
|
5049
5690
|
return (await args.client.fetch(args.query, args.params, {
|
|
5050
5691
|
tag: REQUEST_TAG.guardQuery
|
|
@@ -5061,16 +5702,20 @@ function guardsForResource(client) {
|
|
|
5061
5702
|
});
|
|
5062
5703
|
}
|
|
5063
5704
|
|
|
5064
|
-
function
|
|
5705
|
+
function instancesGuardQuery(instanceIds) {
|
|
5065
5706
|
return {
|
|
5066
|
-
query: "*[_type == $guardType && sourceInstanceId
|
|
5707
|
+
query: "*[_type == $guardType && sourceInstanceId in $instanceIds] | order(_id asc)",
|
|
5067
5708
|
params: {
|
|
5068
5709
|
guardType: GUARD_DOC_TYPE,
|
|
5069
|
-
|
|
5710
|
+
instanceIds: [ ...instanceIds ]
|
|
5070
5711
|
}
|
|
5071
5712
|
};
|
|
5072
5713
|
}
|
|
5073
5714
|
|
|
5715
|
+
function instanceGuardQuery(instanceId) {
|
|
5716
|
+
return instancesGuardQuery([ instanceId ]);
|
|
5717
|
+
}
|
|
5718
|
+
|
|
5074
5719
|
function verdictGuardsForInstance(client, instanceId) {
|
|
5075
5720
|
const {query: query, params: params} = instanceGuardQuery(instanceId);
|
|
5076
5721
|
return fetchGuards({
|
|
@@ -5172,7 +5817,7 @@ function dedupById(guards) {
|
|
|
5172
5817
|
return [ ...new Map(guards.map(g => [ g._id, g ])).values() ].sort((a, b) => a._id.localeCompare(b._id));
|
|
5173
5818
|
}
|
|
5174
5819
|
|
|
5175
|
-
const GUARD_OWNER = "robot:workflow-engine";
|
|
5820
|
+
const GUARD_OWNER = "robot:workflow-engine", DELETE_CHUNK_SIZE = 200;
|
|
5176
5821
|
|
|
5177
5822
|
function resolveGuardRoute(guard, ctx) {
|
|
5178
5823
|
const targets = resolveIdRefTargets(guard.match.idRefs, ctx);
|
|
@@ -5225,10 +5870,9 @@ function resolveGuard({guard: guard, instance: instance, stageName: stageName, n
|
|
|
5225
5870
|
};
|
|
5226
5871
|
}
|
|
5227
5872
|
|
|
5228
|
-
async function upsertGuard(
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
})) {
|
|
5873
|
+
async function upsertGuard(args) {
|
|
5874
|
+
const {client: client, doc: doc, exists: exists} = args;
|
|
5875
|
+
if (!exists) {
|
|
5232
5876
|
await client.create(doc, {
|
|
5233
5877
|
...SYNC_COMMIT,
|
|
5234
5878
|
tag: REQUEST_TAG.guardDeploy
|
|
@@ -5254,7 +5898,9 @@ function resolvedStageGuards(args) {
|
|
|
5254
5898
|
});
|
|
5255
5899
|
resolved !== null && out.push({
|
|
5256
5900
|
client: args.clientForGdr(resolved.routeGdr),
|
|
5257
|
-
|
|
5901
|
+
resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(resolved.routeGdr)),
|
|
5902
|
+
value: resolved.doc,
|
|
5903
|
+
guard: guard
|
|
5258
5904
|
});
|
|
5259
5905
|
}
|
|
5260
5906
|
return out;
|
|
@@ -5271,12 +5917,54 @@ function resolvedStageGuardRoutes(args) {
|
|
|
5271
5917
|
const route = resolveGuardRoute(guard, ctx);
|
|
5272
5918
|
route !== null && out.push({
|
|
5273
5919
|
client: args.clientForGdr(route.routeGdr),
|
|
5274
|
-
|
|
5920
|
+
resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(route.routeGdr)),
|
|
5921
|
+
value: route.guardId
|
|
5275
5922
|
});
|
|
5276
5923
|
}
|
|
5277
5924
|
return out;
|
|
5278
5925
|
}
|
|
5279
5926
|
|
|
5927
|
+
function groupByResource(routed) {
|
|
5928
|
+
const groups = /* @__PURE__ */ new Map;
|
|
5929
|
+
for (const item of routed) {
|
|
5930
|
+
const existing = groups.get(item.resourceKey);
|
|
5931
|
+
if (existing !== void 0) {
|
|
5932
|
+
existing.values.push(item.value);
|
|
5933
|
+
continue;
|
|
5934
|
+
}
|
|
5935
|
+
groups.set(item.resourceKey, {
|
|
5936
|
+
client: item.client,
|
|
5937
|
+
resourceKey: item.resourceKey,
|
|
5938
|
+
values: [ item.value ]
|
|
5939
|
+
});
|
|
5940
|
+
}
|
|
5941
|
+
return [ ...groups.values() ];
|
|
5942
|
+
}
|
|
5943
|
+
|
|
5944
|
+
async function existingGuardIds(groups) {
|
|
5945
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: values}) => {
|
|
5946
|
+
const ids = values.map(doc => doc._id), existing = await client.fetch("*[_id in $ids]._id", {
|
|
5947
|
+
ids: ids
|
|
5948
|
+
}, {
|
|
5949
|
+
tag: REQUEST_TAG.guardDeploy
|
|
5950
|
+
});
|
|
5951
|
+
return [ resourceKey, new Set(existing) ];
|
|
5952
|
+
}));
|
|
5953
|
+
return new Map(entries);
|
|
5954
|
+
}
|
|
5955
|
+
|
|
5956
|
+
async function observedGuards(groups) {
|
|
5957
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: ids}) => {
|
|
5958
|
+
const guards = await client.fetch("*[_id in $ids]{_id, predicate, _rev}", {
|
|
5959
|
+
ids: ids
|
|
5960
|
+
}, {
|
|
5961
|
+
tag: REQUEST_TAG.guardRetract
|
|
5962
|
+
});
|
|
5963
|
+
return [ resourceKey, new Map(guards.map(guard => [ guard._id, guard ])) ];
|
|
5964
|
+
}));
|
|
5965
|
+
return new Map(entries);
|
|
5966
|
+
}
|
|
5967
|
+
|
|
5280
5968
|
async function committedInstance(args) {
|
|
5281
5969
|
return getInstanceDocument(args.client, args.instance._id);
|
|
5282
5970
|
}
|
|
@@ -5284,10 +5972,22 @@ async function committedInstance(args) {
|
|
|
5284
5972
|
async function deployStageGuards(args) {
|
|
5285
5973
|
const live = await committedInstance(args);
|
|
5286
5974
|
if (live === void 0 || live.currentStage !== args.stageName || live.abortedAt !== void 0) return;
|
|
5975
|
+
const routed = resolvedStageGuards(args), existingByResource = await existingGuardIds(groupByResource(routed));
|
|
5287
5976
|
let deployed = 0;
|
|
5288
|
-
for (const {client: client, doc:
|
|
5977
|
+
for (const {client: client, resourceKey: resourceKey, value: doc, guard: guard} of routed) {
|
|
5289
5978
|
try {
|
|
5290
|
-
await
|
|
5979
|
+
const localized = await localizeGuardMetadata({
|
|
5980
|
+
doc: doc,
|
|
5981
|
+
guard: guard,
|
|
5982
|
+
client: client,
|
|
5983
|
+
instance: args.instance,
|
|
5984
|
+
definition: args.definition
|
|
5985
|
+
});
|
|
5986
|
+
await upsertGuard({
|
|
5987
|
+
client: client,
|
|
5988
|
+
doc: localized,
|
|
5989
|
+
exists: existingByResource.get(resourceKey)?.has(doc._id) ?? !1
|
|
5990
|
+
});
|
|
5291
5991
|
} catch (cause) {
|
|
5292
5992
|
throw deployed > 0 ? new PartialGuardDeployError({
|
|
5293
5993
|
stageName: args.stageName,
|
|
@@ -5300,13 +6000,11 @@ async function deployStageGuards(args) {
|
|
|
5300
6000
|
}
|
|
5301
6001
|
|
|
5302
6002
|
async function retractStageGuards(args) {
|
|
5303
|
-
const observed = [];
|
|
5304
|
-
for (const {client: client,
|
|
5305
|
-
const guard =
|
|
5306
|
-
tag: REQUEST_TAG.guardRetract
|
|
5307
|
-
});
|
|
6003
|
+
const observed = [], routed = resolvedStageGuardRoutes(args), guardsByResource = await observedGuards(groupByResource(routed));
|
|
6004
|
+
for (const {client: client, resourceKey: resourceKey, value: guardId} of routed) {
|
|
6005
|
+
const guard = guardsByResource.get(resourceKey)?.get(guardId);
|
|
5308
6006
|
if (guard) {
|
|
5309
|
-
if (guard._rev === void 0) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
6007
|
+
if (guard._rev === void 0 || guard._rev === null) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
5310
6008
|
observed.push({
|
|
5311
6009
|
client: client,
|
|
5312
6010
|
guardId: guardId,
|
|
@@ -5337,10 +6035,11 @@ async function deleteOrphanedDefinitionGuards(args) {
|
|
|
5337
6035
|
let count = 0;
|
|
5338
6036
|
for (const {client: resourceClient, guards: guards} of perClient) {
|
|
5339
6037
|
const own = guards.filter(guard => guard.sourceInstanceId.startsWith(ownPartitionPrefix));
|
|
5340
|
-
if (own.length
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
6038
|
+
if (own.length !== 0) for (let start = 0; start < own.length; start += DELETE_CHUNK_SIZE) {
|
|
6039
|
+
const chunk = own.slice(start, start + DELETE_CHUNK_SIZE), tx = resourceClient.transaction();
|
|
6040
|
+
for (const guard of chunk) tx.delete(guard._id);
|
|
6041
|
+
await tx.commit(), count += chunk.length;
|
|
6042
|
+
}
|
|
5344
6043
|
}
|
|
5345
6044
|
return count;
|
|
5346
6045
|
}
|
|
@@ -5406,7 +6105,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5406
6105
|
...actor !== void 0 ? {
|
|
5407
6106
|
actor: actor
|
|
5408
6107
|
} : {}
|
|
5409
|
-
}), mutation.completedAt = at, mutation.abortedAt = at
|
|
6108
|
+
}), mutation.completedAt = at, mutation.abortedAt = at;
|
|
6109
|
+
const instance = readInstanceDoc(await persist(ctx, mutation));
|
|
5410
6110
|
await retractStageGuards({
|
|
5411
6111
|
client: ctx.client,
|
|
5412
6112
|
clientForGdr: ctx.clientForGdr,
|
|
@@ -5426,7 +6126,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5426
6126
|
});
|
|
5427
6127
|
return {
|
|
5428
6128
|
fired: !0,
|
|
5429
|
-
stage: stage.name
|
|
6129
|
+
stage: stage.name,
|
|
6130
|
+
instance: instance
|
|
5430
6131
|
};
|
|
5431
6132
|
}
|
|
5432
6133
|
|
|
@@ -6178,18 +6879,42 @@ async function fetchGrants(args) {
|
|
|
6178
6879
|
});
|
|
6179
6880
|
}
|
|
6180
6881
|
|
|
6181
|
-
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}) {
|
|
6182
6895
|
if (grants === void 0) return;
|
|
6183
6896
|
const can = {};
|
|
6184
6897
|
for (const permission of invariants.DOCUMENT_VALUE_PERMISSIONS) can[permission] = await grantsPermissionOn({
|
|
6185
6898
|
document: instance,
|
|
6186
6899
|
grants: grants,
|
|
6187
6900
|
permission: permission,
|
|
6188
|
-
userId:
|
|
6901
|
+
userId: identity
|
|
6189
6902
|
});
|
|
6190
6903
|
return can;
|
|
6191
6904
|
}
|
|
6192
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
|
+
|
|
6193
6918
|
function subjectDenialLabels(denied) {
|
|
6194
6919
|
return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
|
|
6195
6920
|
}
|
|
@@ -6210,10 +6935,10 @@ class ActionDisabledError extends invariants.WorkflowError {
|
|
|
6210
6935
|
|
|
6211
6936
|
class StartNotAllowedError extends invariants.WorkflowError {
|
|
6212
6937
|
definition;
|
|
6213
|
-
|
|
6938
|
+
unmetRequirements;
|
|
6214
6939
|
constructor(args) {
|
|
6215
|
-
super("start-not-allowed", `startInstance refused
|
|
6216
|
-
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;
|
|
6217
6942
|
}
|
|
6218
6943
|
}
|
|
6219
6944
|
|
|
@@ -6229,7 +6954,7 @@ const disabledReasonDetail = {
|
|
|
6229
6954
|
"stage-terminal": r => `stage "${r.stage}" is terminal`,
|
|
6230
6955
|
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6231
6956
|
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6232
|
-
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
|
|
6957
|
+
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
|
|
6233
6958
|
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
6234
6959
|
};
|
|
6235
6960
|
|
|
@@ -6298,11 +7023,10 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
|
|
|
6298
7023
|
}
|
|
6299
7024
|
});
|
|
6300
7025
|
if (action.filter !== void 0) {
|
|
6301
|
-
const can =
|
|
7026
|
+
const can = await advisoryCanForCall({
|
|
6302
7027
|
instance: ctx.instance,
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
}) : void 0;
|
|
7028
|
+
options: options
|
|
7029
|
+
});
|
|
6306
7030
|
if (!await ctxEvaluateCondition({
|
|
6307
7031
|
ctx: ctx,
|
|
6308
7032
|
condition: action.filter,
|
|
@@ -6543,42 +7267,24 @@ async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: acti
|
|
|
6543
7267
|
entry.firedActions = [ ...entry.firedActions ?? [], action.name ];
|
|
6544
7268
|
const {ranOps: ranOps} = await applyActionFire({
|
|
6545
7269
|
ctx: ctx,
|
|
6546
|
-
mutation: mutation,
|
|
6547
|
-
activity: activity,
|
|
6548
|
-
action: action,
|
|
6549
|
-
params: {},
|
|
6550
|
-
actor: ctx.actor,
|
|
6551
|
-
triggered: !0
|
|
6552
|
-
});
|
|
6553
|
-
return {
|
|
6554
|
-
ranFieldOps: ranOps.some(isFieldOp)
|
|
6555
|
-
};
|
|
6556
|
-
}
|
|
6557
|
-
|
|
6558
|
-
async function primeInitialStage(
|
|
6559
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
6560
|
-
if (!instance || instance.stages.length > 0) return;
|
|
6561
|
-
const
|
|
6562
|
-
if (stage === void 0) return;
|
|
6563
|
-
const ctx =
|
|
6564
|
-
client: client,
|
|
6565
|
-
clientForGdr: clientForGdr,
|
|
6566
|
-
refSurface: refSurface,
|
|
6567
|
-
instance: instance,
|
|
6568
|
-
definition: definition,
|
|
6569
|
-
...clock ? {
|
|
6570
|
-
clock: clock
|
|
6571
|
-
} : {},
|
|
6572
|
-
...actor ? {
|
|
6573
|
-
actor: actor
|
|
6574
|
-
} : {},
|
|
6575
|
-
...executionContext ? {
|
|
6576
|
-
executionContext: executionContext
|
|
6577
|
-
} : {},
|
|
6578
|
-
...telemetry ? {
|
|
6579
|
-
telemetry: telemetry
|
|
6580
|
-
} : {}
|
|
6581
|
-
}), now = ctx.now, discards = [], initialStageEntry = {
|
|
7270
|
+
mutation: mutation,
|
|
7271
|
+
activity: activity,
|
|
7272
|
+
action: action,
|
|
7273
|
+
params: {},
|
|
7274
|
+
actor: ctx.actor,
|
|
7275
|
+
triggered: !0
|
|
7276
|
+
});
|
|
7277
|
+
return {
|
|
7278
|
+
ranFieldOps: ranOps.some(isFieldOp)
|
|
7279
|
+
};
|
|
7280
|
+
}
|
|
7281
|
+
|
|
7282
|
+
async function primeInitialStage(args) {
|
|
7283
|
+
const {client: client, instanceId: instanceId, refSurface: refSurface, clientForGdr: clientForGdr} = args, instance = await getInstanceDocument(client, instanceId);
|
|
7284
|
+
if (!instance || instance.stages.length > 0) return;
|
|
7285
|
+
const ctx = await buildCascadeStepContext(args, instance), {definition: definition} = ctx, stage = definition.stages.find(s => s.name === instance.currentStage);
|
|
7286
|
+
if (stage === void 0) return;
|
|
7287
|
+
const now = ctx.now, discards = [], initialStageEntry = {
|
|
6582
7288
|
_key: randomKey(),
|
|
6583
7289
|
name: stage.name,
|
|
6584
7290
|
enteredAt: now,
|
|
@@ -6647,29 +7353,37 @@ async function primeInitialStage({client: client, instanceId: instanceId, actor:
|
|
|
6647
7353
|
|
|
6648
7354
|
const CASCADE_LIMIT = 100;
|
|
6649
7355
|
|
|
6650
|
-
async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
6651
|
-
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({
|
|
6652
7379
|
client: client,
|
|
6653
7380
|
instanceId: instanceId,
|
|
6654
|
-
options:
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
...clock ? {
|
|
6661
|
-
clock: clock
|
|
6662
|
-
} : {},
|
|
6663
|
-
...executionContext ? {
|
|
6664
|
-
executionContext: executionContext
|
|
6665
|
-
} : {},
|
|
6666
|
-
...telemetry ? {
|
|
6667
|
-
telemetry: telemetry
|
|
6668
|
-
} : {},
|
|
6669
|
-
...overlay ? {
|
|
6670
|
-
overlay: overlay
|
|
6671
|
-
} : {}
|
|
6672
|
-
}
|
|
7381
|
+
options: contextOptions
|
|
7382
|
+
}) : await buildEngineContext({
|
|
7383
|
+
client: client,
|
|
7384
|
+
instance: instance,
|
|
7385
|
+
definition: invariants.parseDefinitionSnapshot(instance),
|
|
7386
|
+
...contextOptions
|
|
6673
7387
|
});
|
|
6674
7388
|
if (isTerminal(ctx)) return {
|
|
6675
7389
|
moved: !1
|
|
@@ -6699,10 +7413,10 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
|
|
|
6699
7413
|
});
|
|
6700
7414
|
}
|
|
6701
7415
|
|
|
6702
|
-
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}) {
|
|
6703
7417
|
let count = 0;
|
|
6704
7418
|
for (;;) {
|
|
6705
|
-
|
|
7419
|
+
const drained = await drainCondemnedChildren({
|
|
6706
7420
|
client: client,
|
|
6707
7421
|
instanceId: instanceId,
|
|
6708
7422
|
actor: actor,
|
|
@@ -6711,7 +7425,8 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6711
7425
|
clock: clock,
|
|
6712
7426
|
executionContext: executionContext,
|
|
6713
7427
|
telemetry: telemetry
|
|
6714
|
-
})
|
|
7428
|
+
});
|
|
7429
|
+
if (!(await runCascadeHop({
|
|
6715
7430
|
client: client,
|
|
6716
7431
|
instanceId: instanceId,
|
|
6717
7432
|
actor: actor,
|
|
@@ -6720,7 +7435,11 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6720
7435
|
clock: clock,
|
|
6721
7436
|
executionContext: executionContext,
|
|
6722
7437
|
telemetry: telemetry,
|
|
6723
|
-
overlay: overlay
|
|
7438
|
+
overlay: overlay,
|
|
7439
|
+
settlingCohorts: settlingCohorts,
|
|
7440
|
+
...drained.drained ? {} : {
|
|
7441
|
+
instance: drained.instance
|
|
7442
|
+
}
|
|
6724
7443
|
})).moved) return count;
|
|
6725
7444
|
if (count++, count >= CASCADE_LIMIT) throw new CascadeLimitError({
|
|
6726
7445
|
instanceId: instanceId,
|
|
@@ -6729,39 +7448,50 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6729
7448
|
}
|
|
6730
7449
|
}
|
|
6731
7450
|
|
|
6732
|
-
async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set}) {
|
|
6733
|
-
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
|
+
};
|
|
6734
7456
|
draining.add(instanceId);
|
|
6735
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
6736
|
-
if (!instance) return
|
|
7457
|
+
const instance = preloadedInstance ?? await getInstanceDocument(client, instanceId);
|
|
7458
|
+
if (!instance) return {
|
|
7459
|
+
instance: void 0,
|
|
7460
|
+
drained: !1
|
|
7461
|
+
};
|
|
6737
7462
|
const condemned = condemnedSubworkflows(instance);
|
|
6738
|
-
if (condemned.length
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
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
|
+
};
|
|
6759
7489
|
}
|
|
6760
7490
|
|
|
6761
7491
|
async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
|
|
6762
7492
|
const childId = invariants.toBareId(row.ref.id);
|
|
6763
7493
|
try {
|
|
6764
|
-
await abortInstance({
|
|
7494
|
+
const result = await abortInstance({
|
|
6765
7495
|
client: client,
|
|
6766
7496
|
instanceId: childId,
|
|
6767
7497
|
reason: row.abortPending?.reason ?? "condemned by parent",
|
|
@@ -6781,7 +7511,8 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6781
7511
|
telemetry: telemetry
|
|
6782
7512
|
} : {}
|
|
6783
7513
|
}
|
|
6784
|
-
})
|
|
7514
|
+
});
|
|
7515
|
+
await drainCondemnedChildren({
|
|
6785
7516
|
client: client,
|
|
6786
7517
|
instanceId: childId,
|
|
6787
7518
|
actor: actor,
|
|
@@ -6790,7 +7521,10 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6790
7521
|
clock: clock,
|
|
6791
7522
|
executionContext: executionContext,
|
|
6792
7523
|
telemetry: telemetry,
|
|
6793
|
-
draining: draining
|
|
7524
|
+
draining: draining,
|
|
7525
|
+
...result.fired ? {
|
|
7526
|
+
instance: result.instance
|
|
7527
|
+
} : {}
|
|
6794
7528
|
});
|
|
6795
7529
|
} catch (cause) {
|
|
6796
7530
|
if (cause instanceof invariants.InstanceNotFoundError) return;
|
|
@@ -6803,9 +7537,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6803
7537
|
}
|
|
6804
7538
|
|
|
6805
7539
|
async function stampDrainedRows({client: client, instance: instance, condemned: condemned, clock: clock, executionContext: executionContext}) {
|
|
6806
|
-
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)),
|
|
6807
|
-
ids: ids
|
|
6808
|
-
}), 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 => {
|
|
6809
7541
|
if (row.resolved !== void 0 || !condemnedKeys.has(row._key)) return row;
|
|
6810
7542
|
const child = byId.get(invariants.toBareId(row.ref.id)), resolved = child !== void 0 ? terminalResolution(child) : {
|
|
6811
7543
|
at: now,
|
|
@@ -6827,6 +7559,16 @@ async function stampDrainedRows({client: client, instance: instance, condemned:
|
|
|
6827
7559
|
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
6828
7560
|
}
|
|
6829
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
|
+
|
|
6830
7572
|
function terminalResolution(child) {
|
|
6831
7573
|
const status = resolvedChildStatus(child);
|
|
6832
7574
|
if (!(status === void 0 || child.completedAt === void 0 || child.completedAt === null)) return {
|
|
@@ -6849,28 +7591,18 @@ function subworkflowResolvedEntry({row: row, at: at, status: status}) {
|
|
|
6849
7591
|
};
|
|
6850
7592
|
}
|
|
6851
7593
|
|
|
6852
|
-
async function propagateToAncestors(
|
|
6853
|
-
const loaded = await loadPropagationPair(
|
|
6854
|
-
if (loaded === void 0) return;
|
|
6855
|
-
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({
|
|
6856
7596
|
client: client,
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
definition: definition,
|
|
6861
|
-
...clock ? {
|
|
6862
|
-
clock: clock
|
|
6863
|
-
} : {},
|
|
6864
|
-
...actor ? {
|
|
6865
|
-
actor: actor
|
|
6866
|
-
} : {},
|
|
6867
|
-
...executionContext ? {
|
|
6868
|
-
executionContext: executionContext
|
|
6869
|
-
} : {},
|
|
6870
|
-
...telemetry ? {
|
|
6871
|
-
telemetry: telemetry
|
|
7597
|
+
instanceId: instanceId,
|
|
7598
|
+
...instance !== void 0 ? {
|
|
7599
|
+
instance: instance
|
|
6872
7600
|
} : {}
|
|
6873
|
-
})
|
|
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);
|
|
6874
7606
|
if (row === void 0) {
|
|
6875
7607
|
await recordOrphanedPropagation({
|
|
6876
7608
|
ctx: ctx,
|
|
@@ -6885,29 +7617,11 @@ async function propagateToAncestors({client: client, instanceId: instanceId, act
|
|
|
6885
7617
|
child: child,
|
|
6886
7618
|
now: ctx.now
|
|
6887
7619
|
}), parentTerminal = parent.completedAt !== void 0;
|
|
6888
|
-
changed && await persist(ctx, mutation), !parentTerminal &&
|
|
6889
|
-
client: client,
|
|
6890
|
-
instanceId: parent._id,
|
|
6891
|
-
actor: actor,
|
|
6892
|
-
clientForGdr: clientForGdr,
|
|
6893
|
-
refSurface: refSurface,
|
|
6894
|
-
clock: clock,
|
|
6895
|
-
executionContext: executionContext,
|
|
6896
|
-
telemetry: telemetry
|
|
6897
|
-
}), await propagateToAncestors({
|
|
6898
|
-
client: client,
|
|
6899
|
-
instanceId: parent._id,
|
|
6900
|
-
actor: actor,
|
|
6901
|
-
clientForGdr: clientForGdr,
|
|
6902
|
-
refSurface: refSurface,
|
|
6903
|
-
clock: clock,
|
|
6904
|
-
executionContext: executionContext,
|
|
6905
|
-
telemetry: telemetry
|
|
6906
|
-
}));
|
|
7620
|
+
changed && await persist(ctx, mutation), !parentTerminal && await cascadeAndPropagateParent(stepArgs, parent);
|
|
6907
7621
|
}
|
|
6908
7622
|
|
|
6909
|
-
async function loadPropagationPair(client, instanceId) {
|
|
6910
|
-
const child = await getInstanceDocument(client, instanceId);
|
|
7623
|
+
async function loadPropagationPair({client: client, instanceId: instanceId, instance: instance}) {
|
|
7624
|
+
const child = instance ?? await getInstanceDocument(client, instanceId);
|
|
6911
7625
|
if (!child) return;
|
|
6912
7626
|
const parentGdr = invariants.parentRef(child);
|
|
6913
7627
|
if (parentGdr === void 0) return;
|
|
@@ -6918,6 +7632,83 @@ async function loadPropagationPair(client, instanceId) {
|
|
|
6918
7632
|
};
|
|
6919
7633
|
}
|
|
6920
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
|
+
|
|
6921
7712
|
function stampResolvedChild({mutation: mutation, row: row, child: child, now: now}) {
|
|
6922
7713
|
if (row.resolved !== void 0) return !1;
|
|
6923
7714
|
const resolved = terminalResolution(child);
|
|
@@ -7053,36 +7844,14 @@ async function persist(ctx, mutation) {
|
|
|
7053
7844
|
for (const {body: body} of pendingCreates) tx.create(body);
|
|
7054
7845
|
tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
|
|
7055
7846
|
await tx.commit(), mutation.pendingCreates = [];
|
|
7056
|
-
const actorForPriming = ctx.actor;
|
|
7057
|
-
for (const {body: body
|
|
7058
|
-
|
|
7059
|
-
client: ctx.client,
|
|
7060
|
-
instanceId: body._id,
|
|
7061
|
-
actor: actorForPriming,
|
|
7062
|
-
clientForGdr: ctx.clientForGdr,
|
|
7063
|
-
refSurface: ctx.refSurface,
|
|
7064
|
-
clock: ctx.clock,
|
|
7065
|
-
executionContext: ctx.executionContext,
|
|
7066
|
-
telemetry: ctx.telemetry
|
|
7067
|
-
}), await cascadeAutoTransitions({
|
|
7068
|
-
client: ctx.client,
|
|
7069
|
-
instanceId: body._id,
|
|
7070
|
-
actor: actorForPriming,
|
|
7071
|
-
clientForGdr: ctx.clientForGdr,
|
|
7072
|
-
refSurface: ctx.refSurface,
|
|
7073
|
-
clock: ctx.clock,
|
|
7074
|
-
executionContext: ctx.executionContext,
|
|
7075
|
-
telemetry: ctx.telemetry
|
|
7076
|
-
}), await propagateToAncestors({
|
|
7077
|
-
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, {
|
|
7078
7850
|
instanceId: body._id,
|
|
7079
7851
|
actor: actorForPriming,
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
executionContext: ctx.executionContext,
|
|
7084
|
-
telemetry: ctx.telemetry
|
|
7085
|
-
}), ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7852
|
+
settlingCohorts: settlingCohorts
|
|
7853
|
+
});
|
|
7854
|
+
await primeInitialStage(stepArgs), await cascadeAutoTransitions(stepArgs);
|
|
7086
7855
|
} catch (cause) {
|
|
7087
7856
|
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7088
7857
|
instanceId: ctx.instance._id,
|
|
@@ -7090,11 +7859,50 @@ async function persist(ctx, mutation) {
|
|
|
7090
7859
|
reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
|
|
7091
7860
|
});
|
|
7092
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);
|
|
7093
7868
|
const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
|
|
7094
7869
|
if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
|
|
7095
7870
|
return reloaded;
|
|
7096
7871
|
}
|
|
7097
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
|
+
|
|
7098
7906
|
function stampExecutionContext(ctx, mutation) {
|
|
7099
7907
|
const stamp = ctx.executionContext, appended = mutation.history.slice(ctx.instance.history.length);
|
|
7100
7908
|
mutation.history = [ ...mutation.history.slice(0, ctx.instance.history.length), ...stampHistoryEntries(appended, stamp) ];
|
|
@@ -7222,24 +8030,25 @@ function buildEffectSettlement(pending, outcome) {
|
|
|
7222
8030
|
}
|
|
7223
8031
|
|
|
7224
8032
|
function validateEffectOutputs(args) {
|
|
7225
|
-
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 = {};
|
|
7226
8034
|
for (const [key, value] of Object.entries(outputs)) {
|
|
7227
8035
|
const shape = byName.get(key);
|
|
7228
8036
|
if (shape === void 0) {
|
|
7229
8037
|
issues.push(`"${key}" is not a declared output`);
|
|
7230
8038
|
continue;
|
|
7231
8039
|
}
|
|
7232
|
-
const
|
|
7233
|
-
|
|
8040
|
+
const check = effectOutputCheck(shape, value);
|
|
8041
|
+
"issues" in check ? issues.push(...check.issues.map(i => `"${key}": ${i}`)) : normalized[key] = check.output;
|
|
7234
8042
|
}
|
|
7235
8043
|
if (issues.length > 0) throw new EffectOutputsInvalidError({
|
|
7236
8044
|
effect: effectName,
|
|
7237
8045
|
issues: issues
|
|
7238
8046
|
});
|
|
8047
|
+
return normalized;
|
|
7239
8048
|
}
|
|
7240
8049
|
|
|
7241
|
-
function
|
|
7242
|
-
return invariants.
|
|
8050
|
+
function effectOutputCheck(shape, value) {
|
|
8051
|
+
return invariants.parseFieldValue({
|
|
7243
8052
|
entryType: shape.type,
|
|
7244
8053
|
value: value,
|
|
7245
8054
|
...shape.fields !== void 0 ? {
|
|
@@ -7285,15 +8094,15 @@ function validateCompletionInput({pending: pending, definition: definition, stat
|
|
|
7285
8094
|
effect: pending.name,
|
|
7286
8095
|
issues: [ "outputs cannot accompany a failed completion — report outputs on a done completion instead" ]
|
|
7287
8096
|
});
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
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
|
+
};
|
|
7297
8106
|
}
|
|
7298
8107
|
|
|
7299
8108
|
async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, actor: actor}) {
|
|
@@ -7302,7 +8111,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7302
8111
|
record: requestRecord,
|
|
7303
8112
|
now: ctx.now
|
|
7304
8113
|
});
|
|
7305
|
-
const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
|
|
8114
|
+
const pending = requirePendingEffect(ctx.instance, effectKey), {ops: validatedOps, outputs: validatedOutputs} = validateCompletionInput({
|
|
7306
8115
|
pending: pending,
|
|
7307
8116
|
definition: ctx.definition,
|
|
7308
8117
|
status: status,
|
|
@@ -7321,7 +8130,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7321
8130
|
detail: detail,
|
|
7322
8131
|
error: error,
|
|
7323
8132
|
durationMs: durationMs,
|
|
7324
|
-
outputs:
|
|
8133
|
+
outputs: validatedOutputs
|
|
7325
8134
|
});
|
|
7326
8135
|
mutation.effectHistory.push(settlement.run);
|
|
7327
8136
|
const wroteEffectOutputs = status === "done" && outputs !== void 0;
|
|
@@ -7519,6 +8328,64 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
|
|
|
7519
8328
|
};
|
|
7520
8329
|
}
|
|
7521
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
|
+
|
|
7522
8389
|
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
|
|
7523
8390
|
|
|
7524
8391
|
async function resolveAccess(taggedClient, args = {}) {
|
|
@@ -7528,10 +8395,13 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7528
8395
|
client: client,
|
|
7529
8396
|
requestFn: requestFn,
|
|
7530
8397
|
resourcePath: args.grantsFromPath
|
|
7531
|
-
}) : Promise.resolve(void 0), [
|
|
7532
|
-
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.");
|
|
7533
8400
|
return {
|
|
7534
|
-
actor: actor,
|
|
8401
|
+
actor: identity.actor,
|
|
8402
|
+
...identity.localPrincipalId !== void 0 ? {
|
|
8403
|
+
localPrincipalId: identity.localPrincipalId
|
|
8404
|
+
} : {},
|
|
7535
8405
|
...grants !== void 0 ? {
|
|
7536
8406
|
grants: grants
|
|
7537
8407
|
} : {}
|
|
@@ -7541,7 +8411,7 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7541
8411
|
function cachedActor(client, requestFn) {
|
|
7542
8412
|
const cached = actorCache.get(client);
|
|
7543
8413
|
if (cached !== void 0) return cached;
|
|
7544
|
-
const pending = fetchActor(requestFn).catch(err => {
|
|
8414
|
+
const pending = fetchActor(client, requestFn).catch(err => {
|
|
7545
8415
|
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
7546
8416
|
});
|
|
7547
8417
|
return actorCache.set(client, pending), pending;
|
|
@@ -7568,27 +8438,90 @@ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resou
|
|
|
7568
8438
|
byPath.set(resourcePath, cached)), cached;
|
|
7569
8439
|
}
|
|
7570
8440
|
|
|
7571
|
-
async function fetchActor(requestFn) {
|
|
7572
|
-
|
|
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) {
|
|
7573
8478
|
try {
|
|
7574
|
-
|
|
8479
|
+
return await requestFn({
|
|
7575
8480
|
uri: "/users/me",
|
|
7576
8481
|
tag: REQUEST_TAG.accessResolveActor
|
|
7577
8482
|
});
|
|
7578
8483
|
} catch (err) {
|
|
7579
|
-
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.`, {
|
|
7580
8485
|
cause: err
|
|
7581
8486
|
});
|
|
7582
8487
|
}
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
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"
|
|
7591
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
|
+
}
|
|
7592
8525
|
}
|
|
7593
8526
|
|
|
7594
8527
|
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
@@ -7764,35 +8697,48 @@ async function subjectResourceGrants(args) {
|
|
|
7764
8697
|
const resolved = await Promise.all([ ...clients.entries() ].map(async ([key, entry]) => {
|
|
7765
8698
|
const path = aclPathForResource(entry.resource);
|
|
7766
8699
|
if (path === void 0) return;
|
|
7767
|
-
const grants = await grantsForClientPath(entry.client, path);
|
|
7768
|
-
|
|
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
|
+
} ];
|
|
7769
8705
|
}));
|
|
7770
8706
|
return new Map(resolved.filter(entry => entry !== void 0));
|
|
7771
8707
|
}
|
|
7772
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
|
+
|
|
7773
8719
|
async function evaluateInstance(args) {
|
|
7774
8720
|
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
7775
8721
|
invariants.validateTag(tag);
|
|
7776
|
-
const
|
|
8722
|
+
const [access, instance] = await Promise.all([ resolveAccess(client, {
|
|
7777
8723
|
...args.grantsFromPath !== void 0 ? {
|
|
7778
8724
|
grantsFromPath: args.grantsFromPath
|
|
7779
8725
|
} : {}
|
|
7780
|
-
}),
|
|
8726
|
+
}), reload({
|
|
7781
8727
|
client: client,
|
|
7782
8728
|
instanceId: instanceId,
|
|
7783
8729
|
tag: tag
|
|
7784
|
-
}), definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
8730
|
+
}) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7785
8731
|
client: client,
|
|
7786
8732
|
workflowResource: workflowResource,
|
|
7787
8733
|
resourceClients: resourceClients
|
|
7788
|
-
}), snapshot = await hydrateSnapshot({
|
|
8734
|
+
}), [snapshot, guards, resourceGrants] = await Promise.all([ hydrateSnapshot({
|
|
7789
8735
|
client: client,
|
|
7790
8736
|
clientForGdr: clientForGdr,
|
|
7791
8737
|
instance: instance
|
|
7792
|
-
}),
|
|
8738
|
+
}), verdictGuardsForInstance(client, instance._id), subjectResourceGrants({
|
|
7793
8739
|
clientForGdr: clientForGdr,
|
|
7794
8740
|
instance: instance
|
|
7795
|
-
});
|
|
8741
|
+
}) ]);
|
|
7796
8742
|
return evaluateFromSnapshot({
|
|
7797
8743
|
instance: instance,
|
|
7798
8744
|
definition: definition,
|
|
@@ -7801,6 +8747,9 @@ async function evaluateInstance(args) {
|
|
|
7801
8747
|
guards: guards,
|
|
7802
8748
|
now: now,
|
|
7803
8749
|
resourceGrants: resourceGrants,
|
|
8750
|
+
...localPrincipalId !== void 0 ? {
|
|
8751
|
+
localPrincipalId: localPrincipalId
|
|
8752
|
+
} : {},
|
|
7804
8753
|
...grants !== void 0 ? {
|
|
7805
8754
|
grants: grants
|
|
7806
8755
|
} : {}
|
|
@@ -7856,9 +8805,12 @@ async function evaluateFromSnapshot(args) {
|
|
|
7856
8805
|
definition: definition,
|
|
7857
8806
|
snapshot: snapshot,
|
|
7858
8807
|
now: now
|
|
7859
|
-
},
|
|
7860
|
-
instance: instance,
|
|
8808
|
+
}, anchorIdentity = invariants.lakePrincipalId({
|
|
7861
8809
|
actor: actor,
|
|
8810
|
+
localPrincipalId: args.localPrincipalId
|
|
8811
|
+
}), can = await advisoryCan({
|
|
8812
|
+
instance: instance,
|
|
8813
|
+
identity: anchorIdentity,
|
|
7862
8814
|
grants: grants
|
|
7863
8815
|
}), scope = await renderConditionScope(scopeSource, {
|
|
7864
8816
|
actor: actor,
|
|
@@ -7875,11 +8827,10 @@ async function evaluateFromSnapshot(args) {
|
|
|
7875
8827
|
activityName: activityName
|
|
7876
8828
|
})), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
|
|
7877
8829
|
instance: instance,
|
|
7878
|
-
|
|
8830
|
+
identity: anchorIdentity,
|
|
7879
8831
|
guards: args.guards
|
|
7880
8832
|
}), subjectDenials = await forecastSubjectDenials({
|
|
7881
8833
|
instance: instance,
|
|
7882
|
-
actor: actor,
|
|
7883
8834
|
snapshot: snapshot,
|
|
7884
8835
|
resourceGrants: args.resourceGrants
|
|
7885
8836
|
}), subjectPermissionReason = subjectDenials.length > 0 ? {
|
|
@@ -8023,20 +8974,20 @@ async function editPredicateInsight(args) {
|
|
|
8023
8974
|
}
|
|
8024
8975
|
|
|
8025
8976
|
async function forecastSubjectDenials(args) {
|
|
8026
|
-
const {instance: instance,
|
|
8977
|
+
const {instance: instance, snapshot: snapshot, resourceGrants: resourceGrants} = args;
|
|
8027
8978
|
if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
|
|
8028
8979
|
const denials = [], seen = /* @__PURE__ */ new Set;
|
|
8029
8980
|
for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
|
|
8030
8981
|
if (seen.has(ref.id)) continue;
|
|
8031
8982
|
seen.add(ref.id);
|
|
8032
|
-
const
|
|
8033
|
-
if (
|
|
8983
|
+
const access = resourceGrants.get(invariants.resourceGdr(resource));
|
|
8984
|
+
if (access === void 0) continue;
|
|
8034
8985
|
const doc = snapshot.docs.find(d => d._id === ref.id);
|
|
8035
8986
|
doc !== void 0 && await subjectUpdateAllowed({
|
|
8036
8987
|
doc: doc,
|
|
8037
8988
|
parsed: parsed,
|
|
8038
|
-
grants: grants,
|
|
8039
|
-
actorId:
|
|
8989
|
+
grants: access.grants,
|
|
8990
|
+
actorId: access.actorId
|
|
8040
8991
|
}) === !1 && denials.push({
|
|
8041
8992
|
subject: ref.id,
|
|
8042
8993
|
resource: invariants.resourceGdr(resource),
|
|
@@ -8117,12 +9068,12 @@ async function explainActivityConditions({activity: activity, activityScope: act
|
|
|
8117
9068
|
snapshot: snapshot,
|
|
8118
9069
|
sites: sites
|
|
8119
9070
|
}), requirementEntries = [];
|
|
8120
|
-
for (const
|
|
9071
|
+
for (const requirement of activity.requirements ?? []) requirementEntries.push([ requirement, await explainAt({
|
|
8121
9072
|
kind: "requirement",
|
|
8122
9073
|
activity: activity.name,
|
|
8123
|
-
requirement: name
|
|
8124
|
-
},
|
|
8125
|
-
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({
|
|
8126
9077
|
site: {
|
|
8127
9078
|
kind: "activity-filter",
|
|
8128
9079
|
activity: activity.name
|
|
@@ -8268,12 +9219,12 @@ function actionEvaluationIdentity(action) {
|
|
|
8268
9219
|
};
|
|
8269
9220
|
}
|
|
8270
9221
|
|
|
8271
|
-
async function instanceGuardReason({instance: instance,
|
|
9222
|
+
async function instanceGuardReason({instance: instance, identity: identity, guards: guards}) {
|
|
8272
9223
|
if (guards === void 0 || guards.length === 0) return;
|
|
8273
9224
|
const denied = await instanceWriteDenials({
|
|
8274
9225
|
instance: instance,
|
|
8275
9226
|
guards: guards,
|
|
8276
|
-
identity:
|
|
9227
|
+
identity: identity
|
|
8277
9228
|
});
|
|
8278
9229
|
if (denied.length !== 0) return {
|
|
8279
9230
|
kind: "mutation-guard-denied",
|
|
@@ -8312,24 +9263,24 @@ function inFlightFilter() {
|
|
|
8312
9263
|
return "!defined(completedAt)";
|
|
8313
9264
|
}
|
|
8314
9265
|
|
|
8315
|
-
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";
|
|
8316
9267
|
|
|
8317
9268
|
function documentPrefilter(documents, params) {
|
|
8318
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)}`);
|
|
8319
9270
|
return params.documents = [ ...documents ], params.bareIds = documents.map(invariants.extractDocumentId),
|
|
8320
|
-
`_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}`;
|
|
8321
9272
|
}
|
|
8322
9273
|
|
|
8323
9274
|
function documentArm(filter, params) {
|
|
8324
9275
|
if (filter.documents === void 0 && filter.document === void 0) return;
|
|
8325
|
-
const documents = [ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ];
|
|
9276
|
+
const documents = [ .../* @__PURE__ */ new Set([ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ]) ].sort();
|
|
8326
9277
|
return documentPrefilter(documents, params);
|
|
8327
9278
|
}
|
|
8328
9279
|
|
|
8329
9280
|
function idsArm(filter, params) {
|
|
8330
9281
|
if (filter.ids !== void 0) {
|
|
8331
9282
|
for (const id of filter.ids) if (invariants.isGdrUri(id)) throw new invariants.ContractViolationError(`instancesQuery: every id must be a bare instance document id (an instance's _id is never resource-qualified); got a GDR URI: ${JSON.stringify(id)}`);
|
|
8332
|
-
return params.ids = [ ...filter.ids ], "_id in $ids";
|
|
9283
|
+
return params.ids = [ ...new Set(filter.ids) ].sort(), "_id in $ids";
|
|
8333
9284
|
}
|
|
8334
9285
|
}
|
|
8335
9286
|
|
|
@@ -8743,11 +9694,10 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
|
|
|
8743
9694
|
}
|
|
8744
9695
|
|
|
8745
9696
|
async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
|
|
8746
|
-
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can =
|
|
9697
|
+
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
|
|
8747
9698
|
instance: ctx.instance,
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
}) : 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({
|
|
8751
9701
|
ctx: ctx,
|
|
8752
9702
|
condition: site.effective,
|
|
8753
9703
|
opts: {
|
|
@@ -9105,8 +10055,7 @@ async function abortAndPropagate(args) {
|
|
|
9105
10055
|
executionContext: executionContext,
|
|
9106
10056
|
telemetry: telemetry
|
|
9107
10057
|
})
|
|
9108
|
-
})
|
|
9109
|
-
return await drainCondemnedChildren({
|
|
10058
|
+
}), drained = await drainCondemnedChildren({
|
|
9110
10059
|
client: client,
|
|
9111
10060
|
instanceId: instanceId,
|
|
9112
10061
|
actor: actor,
|
|
@@ -9118,8 +10067,12 @@ async function abortAndPropagate(args) {
|
|
|
9118
10067
|
} : {},
|
|
9119
10068
|
...telemetry !== void 0 ? {
|
|
9120
10069
|
telemetry: telemetry
|
|
10070
|
+
} : {},
|
|
10071
|
+
...result.fired ? {
|
|
10072
|
+
instance: result.instance
|
|
9121
10073
|
} : {}
|
|
9122
|
-
})
|
|
10074
|
+
});
|
|
10075
|
+
return await propagateToAncestors({
|
|
9123
10076
|
client: client,
|
|
9124
10077
|
instanceId: instanceId,
|
|
9125
10078
|
actor: actor,
|
|
@@ -9131,6 +10084,9 @@ async function abortAndPropagate(args) {
|
|
|
9131
10084
|
} : {},
|
|
9132
10085
|
...telemetry !== void 0 ? {
|
|
9133
10086
|
telemetry: telemetry
|
|
10087
|
+
} : {},
|
|
10088
|
+
...result.fired && !drained.drained ? {
|
|
10089
|
+
instance: drained.instance
|
|
9134
10090
|
} : {}
|
|
9135
10091
|
}), result.fired;
|
|
9136
10092
|
}
|
|
@@ -9238,6 +10194,9 @@ function buildEngineCallOptions(args) {
|
|
|
9238
10194
|
actor: args.actor,
|
|
9239
10195
|
clientForGdr: args.clientForGdr,
|
|
9240
10196
|
refSurface: args.refSurface,
|
|
10197
|
+
...args.localPrincipalId !== void 0 ? {
|
|
10198
|
+
localPrincipalId: args.localPrincipalId
|
|
10199
|
+
} : {},
|
|
9241
10200
|
...args.grants !== void 0 ? {
|
|
9242
10201
|
grants: args.grants
|
|
9243
10202
|
} : {},
|
|
@@ -9379,6 +10338,15 @@ async function abortInstances(args) {
|
|
|
9379
10338
|
return aborted;
|
|
9380
10339
|
}
|
|
9381
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
|
+
|
|
9382
10350
|
async function fetchStartSlice(args) {
|
|
9383
10351
|
const {client: client, tag: tag} = args, {query: query, params: params} = instancesQuery({
|
|
9384
10352
|
tag: tag,
|
|
@@ -9386,7 +10354,7 @@ async function fetchStartSlice(args) {
|
|
|
9386
10354
|
includeCompleted: !0
|
|
9387
10355
|
}
|
|
9388
10356
|
});
|
|
9389
|
-
return (await client.fetch(query, params)).map(invariants.assertReadableModel);
|
|
10357
|
+
return (await client.fetch(query, params)).map(invariants.assertReadableModel).map(projectStartSliceRow);
|
|
9390
10358
|
}
|
|
9391
10359
|
|
|
9392
10360
|
const workflow = {
|
|
@@ -9535,6 +10503,9 @@ const workflow = {
|
|
|
9535
10503
|
...access.grants !== void 0 ? {
|
|
9536
10504
|
grants: access.grants
|
|
9537
10505
|
} : {},
|
|
10506
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10507
|
+
localPrincipalId: access.localPrincipalId
|
|
10508
|
+
} : {},
|
|
9538
10509
|
clock: clock,
|
|
9539
10510
|
clientForGdr: clientForGdr,
|
|
9540
10511
|
refSurface: refSurface,
|
|
@@ -9603,6 +10574,9 @@ const workflow = {
|
|
|
9603
10574
|
...access.grants !== void 0 ? {
|
|
9604
10575
|
grants: access.grants
|
|
9605
10576
|
} : {},
|
|
10577
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10578
|
+
localPrincipalId: access.localPrincipalId
|
|
10579
|
+
} : {},
|
|
9606
10580
|
clock: clock,
|
|
9607
10581
|
clientForGdr: clientForGdr,
|
|
9608
10582
|
refSurface: refSurface,
|
|
@@ -9762,7 +10736,7 @@ const workflow = {
|
|
|
9762
10736
|
});
|
|
9763
10737
|
},
|
|
9764
10738
|
tick: async rawArgs => {
|
|
9765
|
-
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({
|
|
9766
10740
|
client: client,
|
|
9767
10741
|
instanceId: instanceId,
|
|
9768
10742
|
tag: tag
|
|
@@ -9770,7 +10744,7 @@ const workflow = {
|
|
|
9770
10744
|
await assertInstanceWriteAllowed({
|
|
9771
10745
|
instance: current,
|
|
9772
10746
|
guards: guards,
|
|
9773
|
-
identity:
|
|
10747
|
+
identity: invariants.lakePrincipalId(access)
|
|
9774
10748
|
});
|
|
9775
10749
|
const {cascaded: cascaded, instance: instance} = await cascadeAndReload({
|
|
9776
10750
|
client: client,
|
|
@@ -9887,6 +10861,59 @@ const workflow = {
|
|
|
9887
10861
|
}
|
|
9888
10862
|
});
|
|
9889
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
|
+
},
|
|
9890
10917
|
getInstance: async rawArgs => {
|
|
9891
10918
|
const args = taggedScope(rawArgs, REQUEST_TAG.getInstance), {client: client, tag: tag, instanceId: instanceId} = args;
|
|
9892
10919
|
return invariants.validateTag(tag), reload({
|
|
@@ -10033,21 +11060,18 @@ const workflow = {
|
|
|
10033
11060
|
return (await client.fetch(query, params)).map(readInstanceDoc).filter(instance => instanceWatchesDocument(instance, document));
|
|
10034
11061
|
},
|
|
10035
11062
|
definitionsForDocument: async rawArgs => {
|
|
10036
|
-
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;
|
|
10037
11064
|
invariants.validateTag(tag);
|
|
10038
|
-
const clock = args.clock ?? wallClock, deployed = (await client.fetch(
|
|
11065
|
+
const clock = args.clock ?? wallClock, deployed = (await client.fetch(latestDefinitionsGroq(), {
|
|
10039
11066
|
tag: tag
|
|
10040
|
-
})).map(invariants.assertReadableModel)
|
|
11067
|
+
})).map(invariants.assertReadableModel);
|
|
10041
11068
|
let slice;
|
|
10042
11069
|
return applicableDefinitions({
|
|
10043
|
-
definitions:
|
|
11070
|
+
definitions: deployed,
|
|
10044
11071
|
document: document,
|
|
10045
11072
|
scope: {
|
|
10046
11073
|
tag: tag,
|
|
10047
11074
|
now: clock(),
|
|
10048
|
-
...subject !== void 0 ? {
|
|
10049
|
-
subject: subject
|
|
10050
|
-
} : {},
|
|
10051
11075
|
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10052
11076
|
client: client,
|
|
10053
11077
|
tag: tag
|
|
@@ -10070,34 +11094,17 @@ const workflow = {
|
|
|
10070
11094
|
}), missingRequired = missingRequiredInputs({
|
|
10071
11095
|
entryDefs: definition.fields ?? [],
|
|
10072
11096
|
initialFields: initialFields ?? []
|
|
10073
|
-
}),
|
|
10074
|
-
if (allowed === void 0) return {
|
|
10075
|
-
allowed: invalidInitialFields.length === 0,
|
|
10076
|
-
outcome: "satisfied",
|
|
10077
|
-
unboundReads: [],
|
|
10078
|
-
missingRequired: missingRequired,
|
|
10079
|
-
invalidInitialFields: invalidInitialFields
|
|
10080
|
-
};
|
|
10081
|
-
const unboundReads = unboundAllowedReadsWithSubject({
|
|
10082
|
-
allowed: allowed,
|
|
10083
|
-
fields: startFieldsParam({
|
|
10084
|
-
entryDefs: definition.fields ?? [],
|
|
10085
|
-
initialFields: initialFields ?? []
|
|
10086
|
-
}),
|
|
10087
|
-
definition: definition
|
|
10088
|
-
}), insight = await startAllowedInsight({
|
|
11097
|
+
}), verdict = await startRequirementVerdict({
|
|
10089
11098
|
client: client,
|
|
10090
11099
|
tag: tag,
|
|
10091
11100
|
definition: definition,
|
|
10092
|
-
allowed: allowed,
|
|
10093
11101
|
initialFields: initialFields ?? [],
|
|
10094
|
-
now: clock()
|
|
10095
|
-
|
|
11102
|
+
now: clock(),
|
|
11103
|
+
preflight: !0
|
|
11104
|
+
});
|
|
10096
11105
|
return {
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
insight: insight,
|
|
10100
|
-
unboundReads: unboundReads,
|
|
11106
|
+
...verdict,
|
|
11107
|
+
allowed: invalidInitialFields.length === 0 && verdict.allowed,
|
|
10101
11108
|
missingRequired: missingRequired,
|
|
10102
11109
|
invalidInitialFields: invalidInitialFields
|
|
10103
11110
|
};
|
|
@@ -10109,11 +11116,10 @@ const workflow = {
|
|
|
10109
11116
|
}
|
|
10110
11117
|
};
|
|
10111
11118
|
|
|
10112
|
-
|
|
10113
|
-
const {client: client, tag: tag, definition: definition,
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
definition: definition,
|
|
11119
|
+
function startPredicateContext(args) {
|
|
11120
|
+
const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now} = args;
|
|
11121
|
+
let slice;
|
|
11122
|
+
return {
|
|
10117
11123
|
fields: startFieldsParam({
|
|
10118
11124
|
entryDefs: definition.fields ?? [],
|
|
10119
11125
|
initialFields: initialFields
|
|
@@ -10121,12 +11127,71 @@ async function startAllowedInsight(args) {
|
|
|
10121
11127
|
scope: {
|
|
10122
11128
|
tag: tag,
|
|
10123
11129
|
now: now,
|
|
10124
|
-
fetchDataset: () => fetchStartSlice({
|
|
11130
|
+
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10125
11131
|
client: client,
|
|
10126
11132
|
tag: tag
|
|
10127
11133
|
})
|
|
10128
11134
|
}
|
|
10129
|
-
}
|
|
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
|
+
};
|
|
10130
11195
|
}
|
|
10131
11196
|
|
|
10132
11197
|
async function startFreshInstance(args) {
|
|
@@ -10226,19 +11291,16 @@ async function assertStartInputs(args) {
|
|
|
10226
11291
|
initialFields: initialFields,
|
|
10227
11292
|
definitionName: definition.name
|
|
10228
11293
|
});
|
|
10229
|
-
const
|
|
10230
|
-
if (allowed === void 0) return;
|
|
10231
|
-
const insight = await startAllowedInsight({
|
|
11294
|
+
const unmetRequirements = (await startRequirementVerdict({
|
|
10232
11295
|
client: client,
|
|
10233
11296
|
tag: tag,
|
|
10234
11297
|
definition: definition,
|
|
10235
|
-
allowed: allowed,
|
|
10236
11298
|
initialFields: initialFields,
|
|
10237
11299
|
now: now
|
|
10238
|
-
});
|
|
10239
|
-
if (
|
|
11300
|
+
})).requirements.filter(requirement => requirement.outcome !== "satisfied").map(requirementDescriptor);
|
|
11301
|
+
if (unmetRequirements.length > 0) throw new StartNotAllowedError({
|
|
10240
11302
|
definition: definition.name,
|
|
10241
|
-
|
|
11303
|
+
unmetRequirements: unmetRequirements
|
|
10242
11304
|
});
|
|
10243
11305
|
}
|
|
10244
11306
|
|
|
@@ -10271,97 +11333,6 @@ async function resolveStartFields(args) {
|
|
|
10271
11333
|
};
|
|
10272
11334
|
}
|
|
10273
11335
|
|
|
10274
|
-
function isRecord(value) {
|
|
10275
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
10276
|
-
}
|
|
10277
|
-
|
|
10278
|
-
function isClientProjectUser(value) {
|
|
10279
|
-
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");
|
|
10280
|
-
}
|
|
10281
|
-
|
|
10282
|
-
function objectProperty(value, property) {
|
|
10283
|
-
if (!isRecord(value)) return;
|
|
10284
|
-
const propertyValue = value[property];
|
|
10285
|
-
return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
|
|
10286
|
-
}
|
|
10287
|
-
|
|
10288
|
-
function stringProperty(value, property) {
|
|
10289
|
-
const propertyValue = Reflect.get(value, property);
|
|
10290
|
-
return typeof propertyValue == "string" ? propertyValue : void 0;
|
|
10291
|
-
}
|
|
10292
|
-
|
|
10293
|
-
function apiErrorType(error) {
|
|
10294
|
-
const response = objectProperty(error, "response"), body = objectProperty(response, "body");
|
|
10295
|
-
if (!body) return;
|
|
10296
|
-
const nestedError = objectProperty(body, "error");
|
|
10297
|
-
return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
|
|
10298
|
-
}
|
|
10299
|
-
|
|
10300
|
-
function isProjectUserNotFoundError(error) {
|
|
10301
|
-
return apiErrorType(error) === "projectUserNotFoundError";
|
|
10302
|
-
}
|
|
10303
|
-
|
|
10304
|
-
function clientProjectUserDirectory(client, projectId) {
|
|
10305
|
-
return {
|
|
10306
|
-
findById: async id => {
|
|
10307
|
-
if (!client.request) return {
|
|
10308
|
-
status: "inaccessible",
|
|
10309
|
-
cause: new Error("Project-user resolution requires WorkflowClient.request")
|
|
10310
|
-
};
|
|
10311
|
-
try {
|
|
10312
|
-
const response = await client.request({
|
|
10313
|
-
uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
|
|
10314
|
-
}), candidate = Array.isArray(response) ? response[0] : response;
|
|
10315
|
-
return candidate == null ? {
|
|
10316
|
-
status: "missing"
|
|
10317
|
-
} : isClientProjectUser(candidate) ? {
|
|
10318
|
-
status: "resolved",
|
|
10319
|
-
user: candidate
|
|
10320
|
-
} : {
|
|
10321
|
-
status: "inaccessible",
|
|
10322
|
-
cause: new Error("Project-user response had an invalid shape")
|
|
10323
|
-
};
|
|
10324
|
-
} catch (cause) {
|
|
10325
|
-
return isProjectUserNotFoundError(cause) ? {
|
|
10326
|
-
status: "missing"
|
|
10327
|
-
} : {
|
|
10328
|
-
status: "inaccessible",
|
|
10329
|
-
cause: cause
|
|
10330
|
-
};
|
|
10331
|
-
}
|
|
10332
|
-
}
|
|
10333
|
-
};
|
|
10334
|
-
}
|
|
10335
|
-
|
|
10336
|
-
function resolveClientActor(client, args) {
|
|
10337
|
-
return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
|
|
10338
|
-
}
|
|
10339
|
-
|
|
10340
|
-
async function resolveActor(directory, actor) {
|
|
10341
|
-
if (actor.kind !== "person") return {
|
|
10342
|
-
status: "not-person",
|
|
10343
|
-
actor: actor
|
|
10344
|
-
};
|
|
10345
|
-
const personActor = {
|
|
10346
|
-
...actor,
|
|
10347
|
-
kind: "person"
|
|
10348
|
-
}, lookup = await directory.findById(personActor.id);
|
|
10349
|
-
return lookup.status === "resolved" ? {
|
|
10350
|
-
status: "resolved",
|
|
10351
|
-
actor: personActor,
|
|
10352
|
-
user: lookup.user
|
|
10353
|
-
} : lookup.status === "inaccessible" ? {
|
|
10354
|
-
status: "inaccessible",
|
|
10355
|
-
actor: personActor,
|
|
10356
|
-
...lookup.cause === void 0 ? {} : {
|
|
10357
|
-
cause: lookup.cause
|
|
10358
|
-
}
|
|
10359
|
-
} : {
|
|
10360
|
-
status: "missing",
|
|
10361
|
-
actor: personActor
|
|
10362
|
-
};
|
|
10363
|
-
}
|
|
10364
|
-
|
|
10365
11336
|
const EFFECT_COMMIT_QUEUE_DEPTH = 32, EFFECT_COMMIT_DISPATCH_CAP = 200;
|
|
10366
11337
|
|
|
10367
11338
|
class EffectCommitQueueOverflowError extends invariants.WorkflowError {
|
|
@@ -10540,7 +11511,7 @@ function isCancelledCompletion(data) {
|
|
|
10540
11511
|
}
|
|
10541
11512
|
|
|
10542
11513
|
async function drainEffectsInternal(args) {
|
|
10543
|
-
const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, effectHandlers: effectHandlers, missingHandler: missingHandler, logger: logger, handlerClient:
|
|
11514
|
+
const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, effectHandlers: effectHandlers, missingHandler: missingHandler, logger: logger, handlerClient: rawHandlerClient, handlerResourceClients: rawHandlerResourceClients} = args, cascadeTelemetry = drainCascadeTelemetry(args.telemetry), {client: client, resourceClients: resourceClients} = taggedScope(args, REQUEST_TAG.drain), leaseMs = args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS, clock = args.clock ?? wallClock, handlerClient = effectHandlerClient(rawHandlerClient), handlerResourceClients = effectHandlerResolver(rawHandlerResourceClients), routeGdr = buildClientForGdr({
|
|
10544
11515
|
client: handlerClient,
|
|
10545
11516
|
workflowResource: workflowResource,
|
|
10546
11517
|
resourceClients: handlerResourceClients
|
|
@@ -10906,22 +11877,30 @@ function createInstanceSession(args) {
|
|
|
10906
11877
|
}, tickScope = opScope(REQUEST_TAG.tick), fireScope = opScope(REQUEST_TAG.fireAction), editScope = opScope(REQUEST_TAG.editField), evalScope = opScope(REQUEST_TAG.evaluate);
|
|
10907
11878
|
let overlay = /* @__PURE__ */ new Map;
|
|
10908
11879
|
const previews = /* @__PURE__ */ new Map;
|
|
10909
|
-
let heldGuards = [], committing = !1, buffered
|
|
10910
|
-
const
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
11880
|
+
let heldGuards = [], committing = !1, buffered;
|
|
11881
|
+
const bufferedDocuments = /* @__PURE__ */ new Map;
|
|
11882
|
+
let deferredUpdateError;
|
|
11883
|
+
const flushDeferredError = () => {
|
|
11884
|
+
if (deferredUpdateError === void 0) return;
|
|
11885
|
+
const failure = deferredUpdateError;
|
|
11886
|
+
throw deferredUpdateError = void 0, failure;
|
|
11887
|
+
}, selfUri = () => invariants.gdrFromResource(instance.workflowResource, instance._id), applyDocument = (ld, target) => {
|
|
11888
|
+
const owned = {
|
|
11889
|
+
doc: structuredClone(ld.doc),
|
|
11890
|
+
resource: ld.resource
|
|
11891
|
+
}, uri = invariants.gdrFromResource(owned.resource, owned.doc._id);
|
|
11892
|
+
if (uri === selfUri()) {
|
|
11893
|
+
const rawStamp = owned.doc._updatedAt;
|
|
11894
|
+
!invariants.isParseableInstant(rawStamp) || owned.doc._type !== invariants.WORKFLOW_INSTANCE_TYPE ? asHeldInstance(owned.doc) : Date.parse(rawStamp) > Date.parse(instance._updatedAt) && (instance = asHeldInstance(owned.doc));
|
|
11895
|
+
return;
|
|
10923
11896
|
}
|
|
11897
|
+
target.set(uri, owned);
|
|
11898
|
+
}, applyUpdate = docs => {
|
|
11899
|
+
const next = /* @__PURE__ */ new Map;
|
|
11900
|
+
for (const ld of docs) applyDocument(ld, next);
|
|
10924
11901
|
overlay = next;
|
|
11902
|
+
}, applyDocumentUpdate = doc => {
|
|
11903
|
+
applyDocument(doc, overlay);
|
|
10925
11904
|
}, access = () => resolveAccess(client, {
|
|
10926
11905
|
...args.grantsFromPath !== void 0 ? {
|
|
10927
11906
|
grantsFromPath: args.grantsFromPath
|
|
@@ -10979,17 +11958,23 @@ function createInstanceSession(args) {
|
|
|
10979
11958
|
refSurface: evalScope.refSurface
|
|
10980
11959
|
});
|
|
10981
11960
|
}, evaluateWith = async ({held: held, guards: guards, self: self}) => {
|
|
10982
|
-
const {actor: actor, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
11961
|
+
const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
10983
11962
|
clientForGdr: evalScope.clientForGdr,
|
|
10984
11963
|
instance: instance
|
|
11964
|
+
}), normalizedSelf = await normalizeInstanceIdentities({
|
|
11965
|
+
client: evalScope.client,
|
|
11966
|
+
instance: self
|
|
10985
11967
|
});
|
|
10986
11968
|
return evaluateFromSnapshot({
|
|
10987
|
-
instance:
|
|
11969
|
+
instance: normalizedSelf,
|
|
10988
11970
|
definition: definitionOf(),
|
|
10989
11971
|
actor: actor,
|
|
10990
|
-
snapshot: snapshotFrom(held,
|
|
11972
|
+
snapshot: snapshotFrom(held, normalizedSelf),
|
|
10991
11973
|
guards: guards,
|
|
10992
11974
|
resourceGrants: resourceGrants,
|
|
11975
|
+
...localPrincipalId !== void 0 ? {
|
|
11976
|
+
localPrincipalId: localPrincipalId
|
|
11977
|
+
} : {},
|
|
10993
11978
|
...clock !== void 0 ? {
|
|
10994
11979
|
now: clock()
|
|
10995
11980
|
} : {},
|
|
@@ -11035,8 +12020,13 @@ function createInstanceSession(args) {
|
|
|
11035
12020
|
committing = !0;
|
|
11036
12021
|
const held = new Map(overlay);
|
|
11037
12022
|
try {
|
|
11038
|
-
const {actor: actor} = await access();
|
|
11039
|
-
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);
|
|
11040
12030
|
} finally {
|
|
11041
12031
|
if (committing = !1, buffered !== void 0) {
|
|
11042
12032
|
const next = buffered;
|
|
@@ -11047,6 +12037,12 @@ function createInstanceSession(args) {
|
|
|
11047
12037
|
deferredUpdateError = err;
|
|
11048
12038
|
}
|
|
11049
12039
|
}
|
|
12040
|
+
for (const next of bufferedDocuments.values()) try {
|
|
12041
|
+
applyDocumentUpdate(next);
|
|
12042
|
+
} catch (err) {
|
|
12043
|
+
deferredUpdateError = err;
|
|
12044
|
+
}
|
|
12045
|
+
bufferedDocuments.clear();
|
|
11050
12046
|
}
|
|
11051
12047
|
};
|
|
11052
12048
|
return {
|
|
@@ -11054,15 +12050,26 @@ function createInstanceSession(args) {
|
|
|
11054
12050
|
return subscriptionDocumentsForInstance(instance);
|
|
11055
12051
|
},
|
|
11056
12052
|
update(docs) {
|
|
11057
|
-
if (committing) buffered = docs; else try {
|
|
12053
|
+
if (committing) buffered = docs, bufferedDocuments.clear(); else try {
|
|
11058
12054
|
applyUpdate(docs);
|
|
11059
12055
|
} catch (err) {
|
|
11060
12056
|
throw deferredUpdateError = void 0, err;
|
|
11061
12057
|
}
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
12058
|
+
flushDeferredError();
|
|
12059
|
+
},
|
|
12060
|
+
updateDocument(doc) {
|
|
12061
|
+
if (committing) {
|
|
12062
|
+
const uri = invariants.gdrFromResource(doc.resource, doc.doc._id);
|
|
12063
|
+
bufferedDocuments.set(uri, {
|
|
12064
|
+
doc: structuredClone(doc.doc),
|
|
12065
|
+
resource: doc.resource
|
|
12066
|
+
});
|
|
12067
|
+
} else try {
|
|
12068
|
+
applyDocumentUpdate(doc);
|
|
12069
|
+
} catch (err) {
|
|
12070
|
+
throw deferredUpdateError = void 0, err;
|
|
11065
12071
|
}
|
|
12072
|
+
flushDeferredError();
|
|
11066
12073
|
},
|
|
11067
12074
|
updateGuards(guards) {
|
|
11068
12075
|
heldGuards = guards.map(guard => parseGuardDocument(structuredClone(guard)));
|
|
@@ -11094,11 +12101,14 @@ function createInstanceSession(args) {
|
|
|
11094
12101
|
site !== void 0 && previews.delete(siteKey(site));
|
|
11095
12102
|
},
|
|
11096
12103
|
tick() {
|
|
11097
|
-
return commit(async (actor, held) => {
|
|
12104
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11098
12105
|
await assertInstanceWriteAllowed({
|
|
11099
12106
|
instance: instance,
|
|
11100
12107
|
guards: heldGuards,
|
|
11101
|
-
identity:
|
|
12108
|
+
identity: invariants.lakePrincipalId({
|
|
12109
|
+
actor: actor,
|
|
12110
|
+
localPrincipalId: localPrincipalId
|
|
12111
|
+
})
|
|
11102
12112
|
});
|
|
11103
12113
|
const before = await reload({
|
|
11104
12114
|
client: tickScope.client,
|
|
@@ -11125,7 +12135,7 @@ function createInstanceSession(args) {
|
|
|
11125
12135
|
});
|
|
11126
12136
|
},
|
|
11127
12137
|
fireAction({activity: activity, action: action, params: params}) {
|
|
11128
|
-
return commit(async (actor, held) => {
|
|
12138
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11129
12139
|
assertActionAllowed({
|
|
11130
12140
|
evaluation: await evaluateWith({
|
|
11131
12141
|
held: held,
|
|
@@ -11141,6 +12151,9 @@ function createInstanceSession(args) {
|
|
|
11141
12151
|
activity: activity,
|
|
11142
12152
|
action: action,
|
|
11143
12153
|
actor: actor,
|
|
12154
|
+
...localPrincipalId !== void 0 ? {
|
|
12155
|
+
localPrincipalId: localPrincipalId
|
|
12156
|
+
} : {},
|
|
11144
12157
|
clientForGdr: fireScope.clientForGdr,
|
|
11145
12158
|
refSurface: fireScope.refSurface,
|
|
11146
12159
|
...grants !== void 0 ? {
|
|
@@ -11183,7 +12196,7 @@ function createInstanceSession(args) {
|
|
|
11183
12196
|
} catch (err) {
|
|
11184
12197
|
return Promise.reject(err);
|
|
11185
12198
|
}
|
|
11186
|
-
return commit(async (actor, held) => {
|
|
12199
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11187
12200
|
assertEditAllowed(await evaluateWith({
|
|
11188
12201
|
held: held,
|
|
11189
12202
|
guards: heldGuards,
|
|
@@ -11200,6 +12213,9 @@ function createInstanceSession(args) {
|
|
|
11200
12213
|
value: value
|
|
11201
12214
|
} : {},
|
|
11202
12215
|
actor: actor,
|
|
12216
|
+
...localPrincipalId !== void 0 ? {
|
|
12217
|
+
localPrincipalId: localPrincipalId
|
|
12218
|
+
} : {},
|
|
11203
12219
|
clientForGdr: editScope.clientForGdr,
|
|
11204
12220
|
refSurface: editScope.refSurface,
|
|
11205
12221
|
...grants !== void 0 ? {
|
|
@@ -11310,6 +12326,7 @@ function createEngine(args) {
|
|
|
11310
12326
|
availableActions: rest => workflow.availableActions(withScope(rest)),
|
|
11311
12327
|
setStage: rest => workflow.setStage(withScope(rest)),
|
|
11312
12328
|
abortInstance: rest => workflow.abortInstance(withScope(rest)),
|
|
12329
|
+
resetActivity: rest => workflow.resetActivity(withScope(rest)),
|
|
11313
12330
|
deleteDefinition: rest => workflow.deleteDefinition(withScope(rest)),
|
|
11314
12331
|
getInstance: rest => workflow.getInstance(withScope(rest)),
|
|
11315
12332
|
subscriptionDocumentsForInstance: rest => workflow.getInstance(withScope(rest)).then(subscriptionDocumentsForInstance),
|
|
@@ -11882,6 +12899,8 @@ exports.ACTIVITY_KINDS = invariants.ACTIVITY_KINDS;
|
|
|
11882
12899
|
|
|
11883
12900
|
exports.ACTOR_KINDS = invariants.ACTOR_KINDS;
|
|
11884
12901
|
|
|
12902
|
+
exports.ANONYMOUS_IDENTITY = invariants.ANONYMOUS_IDENTITY;
|
|
12903
|
+
|
|
11885
12904
|
exports.CONDITION_VARS = invariants.CONDITION_VARS;
|
|
11886
12905
|
|
|
11887
12906
|
exports.ContractViolationError = invariants.ContractViolationError;
|
|
@@ -11924,10 +12943,12 @@ exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
|
|
|
11924
12943
|
|
|
11925
12944
|
exports.ReaderModelAcknowledgementError = invariants.ReaderModelAcknowledgementError;
|
|
11926
12945
|
|
|
11927
|
-
exports.START_ALLOWED_VARS = invariants.START_ALLOWED_VARS;
|
|
11928
|
-
|
|
11929
12946
|
exports.START_FILTER_VARS = invariants.START_FILTER_VARS;
|
|
11930
12947
|
|
|
12948
|
+
exports.START_REQUIREMENT_VARS = invariants.START_REQUIREMENT_VARS;
|
|
12949
|
+
|
|
12950
|
+
exports.SYSTEM_IDENTITY = invariants.SYSTEM_IDENTITY;
|
|
12951
|
+
|
|
11931
12952
|
exports.SpawnContractsInvalidError = invariants.SpawnContractsInvalidError;
|
|
11932
12953
|
|
|
11933
12954
|
exports.WORKFLOW_DEFINITION_TYPE = invariants.WORKFLOW_DEFINITION_TYPE;
|
|
@@ -11940,6 +12961,8 @@ exports.assertReadableModel = invariants.assertReadableModel;
|
|
|
11940
12961
|
|
|
11941
12962
|
exports.assertReaderModelAcknowledgement = invariants.assertReaderModelAcknowledgement;
|
|
11942
12963
|
|
|
12964
|
+
exports.classifyPrincipalId = invariants.classifyPrincipalId;
|
|
12965
|
+
|
|
11943
12966
|
exports.clientConfigFromResource = invariants.clientConfigFromResource;
|
|
11944
12967
|
|
|
11945
12968
|
exports.conditionFieldReadNames = invariants.conditionFieldReadNames;
|
|
@@ -11990,6 +13013,8 @@ exports.isTodoListItem = invariants.isTodoListItem;
|
|
|
11990
13013
|
|
|
11991
13014
|
exports.isUnprimed = invariants.isUnprimed;
|
|
11992
13015
|
|
|
13016
|
+
exports.lakePrincipalId = invariants.lakePrincipalId;
|
|
13017
|
+
|
|
11993
13018
|
exports.minReaderModelOf = invariants.minReaderModelOf;
|
|
11994
13019
|
|
|
11995
13020
|
exports.modelVersionOf = invariants.modelVersionOf;
|
|
@@ -12216,6 +13241,8 @@ exports.StartNotSettledError = StartNotSettledError;
|
|
|
12216
13241
|
|
|
12217
13242
|
exports.WorkflowActionFired = WorkflowActionFired;
|
|
12218
13243
|
|
|
13244
|
+
exports.WorkflowActivityReset = WorkflowActivityReset;
|
|
13245
|
+
|
|
12219
13246
|
exports.WorkflowDefinitionDeleted = WorkflowDefinitionDeleted;
|
|
12220
13247
|
|
|
12221
13248
|
exports.WorkflowDefinitionDeployed = WorkflowDefinitionDeployed;
|
|
@@ -12348,7 +13375,7 @@ exports.evaluateStartFilter = evaluateStartFilter;
|
|
|
12348
13375
|
|
|
12349
13376
|
exports.expandResourceAliases = expandResourceAliases;
|
|
12350
13377
|
|
|
12351
|
-
exports.
|
|
13378
|
+
exports.explainStartRequirement = explainStartRequirement;
|
|
12352
13379
|
|
|
12353
13380
|
exports.findCurrentActivityEntry = findCurrentActivityEntry;
|
|
12354
13381
|
|
|
@@ -12364,6 +13391,8 @@ exports.guardsForInstance = guardsForInstance;
|
|
|
12364
13391
|
|
|
12365
13392
|
exports.guardsForResource = guardsForResource;
|
|
12366
13393
|
|
|
13394
|
+
exports.hasSingleSubjectRequirement = hasSingleSubjectRequirement;
|
|
13395
|
+
|
|
12367
13396
|
exports.hashDefinitionContent = hashDefinitionContent;
|
|
12368
13397
|
|
|
12369
13398
|
exports.inFlightFilter = inFlightFilter;
|
|
@@ -12376,10 +13405,14 @@ exports.instanceGuardQuery = instanceGuardQuery;
|
|
|
12376
13405
|
|
|
12377
13406
|
exports.instanceWatchesDocument = instanceWatchesDocument;
|
|
12378
13407
|
|
|
13408
|
+
exports.instancesGuardQuery = instancesGuardQuery;
|
|
13409
|
+
|
|
12379
13410
|
exports.instancesQuery = instancesQuery;
|
|
12380
13411
|
|
|
12381
13412
|
exports.isClaimExpired = isClaimExpired;
|
|
12382
13413
|
|
|
13414
|
+
exports.isClientProjectUser = isClientProjectUser;
|
|
13415
|
+
|
|
12383
13416
|
exports.isDefinitionApplicable = isDefinitionApplicable;
|
|
12384
13417
|
|
|
12385
13418
|
exports.isFilterScopedOut = isFilterScopedOut;
|
|
@@ -12392,6 +13425,8 @@ exports.isTerminalStage = isTerminalStage;
|
|
|
12392
13425
|
|
|
12393
13426
|
exports.lakeGuardId = lakeGuardId;
|
|
12394
13427
|
|
|
13428
|
+
exports.latestDefinitionsGroq = latestDefinitionsGroq;
|
|
13429
|
+
|
|
12395
13430
|
exports.latestDeployedDefinitions = latestDeployedDefinitions;
|
|
12396
13431
|
|
|
12397
13432
|
exports.lintEffectOutputs = lintEffectOutputs;
|
|
@@ -12410,6 +13445,8 @@ exports.parseInstanceDocument = parseInstanceDocument;
|
|
|
12410
13445
|
|
|
12411
13446
|
exports.processShellUserProperties = processShellUserProperties;
|
|
12412
13447
|
|
|
13448
|
+
exports.projectStartSliceRow = projectStartSliceRow;
|
|
13449
|
+
|
|
12413
13450
|
exports.projectToWatchRef = projectToWatchRef;
|
|
12414
13451
|
|
|
12415
13452
|
exports.readInstanceDoc = readInstanceDoc;
|
|
@@ -12432,6 +13469,8 @@ exports.retractStageGuards = retractStageGuards;
|
|
|
12432
13469
|
|
|
12433
13470
|
exports.silentLogger = silentLogger;
|
|
12434
13471
|
|
|
13472
|
+
exports.singleSubjectRequirementRefused = singleSubjectRequirementRefused;
|
|
13473
|
+
|
|
12435
13474
|
exports.stageAutonomyOf = stageAutonomyOf;
|
|
12436
13475
|
|
|
12437
13476
|
exports.startFieldsParam = startFieldsParam;
|
|
@@ -12448,7 +13487,7 @@ exports.subscriptionDocumentsForInstance = subscriptionDocumentsForInstance;
|
|
|
12448
13487
|
|
|
12449
13488
|
exports.sweepStaleClaims = sweepStaleClaims;
|
|
12450
13489
|
|
|
12451
|
-
exports.
|
|
13490
|
+
exports.unboundRequirementReads = unboundRequirementReads;
|
|
12452
13491
|
|
|
12453
13492
|
exports.unsatisfiedTransitionSummaries = unsatisfiedTransitionSummaries;
|
|
12454
13493
|
|