@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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { terminalState, andConditions, deriveActivityKind, parseDefinitionSnapshot, CALLER_BOUND_VARS,
|
|
1
|
+
import { terminalState, andConditions, deriveActivityKind, parseDefinitionSnapshot, CALLER_BOUND_VARS, START_REQUIREMENT_VARS, CONDITION_VARS, isSubjectEntry, isUnevaluable, ContractViolationError, isStartableDefinition, conditionFieldReadNames, rethrowWithContext, isGdr, errorMessage, conditionParameterNames, START_FILTER_VARS, gdrFromResource, selfGdr, isSingleDocRefKind, parentRef, actorFulfillsRole, toBareId, WorkflowError, sameResource, resourceFromParsed, tryParseGdr, isTerminalActivityStatus, FieldValueShapeError, validateFieldValue, validateFieldAppendItem, evaluateCondition, isSingleDocRefEntry, choiceValueIssues, scalarValidationIssues, StoredFieldOpSchema, formatIssues, conditionSyntaxIssues, checkWorkflowInvariants, formatIssuePath, isGuardReadExpr, conditionEffectReads, EFFECTS_READ, datasetResourceParts, evaluatePredicates, WORKFLOW_DEFINITION_TYPE, tagScopeFilter, isCascadeFired, WORKFLOW_INSTANCE_TYPE, parseGdr, isGdrUri, gdrRef, isInputSourced, parseFieldValue, VersionSpecificDatasetGdrError, toPhysicalGdr, isBareSeedId, tolerantEntries, NonEmptyString, FIELD_VALUE_KINDS, tolerantObject, ActorShape, IsoTimestamp, ACTIVITY_STATUSES, GdrShape, DRIVER_KINDS, FIELD_SCOPES, fieldValueSchemas, parsePersistedDoc, ACTOR_KINDS, classifyPrincipalId, assertReadableModel, InstanceNotFoundError, modelStampFor, evaluateConditionOutcome, runGroq, FIELD_READ, MUTATION_GUARD_ACTIONS, resourceGdr, minReaderModelOf, resourceFromGdrUri, refTypeIssues, rejectedRefTypes, DOCUMENT_VALUE_PERMISSIONS, lakePrincipalId, driverKind, EffectNotFoundError, deriveExecutorClassification, validateTag, extractDocumentId, parseStoredDefinition, validateResourceAliasName, labelFor, DefinitionNotFoundError, definitionDocId, SpawnContractsInvalidError, gdrResourcePrefix, RESOURCE_ALIAS_NAME_SOURCE, isUnprimed, DefinitionInUseError, assertReaderModelAcknowledgement, isParseableInstant, groupMembershipNames } from "./_chunks-es/invariants.js";
|
|
2
2
|
|
|
3
|
-
import { ACTION_SEMANTICS, ACTIVITY_KINDS,
|
|
3
|
+
import { ACTION_SEMANTICS, ACTIVITY_KINDS, ANONYMOUS_IDENTITY, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, EXECUTOR_CLASSIFICATIONS, FILTER_SCOPE_VARS, GROUP_KINDS, GUARD_PREDICATE_VARS, ModelVersionAheadError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, SYSTEM_IDENTITY, clientConfigFromResource, fieldTreeShape, gdrUri, isNotesEntry, isTodoListEntry, isTodoListItem, modelVersionOf, parseResourceGdr, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, schemaTreeShape, startKindOf } from "./_chunks-es/invariants.js";
|
|
4
4
|
|
|
5
5
|
import { atomNode, dedupeBy, analyzeCondition, atomReadsDataset, checklistLines as checklistLines$1, phrase, quoted, listAnd, describeAtom as describeAtom$1, describeCondition as describeCondition$1, guillemets, formatValue, humanize, listOr, scopeReadOf, describeRead, explainCondition, dedupeReads, whatIfCondition, MAX_COUNTERFACTUAL_INDEX } from "@sanity/groq-condition-describe";
|
|
6
6
|
|
|
@@ -265,6 +265,10 @@ const HIGH_FREQUENCY_SAMPLE_MS = 6e4, WorkflowDefinitionDeployed = defineWorkflo
|
|
|
265
265
|
name: "Editorial Workflows Stage Set",
|
|
266
266
|
version: 1,
|
|
267
267
|
description: "The set-stage admin override was invoked (changed: false = already at the target stage)"
|
|
268
|
+
}), WorkflowActivityReset = defineWorkflowEvent({
|
|
269
|
+
name: "Editorial Workflows Activity Reset",
|
|
270
|
+
version: 1,
|
|
271
|
+
description: "The reset-activity admin override was invoked (changed: false = already at the target status, or the instance was terminal)"
|
|
268
272
|
}), WorkflowDefinitionDeleted = defineWorkflowEvent({
|
|
269
273
|
name: "Editorial Workflows Definition Deleted",
|
|
270
274
|
version: 1,
|
|
@@ -845,7 +849,7 @@ function toGroqDescribeContext(ctx) {
|
|
|
845
849
|
};
|
|
846
850
|
}
|
|
847
851
|
|
|
848
|
-
const VAR_LABELS = new Map([ ...
|
|
852
|
+
const VAR_LABELS = new Map([ ...START_REQUIREMENT_VARS, ...CONDITION_VARS ].map(entry => [ entry.name, entry.label ]));
|
|
849
853
|
|
|
850
854
|
function renderWorkflowRead(read, ctx) {
|
|
851
855
|
if (read.variable === "fields" && typeof read.path[0] == "string") {
|
|
@@ -918,13 +922,6 @@ function clauseVarRequirement(requirement) {
|
|
|
918
922
|
params: {},
|
|
919
923
|
text: "no activity in this stage may have failed"
|
|
920
924
|
});
|
|
921
|
-
if (target.variable === SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR) return kind === "truthy" ? phrase("requirement.subject-has-in-flight-instance", {
|
|
922
|
-
params: {},
|
|
923
|
-
text: "the subject must already have an in-flight workflow"
|
|
924
|
-
}) : phrase("requirement.subject-has-no-in-flight-instance", {
|
|
925
|
-
params: {},
|
|
926
|
-
text: "the subject must not already have an in-flight workflow"
|
|
927
|
-
});
|
|
928
925
|
}
|
|
929
926
|
}
|
|
930
927
|
|
|
@@ -1420,14 +1417,14 @@ function activitySites(activity, stage) {
|
|
|
1420
1417
|
activity: activity.name
|
|
1421
1418
|
},
|
|
1422
1419
|
condition: activity.filter
|
|
1423
|
-
} ] : [], ...
|
|
1420
|
+
} ] : [], ...(activity.requirements ?? []).map(requirement => ({
|
|
1424
1421
|
stage: stage,
|
|
1425
1422
|
address: {
|
|
1426
1423
|
kind: "requirement",
|
|
1427
1424
|
activity: activity.name,
|
|
1428
|
-
requirement: requirement
|
|
1425
|
+
requirement: requirement.name
|
|
1429
1426
|
},
|
|
1430
|
-
condition:
|
|
1427
|
+
condition: requirement.query
|
|
1431
1428
|
})), ...(activity.actions ?? []).flatMap(action => [ ...action.filter !== void 0 ? [ {
|
|
1432
1429
|
stage: stage,
|
|
1433
1430
|
address: {
|
|
@@ -1495,13 +1492,7 @@ async function evaluateStartFilter(args) {
|
|
|
1495
1492
|
const {filter: filter, definition: definition, document: document, scope: scope} = args, parsed = parseStartFilter({
|
|
1496
1493
|
filter: filter,
|
|
1497
1494
|
definition: definition
|
|
1498
|
-
});
|
|
1499
|
-
assertFilterSubject({
|
|
1500
|
-
readsSubject: parsed.readsSubject,
|
|
1501
|
-
definition: definition,
|
|
1502
|
-
scope: scope
|
|
1503
|
-
});
|
|
1504
|
-
const dataset = await filterDataset(parsed.needsDataset, scope);
|
|
1495
|
+
}), dataset = await filterDataset(parsed.needsDataset, scope);
|
|
1505
1496
|
if (dataset === void 0) return !1;
|
|
1506
1497
|
try {
|
|
1507
1498
|
const result = await (await evaluate(parsed.tree, {
|
|
@@ -1511,8 +1502,7 @@ async function evaluateStartFilter(args) {
|
|
|
1511
1502
|
dataset: dataset,
|
|
1512
1503
|
params: startContextParams({
|
|
1513
1504
|
definition: definition,
|
|
1514
|
-
scope: scope
|
|
1515
|
-
dataset: dataset
|
|
1505
|
+
scope: scope
|
|
1516
1506
|
})
|
|
1517
1507
|
})).get();
|
|
1518
1508
|
return isUnevaluable(result) ? !1 : !!result;
|
|
@@ -1528,11 +1518,9 @@ async function evaluateStartFilter(args) {
|
|
|
1528
1518
|
function parseStartFilter(args) {
|
|
1529
1519
|
const {filter: filter, definition: definition} = args;
|
|
1530
1520
|
try {
|
|
1531
|
-
const readsSubject = readsSubjectHasInFlightInstance(filter);
|
|
1532
1521
|
return {
|
|
1533
1522
|
tree: parse(filter),
|
|
1534
|
-
needsDataset: analyzeCondition(filter).readsDataset
|
|
1535
|
-
readsSubject: readsSubject
|
|
1523
|
+
needsDataset: analyzeCondition(filter).readsDataset
|
|
1536
1524
|
};
|
|
1537
1525
|
} catch (err) {
|
|
1538
1526
|
rethrowNamingDefinition({
|
|
@@ -1543,70 +1531,81 @@ function parseStartFilter(args) {
|
|
|
1543
1531
|
}
|
|
1544
1532
|
}
|
|
1545
1533
|
|
|
1546
|
-
function assertFilterSubject(args) {
|
|
1547
|
-
if (!(!args.readsSubject || args.scope?.subject !== void 0)) throw new ContractViolationError(`start.filter on definition "${args.definition.name ?? "<unnamed>"}" reads $${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.`);
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
1534
|
async function filterDataset(needsDataset, scope) {
|
|
1551
1535
|
if (!needsDataset) return [];
|
|
1552
1536
|
if (scope?.fetchDataset !== void 0) return scope.fetchDataset();
|
|
1553
1537
|
}
|
|
1554
1538
|
|
|
1555
|
-
async function
|
|
1556
|
-
const {
|
|
1539
|
+
async function explainStartRequirement(args) {
|
|
1540
|
+
const {query: query, definition: definition, fields: fields, scope: scope} = args;
|
|
1557
1541
|
let needsDataset;
|
|
1558
1542
|
try {
|
|
1559
|
-
needsDataset = analyzeCondition(
|
|
1543
|
+
needsDataset = analyzeCondition(query).readsDataset;
|
|
1560
1544
|
} catch (err) {
|
|
1561
1545
|
rethrowNamingDefinition({
|
|
1562
1546
|
err: err,
|
|
1563
1547
|
definition: definition,
|
|
1564
|
-
key: "
|
|
1548
|
+
key: "requirement"
|
|
1565
1549
|
});
|
|
1566
1550
|
}
|
|
1567
1551
|
let dataset = [];
|
|
1568
1552
|
if (needsDataset) {
|
|
1569
|
-
if (scope?.fetchDataset === void 0) throw new ContractViolationError(`start
|
|
1553
|
+
if (scope?.fetchDataset === void 0) throw new 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.`);
|
|
1570
1554
|
dataset = await scope.fetchDataset();
|
|
1571
1555
|
}
|
|
1572
1556
|
try {
|
|
1573
1557
|
return await explainCondition({
|
|
1574
|
-
condition:
|
|
1558
|
+
condition: query,
|
|
1575
1559
|
dataset: dataset,
|
|
1576
1560
|
params: startContextParams({
|
|
1577
1561
|
definition: definition,
|
|
1578
1562
|
scope: scope,
|
|
1579
|
-
fields: fields
|
|
1580
|
-
dataset: dataset
|
|
1563
|
+
fields: fields
|
|
1581
1564
|
})
|
|
1582
1565
|
});
|
|
1583
1566
|
} catch (err) {
|
|
1584
1567
|
rethrowNamingDefinition({
|
|
1585
1568
|
err: err,
|
|
1586
1569
|
definition: definition,
|
|
1587
|
-
key: "
|
|
1570
|
+
key: "requirement"
|
|
1588
1571
|
});
|
|
1589
1572
|
}
|
|
1590
1573
|
}
|
|
1591
1574
|
|
|
1592
|
-
function
|
|
1593
|
-
return [ ...conditionFieldReadNames(
|
|
1575
|
+
function unboundRequirementReads(query, fields) {
|
|
1576
|
+
return [ ...conditionFieldReadNames(query) ].filter(name => !Object.hasOwn(fields, name));
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function hasSingleSubjectRequirement(definition) {
|
|
1580
|
+
return definition.start?.requirements?.some(requirement => requirement.type === "singleSubject") ?? !1;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
async function singleSubjectRequirementRefused(args) {
|
|
1584
|
+
const {definition: definition, fields: fields, scope: scope} = args, name = singleSubjectDefinitionName(definition), subject = (fields !== void 0 ? startSubject(definition, fields) : void 0) ?? scope?.subject;
|
|
1585
|
+
if (subject === void 0) return !1;
|
|
1586
|
+
if (scope?.fetchDataset === void 0) throw new 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.`);
|
|
1587
|
+
const dataset = await scope.fetchDataset();
|
|
1588
|
+
return sliceHasInFlightSubject({
|
|
1589
|
+
dataset: dataset,
|
|
1590
|
+
subject: subject,
|
|
1591
|
+
definition: name
|
|
1592
|
+
});
|
|
1594
1593
|
}
|
|
1595
1594
|
|
|
1596
|
-
function
|
|
1597
|
-
const
|
|
1598
|
-
|
|
1599
|
-
|
|
1595
|
+
function singleSubjectDefinitionName(definition) {
|
|
1596
|
+
const label = definition.name ?? "<unnamed>";
|
|
1597
|
+
if (definition.start?.requirements?.find(requirement => requirement.type === "singleSubject") === void 0) throw new ContractViolationError(`singleSubjectRequirementRefused called for definition "${label}", which declares no \`singleSubject\` requirement — evaluate only what the definition declares.`);
|
|
1598
|
+
if (definition.name === void 0) throw new ContractViolationError("singleSubjectRequirementRefused needs the definition `name` — the rule scopes its in-flight scan to instances of the definition, which a nameless source cannot identify.");
|
|
1599
|
+
return definition.name;
|
|
1600
1600
|
}
|
|
1601
1601
|
|
|
1602
1602
|
function rethrowNamingDefinition({err: err, definition: definition, key: key}) {
|
|
1603
|
-
rethrowWithContext(err,
|
|
1603
|
+
rethrowWithContext(err, `${key === "filter" ? "start.filter" : "start requirement"} on definition "${definition.name ?? "<unnamed>"}" failed to evaluate (check the predicate and its evaluation inputs)`);
|
|
1604
1604
|
}
|
|
1605
1605
|
|
|
1606
|
-
function startContextParams({definition: definition, scope: scope, fields: fields
|
|
1607
|
-
const
|
|
1608
|
-
return fields !== void 0 && (params.fields = fields),
|
|
1609
|
-
params;
|
|
1606
|
+
function startContextParams({definition: definition, scope: scope, fields: fields}) {
|
|
1607
|
+
const params = baseStartParams(definition, scope);
|
|
1608
|
+
return fields !== void 0 && (params.fields = fields), params;
|
|
1610
1609
|
}
|
|
1611
1610
|
|
|
1612
1611
|
function baseStartParams(definition, scope) {
|
|
@@ -1623,10 +1622,6 @@ function baseStartParams(definition, scope) {
|
|
|
1623
1622
|
};
|
|
1624
1623
|
}
|
|
1625
1624
|
|
|
1626
|
-
function readsSubjectHasInFlightInstance(groq) {
|
|
1627
|
-
return conditionParameterNames(groq).has(SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR);
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
1625
|
function startSubject(definition, fields) {
|
|
1631
1626
|
const subjectEntry = (definition.fields ?? []).find(isSubjectEntry);
|
|
1632
1627
|
if (subjectEntry === void 0) return;
|
|
@@ -1634,15 +1629,12 @@ function startSubject(definition, fields) {
|
|
|
1634
1629
|
return isGdr(value) ? value.id : void 0;
|
|
1635
1630
|
}
|
|
1636
1631
|
|
|
1637
|
-
function
|
|
1632
|
+
function sliceHasInFlightSubject(args) {
|
|
1633
|
+
const {dataset: dataset, subject: subject, definition: definition} = args;
|
|
1638
1634
|
return dataset.some(row => {
|
|
1639
1635
|
if (typeof row != "object" || row === null) return !1;
|
|
1640
1636
|
const instance = row;
|
|
1641
|
-
return instance.
|
|
1642
|
-
if (typeof entry != "object" || entry === null) return !1;
|
|
1643
|
-
const field = entry;
|
|
1644
|
-
return field._type === "subject" && isGdr(field.value) && field.value.id === subject;
|
|
1645
|
-
});
|
|
1637
|
+
return instance.completedAt != null || instance.definition !== definition ? !1 : instance.subject === subject;
|
|
1646
1638
|
});
|
|
1647
1639
|
}
|
|
1648
1640
|
|
|
@@ -1672,11 +1664,11 @@ function startFilterSyntaxIssues(groq) {
|
|
|
1672
1664
|
});
|
|
1673
1665
|
}
|
|
1674
1666
|
|
|
1675
|
-
function
|
|
1667
|
+
function startRequirementSyntaxIssues(groq) {
|
|
1676
1668
|
return startContextSyntaxIssues({
|
|
1677
1669
|
groq: groq,
|
|
1678
|
-
vars:
|
|
1679
|
-
context: "start-
|
|
1670
|
+
vars: START_REQUIREMENT_VARS,
|
|
1671
|
+
context: "start-requirement"
|
|
1680
1672
|
});
|
|
1681
1673
|
}
|
|
1682
1674
|
|
|
@@ -1684,7 +1676,7 @@ function startContextSyntaxIssues({groq: groq, vars: vars, context: context, ski
|
|
|
1684
1676
|
try {
|
|
1685
1677
|
parse(groq);
|
|
1686
1678
|
} catch (err) {
|
|
1687
|
-
return [
|
|
1679
|
+
return [ errorMessage(err) ];
|
|
1688
1680
|
}
|
|
1689
1681
|
const bound = new Set(vars.map(v2 => v2.name));
|
|
1690
1682
|
return [ ...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(", "));
|
|
@@ -2523,24 +2515,24 @@ function applyFieldSet(op, ctx) {
|
|
|
2523
2515
|
src: op.value,
|
|
2524
2516
|
ctx: ctx,
|
|
2525
2517
|
target: entrySlot(entry)
|
|
2526
|
-
})
|
|
2527
|
-
return validateFieldValue({
|
|
2518
|
+
}), validated = validateFieldValue({
|
|
2528
2519
|
entryType: entry._type,
|
|
2529
2520
|
entryName: entry.name,
|
|
2530
2521
|
value: value,
|
|
2531
2522
|
...entryShape(entry)
|
|
2532
|
-
})
|
|
2523
|
+
});
|
|
2524
|
+
return assertRuntimeRefsWithinSurface({
|
|
2533
2525
|
entryType: entry._type,
|
|
2534
2526
|
entryName: entry.name,
|
|
2535
|
-
value:
|
|
2527
|
+
value: validated,
|
|
2536
2528
|
...entryShape(entry),
|
|
2537
2529
|
ctx: ctx,
|
|
2538
2530
|
src: op.value
|
|
2539
|
-
}), setEntryValue(entry,
|
|
2531
|
+
}), setEntryValue(entry, validated), {
|
|
2540
2532
|
opType: op.type,
|
|
2541
2533
|
target: op.target,
|
|
2542
2534
|
resolved: {
|
|
2543
|
-
value:
|
|
2535
|
+
value: validated
|
|
2544
2536
|
}
|
|
2545
2537
|
};
|
|
2546
2538
|
}
|
|
@@ -2601,27 +2593,27 @@ function applyFieldAppend(op, ctx) {
|
|
|
2601
2593
|
...slot !== void 0 ? {
|
|
2602
2594
|
target: slot
|
|
2603
2595
|
} : {}
|
|
2604
|
-
})
|
|
2605
|
-
validateFieldAppendItem({
|
|
2596
|
+
}), validated = validateFieldAppendItem({
|
|
2606
2597
|
entryType: entry._type,
|
|
2607
2598
|
entryName: entry.name,
|
|
2608
2599
|
item: item,
|
|
2609
2600
|
types: entry._type === "doc.refs" ? entry.types : void 0,
|
|
2610
2601
|
of: entry._type === "array" ? entry.of : void 0
|
|
2611
|
-
})
|
|
2602
|
+
});
|
|
2603
|
+
assertRuntimeRefsWithinSurface({
|
|
2612
2604
|
entryType: entry._type === "doc.refs" ? "doc.ref" : "object",
|
|
2613
2605
|
entryName: entry.name,
|
|
2614
|
-
value:
|
|
2606
|
+
value: validated,
|
|
2615
2607
|
fields: entry._type === "array" ? entry.of : void 0,
|
|
2616
2608
|
ctx: ctx,
|
|
2617
2609
|
src: op.value
|
|
2618
2610
|
});
|
|
2619
2611
|
const current = Array.isArray(entry.value) ? entry.value : [];
|
|
2620
|
-
return setEntryValue(entry, [ ...current, withRowKey(
|
|
2612
|
+
return setEntryValue(entry, [ ...current, withRowKey(validated) ]), {
|
|
2621
2613
|
opType: op.type,
|
|
2622
2614
|
target: op.target,
|
|
2623
2615
|
resolved: {
|
|
2624
|
-
item:
|
|
2616
|
+
item: validated
|
|
2625
2617
|
}
|
|
2626
2618
|
};
|
|
2627
2619
|
}
|
|
@@ -2649,8 +2641,9 @@ async function applyFieldUpdateWhere(op, ctx) {
|
|
|
2649
2641
|
mode: "value",
|
|
2650
2642
|
issues: [ `field.updateWhere value must resolve to an object of fields to merge (target "${op.target.field}")` ]
|
|
2651
2643
|
});
|
|
2644
|
+
const mergeRecord = merge;
|
|
2652
2645
|
requireNoReservedMergeKeys({
|
|
2653
|
-
merge:
|
|
2646
|
+
merge: mergeRecord,
|
|
2654
2647
|
entry: entry,
|
|
2655
2648
|
op: op
|
|
2656
2649
|
});
|
|
@@ -2660,25 +2653,27 @@ async function applyFieldUpdateWhere(op, ctx) {
|
|
|
2660
2653
|
ctx: ctx
|
|
2661
2654
|
}), next = rows.map((row, index) => matches[index] ? {
|
|
2662
2655
|
...row,
|
|
2663
|
-
...
|
|
2664
|
-
} : row)
|
|
2665
|
-
return validateFieldValue({
|
|
2656
|
+
...mergeRecord
|
|
2657
|
+
} : row), validated = validateFieldValue({
|
|
2666
2658
|
entryType: entry._type,
|
|
2667
2659
|
entryName: entry.name,
|
|
2668
2660
|
value: next,
|
|
2669
2661
|
of: entry.of
|
|
2670
|
-
})
|
|
2662
|
+
});
|
|
2663
|
+
assertRuntimeRefsWithinSurface({
|
|
2671
2664
|
entryType: "object",
|
|
2672
2665
|
entryName: entry.name,
|
|
2673
2666
|
value: merge,
|
|
2674
2667
|
fields: entry.of,
|
|
2675
2668
|
ctx: ctx,
|
|
2676
2669
|
src: op.value
|
|
2677
|
-
}), setEntryValue(entry,
|
|
2670
|
+
}), setEntryValue(entry, validated);
|
|
2671
|
+
const firstMatch = matches.indexOf(!0), persistedRows = validated, persistedMerge = firstMatch === -1 ? merge : Object.fromEntries(Object.keys(mergeRecord).map(key => [ key, persistedRows[firstMatch]?.[key] ]));
|
|
2672
|
+
return {
|
|
2678
2673
|
opType: op.type,
|
|
2679
2674
|
target: op.target,
|
|
2680
2675
|
resolved: {
|
|
2681
|
-
merge:
|
|
2676
|
+
merge: persistedMerge
|
|
2682
2677
|
}
|
|
2683
2678
|
};
|
|
2684
2679
|
}
|
|
@@ -2870,8 +2865,8 @@ function validateDefinition(definition) {
|
|
|
2870
2865
|
address: address
|
|
2871
2866
|
}));
|
|
2872
2867
|
}
|
|
2873
|
-
definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter))
|
|
2874
|
-
definition.start?.
|
|
2868
|
+
definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter));
|
|
2869
|
+
for (const [index, requirement] of (definition.start?.requirements ?? []).entries()) requirement.type === "groq" && v2.report(`start.requirements[${index}].query`, startRequirementSyntaxIssues(requirement.query));
|
|
2875
2870
|
for (const entry of definition.fields ?? []) v2.checkEntry(entry, `workflow.fields "${entry.name}"`);
|
|
2876
2871
|
for (const stage of definition.stages) validateStage(v2, stage);
|
|
2877
2872
|
for (const issue of checkWorkflowInvariants(definition)) v2.errors.push(` · ${formatIssuePath(issue.path)}: ${issue.message}`);
|
|
@@ -3301,6 +3296,11 @@ function definitionsListGroq(versionOrder) {
|
|
|
3301
3296
|
return `*[_type == "${WORKFLOW_DEFINITION_TYPE}" && ${tagScopeFilter()}] | order(name asc, version ${versionOrder})`;
|
|
3302
3297
|
}
|
|
3303
3298
|
|
|
3299
|
+
function latestDefinitionsGroq() {
|
|
3300
|
+
const scoped = `_type == "${WORKFLOW_DEFINITION_TYPE}" && ${tagScopeFilter()}`;
|
|
3301
|
+
return `*[${scoped} && version == math::max(*[${scoped} && name == ^.name].version)] | order(name asc)`;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
3304
|
function latestDeployedDefinitions(rows) {
|
|
3305
3305
|
const byName = /* @__PURE__ */ new Map;
|
|
3306
3306
|
for (const row of rows) {
|
|
@@ -3382,7 +3382,7 @@ function blockedState(input) {
|
|
|
3382
3382
|
if (blocked !== void 0) return {
|
|
3383
3383
|
state: "blocked",
|
|
3384
3384
|
activity: blocked.activity.name,
|
|
3385
|
-
requirements: blocked.unmetRequirements ?? [],
|
|
3385
|
+
requirements: (blocked.unmetRequirements ?? []).map(requirement => requirement.name),
|
|
3386
3386
|
assignees: input.assignees[blocked.activity.name] ?? []
|
|
3387
3387
|
};
|
|
3388
3388
|
}
|
|
@@ -3425,7 +3425,7 @@ function diagnoseInstance(input) {
|
|
|
3425
3425
|
};
|
|
3426
3426
|
}
|
|
3427
3427
|
|
|
3428
|
-
const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects" ]);
|
|
3428
|
+
const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
|
|
3429
3429
|
|
|
3430
3430
|
function remediationsForCause(cause) {
|
|
3431
3431
|
switch (cause.kind) {
|
|
@@ -3927,7 +3927,7 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3927
3927
|
defaultValue: defaultValue
|
|
3928
3928
|
});
|
|
3929
3929
|
if (entry.initialValue?.type === "query") {
|
|
3930
|
-
const
|
|
3930
|
+
const check = parseFieldValue({
|
|
3931
3931
|
entryType: entry.type,
|
|
3932
3932
|
value: value,
|
|
3933
3933
|
types: entry.types,
|
|
@@ -3936,9 +3936,9 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3936
3936
|
options: entry.options,
|
|
3937
3937
|
validation: entry.validation
|
|
3938
3938
|
});
|
|
3939
|
-
return issues
|
|
3939
|
+
return "issues" in check ? (ctx.recordDiscard?.({
|
|
3940
3940
|
field: entry.name,
|
|
3941
|
-
detail: issues.join("; ")
|
|
3941
|
+
detail: check.issues.join("; ")
|
|
3942
3942
|
}), buildResolvedEntry({
|
|
3943
3943
|
entry: entry,
|
|
3944
3944
|
value: defaultValue,
|
|
@@ -3946,12 +3946,12 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3946
3946
|
now: ctx.now
|
|
3947
3947
|
})) : buildResolvedEntry({
|
|
3948
3948
|
entry: entry,
|
|
3949
|
-
value:
|
|
3949
|
+
value: check.output,
|
|
3950
3950
|
_key: randomKey2(),
|
|
3951
3951
|
now: ctx.now
|
|
3952
3952
|
});
|
|
3953
3953
|
}
|
|
3954
|
-
|
|
3954
|
+
const validated = validateFieldValue({
|
|
3955
3955
|
entryType: entry.type,
|
|
3956
3956
|
entryName: entry.name,
|
|
3957
3957
|
value: value,
|
|
@@ -3960,16 +3960,17 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
|
|
|
3960
3960
|
of: entry.of,
|
|
3961
3961
|
options: entry.options,
|
|
3962
3962
|
validation: entry.validation
|
|
3963
|
-
})
|
|
3963
|
+
});
|
|
3964
|
+
return entry.initialValue?.type === "input" && ctx.inputProvenance !== "definition" && assertRefsWithinSurface({
|
|
3964
3965
|
entryType: entry.type,
|
|
3965
3966
|
entryName: entry.name,
|
|
3966
|
-
value:
|
|
3967
|
+
value: validated,
|
|
3967
3968
|
fields: entry.fields,
|
|
3968
3969
|
of: entry.of,
|
|
3969
3970
|
surface: ctx.refSurface
|
|
3970
3971
|
}), buildResolvedEntry({
|
|
3971
3972
|
entry: entry,
|
|
3972
|
-
value:
|
|
3973
|
+
value: validated,
|
|
3973
3974
|
_key: randomKey2(),
|
|
3974
3975
|
now: ctx.now
|
|
3975
3976
|
});
|
|
@@ -4001,12 +4002,27 @@ function assertInputValueShape(entry, value) {
|
|
|
4001
4002
|
function assertGdrShape(value, context) {
|
|
4002
4003
|
if (typeof value != "object" || value === null) throw new ContractViolationError(`Invalid GDR for ${context}: expected { id: "<scheme>:...", type: "<schema>" }, got ${typeof value}.`);
|
|
4003
4004
|
const v2 = value;
|
|
4004
|
-
if (typeof v2.id != "string"
|
|
4005
|
+
if (typeof v2.id != "string") throw invalidGdrUriError(context, v2.id);
|
|
4006
|
+
try {
|
|
4007
|
+
parseGdr(v2.id);
|
|
4008
|
+
} catch (error) {
|
|
4009
|
+
throw error instanceof VersionSpecificDatasetGdrError ? new ContractViolationError(`Invalid GDR for ${context}: ${error.message}`) : invalidGdrUriError(context, v2.id);
|
|
4010
|
+
}
|
|
4005
4011
|
if (typeof v2.type != "string" || v2.type.length === 0) throw new ContractViolationError(`Invalid GDR for ${context}: \`type\` (schema name) must be a non-empty string. Got ${JSON.stringify(v2.type)}.`);
|
|
4006
4012
|
}
|
|
4007
4013
|
|
|
4014
|
+
function invalidGdrUriError(context, id) {
|
|
4015
|
+
return new 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.`);
|
|
4016
|
+
}
|
|
4017
|
+
|
|
4008
4018
|
function normalizeQueryResult({entryType: entryType, raw: raw, workflowResource: workflowResource}) {
|
|
4009
|
-
|
|
4019
|
+
if (raw == null) return raw;
|
|
4020
|
+
try {
|
|
4021
|
+
return isSingleDocRefKind(entryType) ? coerceToGdr(raw, workflowResource) : entryType === "doc.refs" ? Array.isArray(raw) ? raw.map(item => coerceToGdr(item, workflowResource)).filter(v2 => v2 !== null) : [] : raw;
|
|
4022
|
+
} catch (error) {
|
|
4023
|
+
if (error instanceof VersionSpecificDatasetGdrError) return raw;
|
|
4024
|
+
throw error;
|
|
4025
|
+
}
|
|
4010
4026
|
}
|
|
4011
4027
|
|
|
4012
4028
|
function coerceGdrShape(raw, workflowResource) {
|
|
@@ -4348,219 +4364,706 @@ function parseInstanceDocument(doc) {
|
|
|
4348
4364
|
});
|
|
4349
4365
|
}
|
|
4350
4366
|
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4367
|
+
const SYNC_COMMIT = {
|
|
4368
|
+
visibility: "sync"
|
|
4369
|
+
}, ENGINE_API_VERSION = "2026-04-29", REQUEST_TAG = {
|
|
4370
|
+
engine: "workflow",
|
|
4371
|
+
deploy: "workflow.deploy",
|
|
4372
|
+
deleteDefinition: "workflow.delete-definition",
|
|
4373
|
+
start: "workflow.start",
|
|
4374
|
+
fireAction: "workflow.fire-action",
|
|
4375
|
+
editField: "workflow.edit-field",
|
|
4376
|
+
completeEffect: "workflow.complete-effect",
|
|
4377
|
+
commitEffectOps: "workflow.commit-effect-ops",
|
|
4378
|
+
tick: "workflow.tick",
|
|
4379
|
+
evaluate: "workflow.evaluate",
|
|
4380
|
+
evaluateStart: "workflow.evaluate-start",
|
|
4381
|
+
diagnose: "workflow.diagnose",
|
|
4382
|
+
availableActions: "workflow.available-actions",
|
|
4383
|
+
setStage: "workflow.set-stage",
|
|
4384
|
+
abort: "workflow.abort",
|
|
4385
|
+
resetActivity: "workflow.reset-activity",
|
|
4386
|
+
getInstance: "workflow.get-instance",
|
|
4387
|
+
children: "workflow.children",
|
|
4388
|
+
instancesForDocument: "workflow.instances-for-document",
|
|
4389
|
+
definitionsForDocument: "workflow.definitions-for-document",
|
|
4390
|
+
query: "workflow.query",
|
|
4391
|
+
discover: "workflow.discover",
|
|
4392
|
+
guardQuery: "workflow.guard.query",
|
|
4393
|
+
guardDeploy: "workflow.guard.deploy",
|
|
4394
|
+
guardRefresh: "workflow.guard.refresh",
|
|
4395
|
+
guardRetract: "workflow.guard.retract",
|
|
4396
|
+
effectList: "workflow.effect.list",
|
|
4397
|
+
effectFind: "workflow.effect.find",
|
|
4398
|
+
drain: "workflow.drain",
|
|
4399
|
+
effect: "workflow.effect",
|
|
4400
|
+
verifyDefinitions: "workflow.verify-definitions",
|
|
4401
|
+
accessResolveActor: "workflow.access.resolve-actor",
|
|
4402
|
+
accessGrants: "workflow.access.grants"
|
|
4403
|
+
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
4355
4404
|
|
|
4356
|
-
function
|
|
4357
|
-
return
|
|
4405
|
+
function unwrapPatch(patch) {
|
|
4406
|
+
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4358
4407
|
}
|
|
4359
4408
|
|
|
4360
|
-
|
|
4361
|
-
const doc = await getInstanceDocument(client, instanceId);
|
|
4362
|
-
if (!doc) throw new InstanceNotFoundError({
|
|
4363
|
-
instanceId: instanceId
|
|
4364
|
-
});
|
|
4365
|
-
if (doc.tag !== tag) throw new InstanceNotFoundError({
|
|
4366
|
-
instanceId: instanceId,
|
|
4367
|
-
detail: "not visible to this engine: tag mismatch"
|
|
4368
|
-
});
|
|
4369
|
-
return doc;
|
|
4370
|
-
}
|
|
4409
|
+
const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4371
4410
|
|
|
4372
|
-
function
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
_type: "context.string",
|
|
4377
|
-
name: name,
|
|
4378
|
-
value: value
|
|
4379
|
-
} : typeof value == "number" ? {
|
|
4380
|
-
_key: _key,
|
|
4381
|
-
_type: "context.number",
|
|
4382
|
-
name: name,
|
|
4383
|
-
value: value
|
|
4384
|
-
} : typeof value == "boolean" ? {
|
|
4385
|
-
_key: _key,
|
|
4386
|
-
_type: "context.boolean",
|
|
4387
|
-
name: name,
|
|
4388
|
-
value: value
|
|
4389
|
-
} : {
|
|
4390
|
-
_key: _key,
|
|
4391
|
-
_type: "context.ref",
|
|
4392
|
-
name: name,
|
|
4393
|
-
value: value
|
|
4394
|
-
};
|
|
4411
|
+
function unwrapRequestTag(client) {
|
|
4412
|
+
let current = client;
|
|
4413
|
+
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
4414
|
+
return current;
|
|
4395
4415
|
}
|
|
4396
4416
|
|
|
4397
|
-
function
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4417
|
+
function withRequestTag(client, fallback) {
|
|
4418
|
+
let byTag = wrapperCache.get(client);
|
|
4419
|
+
byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
|
|
4420
|
+
const cached = byTag.get(fallback);
|
|
4421
|
+
if (cached !== void 0) return cached;
|
|
4422
|
+
const wrapped = buildTaggedClient(client, fallback);
|
|
4423
|
+
return byTag.set(fallback, wrapped), wrapped;
|
|
4404
4424
|
}
|
|
4405
4425
|
|
|
4406
|
-
function
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4426
|
+
function effectHandlerClient(client) {
|
|
4427
|
+
const cached = effectHandlerClientCache.get(client);
|
|
4428
|
+
if (cached !== void 0) return cached;
|
|
4429
|
+
let tagged;
|
|
4430
|
+
if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
|
|
4431
|
+
const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
|
|
4432
|
+
tagged = client.withConfig({
|
|
4433
|
+
requestTagPrefix: effectTag
|
|
4434
|
+
});
|
|
4412
4435
|
}
|
|
4413
|
-
|
|
4414
|
-
return json;
|
|
4436
|
+
return effectHandlerClientCache.set(client, tagged), tagged;
|
|
4415
4437
|
}
|
|
4416
4438
|
|
|
4417
|
-
function
|
|
4418
|
-
|
|
4419
|
-
_key: randomKey(),
|
|
4420
|
-
_type: "stageEntered",
|
|
4421
|
-
at: now,
|
|
4422
|
-
stage: args.initialStage,
|
|
4423
|
-
...actor !== void 0 ? {
|
|
4424
|
-
actor: actor
|
|
4425
|
-
} : {}
|
|
4426
|
-
}, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
|
|
4427
|
-
_id: id,
|
|
4428
|
-
_type: WORKFLOW_INSTANCE_TYPE,
|
|
4429
|
-
_rev: "",
|
|
4430
|
-
_createdAt: now,
|
|
4431
|
-
_updatedAt: now,
|
|
4432
|
-
tag: args.tag,
|
|
4433
|
-
workflowResource: args.workflowResource,
|
|
4434
|
-
definition: args.definitionName,
|
|
4435
|
-
pinnedVersion: args.pinnedVersion,
|
|
4436
|
-
...args.pinnedContentHash !== void 0 ? {
|
|
4437
|
-
pinnedContentHash: args.pinnedContentHash
|
|
4438
|
-
} : {},
|
|
4439
|
-
definitionSnapshot: JSON.stringify(args.definition),
|
|
4440
|
-
fields: args.fields,
|
|
4441
|
-
context: args.context,
|
|
4442
|
-
ancestors: args.ancestors,
|
|
4443
|
-
...perspective !== void 0 ? {
|
|
4444
|
-
perspective: perspective
|
|
4445
|
-
} : {},
|
|
4446
|
-
currentStage: args.initialStage,
|
|
4447
|
-
stages: [],
|
|
4448
|
-
subworkflows: [],
|
|
4449
|
-
pendingEffects: [],
|
|
4450
|
-
effectHistory: [],
|
|
4451
|
-
history: history,
|
|
4452
|
-
startedAt: now,
|
|
4453
|
-
lastChangedAt: now
|
|
4454
|
-
};
|
|
4455
|
-
return {
|
|
4456
|
-
...body,
|
|
4457
|
-
...modelStampFor({
|
|
4458
|
-
documentType: "instance",
|
|
4459
|
-
document: body
|
|
4460
|
-
})
|
|
4461
|
-
};
|
|
4439
|
+
function effectHandlerResolver(resolver) {
|
|
4440
|
+
return mapResourceClientResolver(resolver, effectHandlerClient);
|
|
4462
4441
|
}
|
|
4463
4442
|
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
if (held !== void 0) {
|
|
4469
|
-
loaded.push(held), visited.add(uri);
|
|
4470
|
-
return;
|
|
4471
|
-
}
|
|
4472
|
-
const fetched = await loadByGdr({
|
|
4473
|
-
defaultClient: client,
|
|
4474
|
-
clientForGdr: clientForGdr,
|
|
4475
|
-
defaultResource: instance.workflowResource,
|
|
4476
|
-
uri: uri,
|
|
4477
|
-
perspective: perspective
|
|
4478
|
-
});
|
|
4479
|
-
fetched && (loaded.push(fetched), visited.add(uri));
|
|
4443
|
+
function mapResourceClientResolver(resolver, mapClient) {
|
|
4444
|
+
if (resolver !== void 0) return parsed => {
|
|
4445
|
+
const client = resolver(parsed);
|
|
4446
|
+
return client === void 0 ? void 0 : mapClient(client);
|
|
4480
4447
|
};
|
|
4481
|
-
loaded.push({
|
|
4482
|
-
doc: instance,
|
|
4483
|
-
resource: instance.workflowResource
|
|
4484
|
-
}), visited.add(selfGdr(instance));
|
|
4485
|
-
for (const ref of collectWatchRefs(instance)) await loadInto(ref.id, readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE);
|
|
4486
|
-
return buildSnapshot({
|
|
4487
|
-
docs: loaded
|
|
4488
|
-
});
|
|
4489
|
-
}
|
|
4490
|
-
|
|
4491
|
-
async function loadByGdr({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4492
|
-
const parsed = tryParseGdr(uri);
|
|
4493
|
-
if (parsed === void 0) {
|
|
4494
|
-
const doc2 = await readDoc({
|
|
4495
|
-
client: defaultClient,
|
|
4496
|
-
id: uri,
|
|
4497
|
-
perspective: perspective
|
|
4498
|
-
});
|
|
4499
|
-
return doc2 ? {
|
|
4500
|
-
doc: doc2,
|
|
4501
|
-
resource: defaultResource
|
|
4502
|
-
} : null;
|
|
4503
|
-
}
|
|
4504
|
-
const routed = clientForGdr(parsed), doc = await readDoc({
|
|
4505
|
-
client: routed,
|
|
4506
|
-
id: parsed.documentId,
|
|
4507
|
-
perspective: perspective
|
|
4508
|
-
});
|
|
4509
|
-
return doc ? {
|
|
4510
|
-
doc: doc,
|
|
4511
|
-
resource: resourceFromParsed(parsed)
|
|
4512
|
-
} : null;
|
|
4513
4448
|
}
|
|
4514
4449
|
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
const doc2 = await client.getDocument(id) ?? null;
|
|
4518
|
-
return doc2 ? doc2._type === WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc2) : assertReadableModel(doc2) : null;
|
|
4519
|
-
}
|
|
4520
|
-
const {query: query, params: params} = contentDocQuery(id);
|
|
4521
|
-
return await client.fetch(query, params, {
|
|
4522
|
-
perspective: perspective
|
|
4523
|
-
}) ?? null;
|
|
4450
|
+
function isWorkflowsFamilyPrefix(prefix) {
|
|
4451
|
+
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4524
4452
|
}
|
|
4525
4453
|
|
|
4526
|
-
function
|
|
4527
|
-
|
|
4454
|
+
function clientRequestTagPrefix(client) {
|
|
4455
|
+
const probe = client;
|
|
4456
|
+
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4528
4457
|
}
|
|
4529
4458
|
|
|
4530
|
-
function
|
|
4531
|
-
|
|
4459
|
+
function composeRequestTag(prefix, tag) {
|
|
4460
|
+
if (prefix === void 0) return tag;
|
|
4461
|
+
const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
|
|
4462
|
+
return `${prefix}.${relative}`;
|
|
4532
4463
|
}
|
|
4533
4464
|
|
|
4534
|
-
function
|
|
4535
|
-
return
|
|
4536
|
-
client: client,
|
|
4537
|
-
instanceId: instanceId,
|
|
4538
|
-
options: {
|
|
4539
|
-
clientForGdr: options.clientForGdr,
|
|
4540
|
-
refSurface: options.refSurface,
|
|
4541
|
-
...options.actor ? {
|
|
4542
|
-
actor: options.actor
|
|
4543
|
-
} : {},
|
|
4544
|
-
...options.clock ? {
|
|
4545
|
-
clock: options.clock
|
|
4546
|
-
} : {},
|
|
4547
|
-
...options.executionContext ? {
|
|
4548
|
-
executionContext: options.executionContext
|
|
4549
|
-
} : {},
|
|
4550
|
-
...options.telemetry ? {
|
|
4551
|
-
telemetry: options.telemetry
|
|
4552
|
-
} : {}
|
|
4553
|
-
}
|
|
4554
|
-
});
|
|
4465
|
+
function stripWorkflowRoot(tag) {
|
|
4466
|
+
return tag.startsWith("workflow.") ? tag.slice(9) : tag;
|
|
4555
4467
|
}
|
|
4556
4468
|
|
|
4557
|
-
|
|
4558
|
-
const
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4469
|
+
function buildTaggedClient(client, fallback) {
|
|
4470
|
+
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
|
|
4471
|
+
tag: normalize(fallback)
|
|
4472
|
+
} : options.tag === void 0 ? {
|
|
4473
|
+
...options,
|
|
4474
|
+
tag: normalize(fallback)
|
|
4475
|
+
} : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
|
|
4476
|
+
...options,
|
|
4477
|
+
tag: normalize(options.tag)
|
|
4478
|
+
} : options, wrapPatch = patch => {
|
|
4479
|
+
let target = patch;
|
|
4480
|
+
const wrapped = {
|
|
4481
|
+
get [RAW_PATCH]() {
|
|
4482
|
+
return target;
|
|
4483
|
+
},
|
|
4484
|
+
set: props => (target = target.set(props), wrapped),
|
|
4485
|
+
setIfMissing: props => (target = target.setIfMissing(props), wrapped),
|
|
4486
|
+
unset: paths => (target = target.unset(paths), wrapped),
|
|
4487
|
+
ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
|
|
4488
|
+
commit: options => target.commit(stamp(options))
|
|
4489
|
+
};
|
|
4490
|
+
return wrapped;
|
|
4491
|
+
}, wrapTransaction = tx => {
|
|
4492
|
+
let target = tx;
|
|
4493
|
+
const wrapped = {
|
|
4494
|
+
create: doc => (target = target.create(doc), wrapped),
|
|
4495
|
+
patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
|
|
4496
|
+
delete: id => (target = target.delete(id), wrapped),
|
|
4497
|
+
commit: options => target.commit(stamp(options))
|
|
4498
|
+
};
|
|
4499
|
+
return wrapped;
|
|
4500
|
+
}, overrides = {
|
|
4501
|
+
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
4502
|
+
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
4503
|
+
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
4504
|
+
patch: documentId => wrapPatch(client.patch(documentId)),
|
|
4505
|
+
create: (doc, options) => client.create(doc, stamp(options)),
|
|
4506
|
+
transaction: () => wrapTransaction(client.transaction()),
|
|
4507
|
+
...client.withConfig !== void 0 ? {
|
|
4508
|
+
withConfig: config => withRequestTag(client.withConfig(config), fallback)
|
|
4509
|
+
} : {},
|
|
4510
|
+
...client.action !== void 0 ? {
|
|
4511
|
+
action: (action, options) => client.action(action, stamp(options))
|
|
4512
|
+
} : {},
|
|
4513
|
+
...client.request !== void 0 ? {
|
|
4514
|
+
request: opts => client.request(stamp(opts))
|
|
4515
|
+
} : {}
|
|
4516
|
+
};
|
|
4517
|
+
return new Proxy(client, {
|
|
4518
|
+
has: (target, property) => Object.hasOwn(overrides, property) || property in target,
|
|
4519
|
+
get: (target, property) => {
|
|
4520
|
+
if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
|
|
4521
|
+
const value = Reflect.get(target, property, target);
|
|
4522
|
+
return typeof value == "function" ? value.bind(target) : value;
|
|
4523
|
+
}
|
|
4524
|
+
});
|
|
4525
|
+
}
|
|
4526
|
+
|
|
4527
|
+
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
4528
|
+
|
|
4529
|
+
function pinApiVersion(client) {
|
|
4530
|
+
const raw = unwrapRequestTag(client);
|
|
4531
|
+
if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
|
|
4532
|
+
let sibling = pinCache.get(raw);
|
|
4533
|
+
return sibling === void 0 && (sibling = raw.withConfig({
|
|
4534
|
+
apiVersion: ENGINE_API_VERSION
|
|
4535
|
+
}), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
function taggedResolver(resolver, fallback) {
|
|
4539
|
+
return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
function taggedScope(args, tag) {
|
|
4543
|
+
const resourceClients = taggedResolver(args.resourceClients, tag);
|
|
4544
|
+
return {
|
|
4545
|
+
...args,
|
|
4546
|
+
client: withRequestTag(pinApiVersion(args.client), tag),
|
|
4547
|
+
...resourceClients !== void 0 ? {
|
|
4548
|
+
resourceClients: resourceClients
|
|
4549
|
+
} : {}
|
|
4550
|
+
};
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
const ACTOR_KIND_SET = new Set(ACTOR_KINDS), resolutionCache = /* @__PURE__ */ new WeakMap, warnedInstances = /* @__PURE__ */ new WeakMap;
|
|
4554
|
+
|
|
4555
|
+
async function normalizeInstanceIdentities(args) {
|
|
4556
|
+
const {client: client, instance: instance} = args, pending = collectLegacyIds(instance);
|
|
4557
|
+
if (pending.size === 0) return instance;
|
|
4558
|
+
const resolved = await resolveLegacyIds({
|
|
4559
|
+
client: client,
|
|
4560
|
+
instance: instance,
|
|
4561
|
+
pending: pending
|
|
4562
|
+
}), unresolved = [ ...pending ].filter(id => !resolved.has(id));
|
|
4563
|
+
return unresolved.length > 0 ? (warnUnresolvedOnce({
|
|
4564
|
+
client: client,
|
|
4565
|
+
instance: instance,
|
|
4566
|
+
unresolved: unresolved
|
|
4567
|
+
}), instance) : rewriteIdentitySlots(instance, id => resolved.get(id));
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
async function resolveLegacyIds(args) {
|
|
4571
|
+
const resolved = /* @__PURE__ */ new Map, directoryIds = [];
|
|
4572
|
+
for (const id of args.pending) {
|
|
4573
|
+
const {globalId: globalId} = classifyPrincipalId(id);
|
|
4574
|
+
globalId !== void 0 ? resolved.set(id, globalId) : directoryIds.push(id);
|
|
4575
|
+
}
|
|
4576
|
+
const projectId = anchorProjectId(args.instance.workflowResource);
|
|
4577
|
+
if (directoryIds.length === 0 || projectId === void 0) return resolved;
|
|
4578
|
+
const fromDirectory = await resolveThroughDirectory({
|
|
4579
|
+
client: args.client,
|
|
4580
|
+
projectId: projectId,
|
|
4581
|
+
ids: directoryIds
|
|
4582
|
+
});
|
|
4583
|
+
for (const [id, globalId] of fromDirectory) resolved.set(id, globalId);
|
|
4584
|
+
return resolved;
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4587
|
+
function warnUnresolvedOnce(args) {
|
|
4588
|
+
const key = unwrapRequestTag(args.client);
|
|
4589
|
+
let warned = warnedInstances.get(key);
|
|
4590
|
+
warned === void 0 && (warned = /* @__PURE__ */ new Set, warnedInstances.set(key, warned)),
|
|
4591
|
+
!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.`));
|
|
4592
|
+
}
|
|
4593
|
+
|
|
4594
|
+
function anchorProjectId(resource) {
|
|
4595
|
+
if (resource.type === "dataset") return datasetResourceParts(resource.id).projectId;
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
function collectLegacyIds(instance) {
|
|
4599
|
+
const found = /* @__PURE__ */ new Set;
|
|
4600
|
+
return rewriteIdentitySlots(instance, id => {
|
|
4601
|
+
classifyPrincipalId(id).namespace === "project" && found.add(id);
|
|
4602
|
+
}), found;
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4605
|
+
function rewriteIdentitySlots(instance, visit) {
|
|
4606
|
+
const record = instance, fields = walkEntries(record.fields, visit), stages = walkStages(record.stages, visit);
|
|
4607
|
+
return fields === record.fields && stages === record.stages ? instance : {
|
|
4608
|
+
...record,
|
|
4609
|
+
fields: fields,
|
|
4610
|
+
stages: stages
|
|
4611
|
+
};
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4614
|
+
function walkStages(stages, visit) {
|
|
4615
|
+
return Array.isArray(stages) ? shareMap(stages, stage => {
|
|
4616
|
+
const walked = walkEntryRow({
|
|
4617
|
+
row: stage,
|
|
4618
|
+
visit: visit
|
|
4619
|
+
});
|
|
4620
|
+
if (walked === null || typeof walked != "object") return walked;
|
|
4621
|
+
const record = walked, activities = walkActivities(record.activities, visit);
|
|
4622
|
+
return activities === record.activities ? walked === stage ? stage : walked : {
|
|
4623
|
+
...record,
|
|
4624
|
+
activities: activities
|
|
4625
|
+
};
|
|
4626
|
+
}) : stages;
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
function walkActivities(activities, visit) {
|
|
4630
|
+
return Array.isArray(activities) ? shareMap(activities, activity => walkEntryRow({
|
|
4631
|
+
row: activity,
|
|
4632
|
+
visit: visit
|
|
4633
|
+
})) : activities;
|
|
4634
|
+
}
|
|
4635
|
+
|
|
4636
|
+
function walkEntryRow(args) {
|
|
4637
|
+
const {row: row, visit: visit} = args;
|
|
4638
|
+
if (row === null || typeof row != "object") return row;
|
|
4639
|
+
const record = row, patch = {}, fields = walkEntries(record.fields, visit);
|
|
4640
|
+
if (fields !== record.fields && (patch.fields = fields), typeof record.completedBy == "string") {
|
|
4641
|
+
const stamped = visit(record.completedBy) ?? record.completedBy;
|
|
4642
|
+
stamped !== record.completedBy && (patch.completedBy = stamped);
|
|
4643
|
+
}
|
|
4644
|
+
return Object.keys(patch).length === 0 ? row : {
|
|
4645
|
+
...record,
|
|
4646
|
+
...patch
|
|
4647
|
+
};
|
|
4648
|
+
}
|
|
4649
|
+
|
|
4650
|
+
function walkEntries(entries, visit) {
|
|
4651
|
+
return Array.isArray(entries) ? shareMap(entries, entry => {
|
|
4652
|
+
if (entry === null || typeof entry != "object") return entry;
|
|
4653
|
+
const record = entry, value = walkDeclaredValue({
|
|
4654
|
+
type: record._type,
|
|
4655
|
+
fields: record.fields,
|
|
4656
|
+
of: record.of,
|
|
4657
|
+
value: record.value,
|
|
4658
|
+
visit: visit
|
|
4659
|
+
});
|
|
4660
|
+
return value === record.value ? entry : {
|
|
4661
|
+
...record,
|
|
4662
|
+
value: value
|
|
4663
|
+
};
|
|
4664
|
+
}) : entries;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
function collectDeclaredGlobalIds(args) {
|
|
4668
|
+
const found = /* @__PURE__ */ new Set;
|
|
4669
|
+
return walkDeclaredValue({
|
|
4670
|
+
type: args.type,
|
|
4671
|
+
fields: args.fields,
|
|
4672
|
+
of: args.of,
|
|
4673
|
+
value: args.value,
|
|
4674
|
+
visit: id => {
|
|
4675
|
+
classifyPrincipalId(id).namespace === "global" && found.add(id);
|
|
4676
|
+
}
|
|
4677
|
+
}), found;
|
|
4678
|
+
}
|
|
4679
|
+
|
|
4680
|
+
function rewriteDeclaredPrincipalIds(args) {
|
|
4681
|
+
return walkDeclaredValue({
|
|
4682
|
+
type: args.type,
|
|
4683
|
+
fields: args.fields,
|
|
4684
|
+
of: args.of,
|
|
4685
|
+
value: args.value,
|
|
4686
|
+
visit: id => args.map.get(id)
|
|
4687
|
+
});
|
|
4688
|
+
}
|
|
4689
|
+
|
|
4690
|
+
function walkDeclaredValue(args) {
|
|
4691
|
+
const {type: type, value: value, visit: visit} = args;
|
|
4692
|
+
return type === "actor" || type === "assignee" ? visitPrincipalObject(value, visit) : type === "assignees" ? Array.isArray(value) ? shareMap(value, item => visitPrincipalObject(item, visit)) : value : type === "object" ? walkDeclaredObject({
|
|
4693
|
+
value: value,
|
|
4694
|
+
shapes: args.fields,
|
|
4695
|
+
visit: visit
|
|
4696
|
+
}) : type === "array" && Array.isArray(value) ? shareMap(value, row => walkDeclaredObject({
|
|
4697
|
+
value: row,
|
|
4698
|
+
shapes: args.of,
|
|
4699
|
+
visit: visit
|
|
4700
|
+
})) : value;
|
|
4701
|
+
}
|
|
4702
|
+
|
|
4703
|
+
function walkDeclaredObject(args) {
|
|
4704
|
+
const {value: value, shapes: shapes, visit: visit} = args;
|
|
4705
|
+
if (value === null || typeof value != "object" || Array.isArray(value) || !Array.isArray(shapes)) return value;
|
|
4706
|
+
const record = value, patch = {};
|
|
4707
|
+
for (const shape of shapes) {
|
|
4708
|
+
const step = walkDeclaredProperty({
|
|
4709
|
+
record: record,
|
|
4710
|
+
shape: shape,
|
|
4711
|
+
visit: visit
|
|
4712
|
+
});
|
|
4713
|
+
step !== void 0 && (patch[step.name] = step.value);
|
|
4714
|
+
}
|
|
4715
|
+
return Object.keys(patch).length === 0 ? value : {
|
|
4716
|
+
...record,
|
|
4717
|
+
...patch
|
|
4718
|
+
};
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
function walkDeclaredProperty(args) {
|
|
4722
|
+
const {record: record, shape: shape, visit: visit} = args;
|
|
4723
|
+
if (shape === null || typeof shape != "object") return;
|
|
4724
|
+
const name = shape.name;
|
|
4725
|
+
if (typeof name != "string" || !Object.hasOwn(record, name)) return;
|
|
4726
|
+
const walked = walkDeclaredValue({
|
|
4727
|
+
type: shape.type,
|
|
4728
|
+
fields: shape.fields,
|
|
4729
|
+
of: shape.of,
|
|
4730
|
+
value: record[name],
|
|
4731
|
+
visit: visit
|
|
4732
|
+
});
|
|
4733
|
+
return walked === record[name] ? void 0 : {
|
|
4734
|
+
name: name,
|
|
4735
|
+
value: walked
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4739
|
+
function visitPrincipalObject(value, visit) {
|
|
4740
|
+
if (value === null || typeof value != "object" || Array.isArray(value)) return value;
|
|
4741
|
+
const record = value;
|
|
4742
|
+
if (typeof record.id != "string" || record.type !== "user" && !(typeof record.kind == "string" && ACTOR_KIND_SET.has(record.kind))) return value;
|
|
4743
|
+
const stamped = visit(record.id) ?? record.id;
|
|
4744
|
+
return stamped === record.id ? value : {
|
|
4745
|
+
...record,
|
|
4746
|
+
id: stamped
|
|
4747
|
+
};
|
|
4748
|
+
}
|
|
4749
|
+
|
|
4750
|
+
function shareMap(items, fn) {
|
|
4751
|
+
let changed = !1;
|
|
4752
|
+
const next = items.map(item => {
|
|
4753
|
+
const out = fn(item);
|
|
4754
|
+
return out !== item && (changed = !0), out;
|
|
4755
|
+
});
|
|
4756
|
+
return changed ? next : items;
|
|
4757
|
+
}
|
|
4758
|
+
|
|
4759
|
+
const SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
4760
|
+
|
|
4761
|
+
async function resolveThroughDirectory(args) {
|
|
4762
|
+
const {client: client, projectId: projectId, ids: ids} = args, cache = cacheFor(unwrapRequestTag(client)), out = /* @__PURE__ */ new Map, safeMisses = ids.filter(id => {
|
|
4763
|
+
const hit = cache.get(id);
|
|
4764
|
+
return typeof hit == "string" && out.set(id, hit), hit === void 0;
|
|
4765
|
+
}).filter(id => SAFE_ID.test(id) && SAFE_ID.test(projectId));
|
|
4766
|
+
if (safeMisses.length === 0 || client.request === void 0) return out;
|
|
4767
|
+
try {
|
|
4768
|
+
const response = await client.request({
|
|
4769
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${safeMisses.map(encodeURIComponent).join(",")}`,
|
|
4770
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
4771
|
+
});
|
|
4772
|
+
ingestDirectoryRows({
|
|
4773
|
+
response: response,
|
|
4774
|
+
requested: new Set(safeMisses),
|
|
4775
|
+
cache: cache,
|
|
4776
|
+
out: out
|
|
4777
|
+
});
|
|
4778
|
+
for (const id of safeMisses) out.has(id) || cache.set(id, null);
|
|
4779
|
+
} catch (err) {
|
|
4780
|
+
console.warn(`workflow: project-users directory lookup failed for project "${projectId}" — legacy principal ids stay unresolved this pass. Original error: ${errorMessage(err)}`);
|
|
4781
|
+
}
|
|
4782
|
+
return out;
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
function cacheFor(client) {
|
|
4786
|
+
let cache = resolutionCache.get(client);
|
|
4787
|
+
return cache === void 0 && (cache = /* @__PURE__ */ new Map, resolutionCache.set(client, cache)),
|
|
4788
|
+
cache;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
function ingestDirectoryRows(args) {
|
|
4792
|
+
const records = Array.isArray(args.response) ? args.response : [ args.response ];
|
|
4793
|
+
for (const row of records) typeof row?.id != "string" || typeof row.sanityUserId != "string" || args.requested.has(row.id) && classifyPrincipalId(row.sanityUserId).namespace === "global" && (args.cache.set(row.id, row.sanityUserId),
|
|
4794
|
+
args.out.set(row.id, row.sanityUserId));
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
async function getInstanceDocument(client, instanceId) {
|
|
4798
|
+
const doc = await client.getDocument(instanceId);
|
|
4799
|
+
if (doc) return normalizeInstanceIdentities({
|
|
4800
|
+
client: client,
|
|
4801
|
+
instance: readInstanceDoc(doc)
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4805
|
+
function readInstanceDoc(doc) {
|
|
4806
|
+
return parseInstanceDocument(assertReadableModel(doc));
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
async function reload({client: client, instanceId: instanceId, tag: tag}) {
|
|
4810
|
+
const doc = await getInstanceDocument(client, instanceId);
|
|
4811
|
+
if (!doc) throw new InstanceNotFoundError({
|
|
4812
|
+
instanceId: instanceId
|
|
4813
|
+
});
|
|
4814
|
+
if (doc.tag !== tag) throw new InstanceNotFoundError({
|
|
4815
|
+
instanceId: instanceId,
|
|
4816
|
+
detail: "not visible to this engine: tag mismatch"
|
|
4817
|
+
});
|
|
4818
|
+
return doc;
|
|
4819
|
+
}
|
|
4820
|
+
|
|
4821
|
+
function contextEntry(name, value) {
|
|
4822
|
+
const _key = randomKey();
|
|
4823
|
+
return typeof value == "string" ? {
|
|
4824
|
+
_key: _key,
|
|
4825
|
+
_type: "context.string",
|
|
4826
|
+
name: name,
|
|
4827
|
+
value: value
|
|
4828
|
+
} : typeof value == "number" ? {
|
|
4829
|
+
_key: _key,
|
|
4830
|
+
_type: "context.number",
|
|
4831
|
+
name: name,
|
|
4832
|
+
value: value
|
|
4833
|
+
} : typeof value == "boolean" ? {
|
|
4834
|
+
_key: _key,
|
|
4835
|
+
_type: "context.boolean",
|
|
4836
|
+
name: name,
|
|
4837
|
+
value: value
|
|
4838
|
+
} : {
|
|
4839
|
+
_key: _key,
|
|
4840
|
+
_type: "context.ref",
|
|
4841
|
+
name: name,
|
|
4842
|
+
value: value
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4845
|
+
|
|
4846
|
+
function contextJsonEntry(name, value) {
|
|
4847
|
+
return {
|
|
4848
|
+
_key: randomKey(),
|
|
4849
|
+
_type: "context.json",
|
|
4850
|
+
name: name,
|
|
4851
|
+
value: serializeContextValue(name, value)
|
|
4852
|
+
};
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4855
|
+
function serializeContextValue(name, value) {
|
|
4856
|
+
let json;
|
|
4857
|
+
try {
|
|
4858
|
+
json = JSON.stringify(value);
|
|
4859
|
+
} catch (err) {
|
|
4860
|
+
rethrowWithContext(err, `context entry "${name}" holds unserializable JSON`);
|
|
4861
|
+
}
|
|
4862
|
+
if (json === void 0) throw new Error(`context entry "${name}" holds a non-JSON value (undefined, a function, or a symbol)`);
|
|
4863
|
+
return json;
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4866
|
+
function buildInstanceBase(args) {
|
|
4867
|
+
const {id: id, now: now, actor: actor, perspective: perspective, executionContext: executionContext} = args, entries = [ {
|
|
4868
|
+
_key: randomKey(),
|
|
4869
|
+
_type: "stageEntered",
|
|
4870
|
+
at: now,
|
|
4871
|
+
stage: args.initialStage,
|
|
4872
|
+
...actor !== void 0 ? {
|
|
4873
|
+
actor: actor
|
|
4874
|
+
} : {}
|
|
4875
|
+
}, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
|
|
4876
|
+
_id: id,
|
|
4877
|
+
_type: WORKFLOW_INSTANCE_TYPE,
|
|
4878
|
+
_rev: "",
|
|
4879
|
+
_createdAt: now,
|
|
4880
|
+
_updatedAt: now,
|
|
4881
|
+
tag: args.tag,
|
|
4882
|
+
workflowResource: args.workflowResource,
|
|
4883
|
+
definition: args.definitionName,
|
|
4884
|
+
pinnedVersion: args.pinnedVersion,
|
|
4885
|
+
...args.pinnedContentHash !== void 0 ? {
|
|
4886
|
+
pinnedContentHash: args.pinnedContentHash
|
|
4887
|
+
} : {},
|
|
4888
|
+
definitionSnapshot: JSON.stringify(args.definition),
|
|
4889
|
+
fields: args.fields,
|
|
4890
|
+
context: args.context,
|
|
4891
|
+
ancestors: args.ancestors,
|
|
4892
|
+
...perspective !== void 0 ? {
|
|
4893
|
+
perspective: perspective
|
|
4894
|
+
} : {},
|
|
4895
|
+
currentStage: args.initialStage,
|
|
4896
|
+
stages: [],
|
|
4897
|
+
subworkflows: [],
|
|
4898
|
+
pendingEffects: [],
|
|
4899
|
+
effectHistory: [],
|
|
4900
|
+
history: history,
|
|
4901
|
+
startedAt: now,
|
|
4902
|
+
lastChangedAt: now
|
|
4903
|
+
};
|
|
4904
|
+
return {
|
|
4905
|
+
...body,
|
|
4906
|
+
...modelStampFor({
|
|
4907
|
+
documentType: "instance",
|
|
4908
|
+
document: body
|
|
4909
|
+
})
|
|
4910
|
+
};
|
|
4911
|
+
}
|
|
4912
|
+
|
|
4913
|
+
async function hydrateSnapshot(args) {
|
|
4914
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
|
|
4915
|
+
loaded.push({
|
|
4916
|
+
doc: instance,
|
|
4917
|
+
resource: instance.workflowResource
|
|
4918
|
+
}), visited.add(selfGdr(instance));
|
|
4919
|
+
const {pending: pending, ordered: ordered} = planReads({
|
|
4920
|
+
client: client,
|
|
4921
|
+
clientForGdr: clientForGdr,
|
|
4922
|
+
instance: instance,
|
|
4923
|
+
overlay: overlay,
|
|
4924
|
+
visited: visited
|
|
4925
|
+
}), fetched = await readPending(pending);
|
|
4926
|
+
for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
|
|
4927
|
+
const doc = fetched.get(entry);
|
|
4928
|
+
doc !== void 0 && loaded.push({
|
|
4929
|
+
doc: doc,
|
|
4930
|
+
resource: entry.resource
|
|
4931
|
+
});
|
|
4932
|
+
}
|
|
4933
|
+
return buildSnapshot({
|
|
4934
|
+
docs: loaded
|
|
4935
|
+
});
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
function planReads(args) {
|
|
4939
|
+
const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay, visited: visited} = args, pending = [], ordered = [];
|
|
4940
|
+
for (const ref of collectWatchRefs(instance)) {
|
|
4941
|
+
if (visited.has(ref.id)) continue;
|
|
4942
|
+
visited.add(ref.id);
|
|
4943
|
+
const held = overlay?.get(ref.id);
|
|
4944
|
+
if (held !== void 0) ordered.push(held); else {
|
|
4945
|
+
const read = routeRead({
|
|
4946
|
+
defaultClient: client,
|
|
4947
|
+
clientForGdr: clientForGdr,
|
|
4948
|
+
defaultResource: instance.workflowResource,
|
|
4949
|
+
uri: ref.id,
|
|
4950
|
+
perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
|
|
4951
|
+
});
|
|
4952
|
+
pending.push(read), ordered.push(read);
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
return {
|
|
4956
|
+
pending: pending,
|
|
4957
|
+
ordered: ordered
|
|
4958
|
+
};
|
|
4959
|
+
}
|
|
4960
|
+
|
|
4961
|
+
function isPendingRead(entry) {
|
|
4962
|
+
return "client" in entry;
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
const SNAPSHOT_READ_BATCH_SIZE = 100, SNAPSHOT_READ_CONCURRENCY = 4, snapshotDocsQuery = "*[_id in $ids]";
|
|
4966
|
+
|
|
4967
|
+
function routeRead({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
|
|
4968
|
+
const parsed = tryParseGdr(uri);
|
|
4969
|
+
return parsed === void 0 ? {
|
|
4970
|
+
client: defaultClient,
|
|
4971
|
+
id: uri,
|
|
4972
|
+
perspective: perspective,
|
|
4973
|
+
resource: defaultResource
|
|
4974
|
+
} : {
|
|
4975
|
+
client: clientForGdr(parsed),
|
|
4976
|
+
id: parsed.documentId,
|
|
4977
|
+
perspective: perspective,
|
|
4978
|
+
resource: resourceFromParsed(parsed)
|
|
4979
|
+
};
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
async function readPending(reads) {
|
|
4983
|
+
const batches = groupReads(reads).flatMap(group => chunks(group.reads, SNAPSHOT_READ_BATCH_SIZE).map(batch => ({
|
|
4984
|
+
group: group,
|
|
4985
|
+
batch: batch
|
|
4986
|
+
}))), results = [];
|
|
4987
|
+
for (const wave of chunks(batches, SNAPSHOT_READ_CONCURRENCY)) results.push(...await Promise.all(wave.map(readBatch)));
|
|
4988
|
+
return new Map(results.flat());
|
|
4989
|
+
}
|
|
4990
|
+
|
|
4991
|
+
async function readBatch(args) {
|
|
4992
|
+
const {group: group, batch: batch} = args, ids = batch.map(read => read.id), docs = await group.client.fetch(snapshotDocsQuery, {
|
|
4993
|
+
ids: ids
|
|
4994
|
+
}, {
|
|
4995
|
+
perspective: group.perspective
|
|
4996
|
+
}), byId = new Map(docs.map(doc => [ doc._id, validateRawDoc(doc, group.perspective) ]));
|
|
4997
|
+
return batch.flatMap(read => {
|
|
4998
|
+
const doc = byId.get(read.id);
|
|
4999
|
+
return doc === void 0 ? [] : [ [ read, doc ] ];
|
|
5000
|
+
});
|
|
5001
|
+
}
|
|
5002
|
+
|
|
5003
|
+
function validateRawDoc(doc, perspective) {
|
|
5004
|
+
return perspective !== "raw" ? doc : doc._type === WORKFLOW_INSTANCE_TYPE ? readInstanceDoc(doc) : assertReadableModel(doc);
|
|
5005
|
+
}
|
|
5006
|
+
|
|
5007
|
+
function groupReads(reads) {
|
|
5008
|
+
const byClient = /* @__PURE__ */ new Map;
|
|
5009
|
+
for (const read of reads) {
|
|
5010
|
+
let clientGroups = byClient.get(read.client);
|
|
5011
|
+
clientGroups === void 0 && (clientGroups = /* @__PURE__ */ new Map, byClient.set(read.client, clientGroups));
|
|
5012
|
+
const key = JSON.stringify(read.perspective);
|
|
5013
|
+
let group = clientGroups.get(key);
|
|
5014
|
+
group === void 0 && (group = {
|
|
5015
|
+
client: read.client,
|
|
5016
|
+
perspective: read.perspective,
|
|
5017
|
+
reads: []
|
|
5018
|
+
}, clientGroups.set(key, group)), group.reads.push(read);
|
|
5019
|
+
}
|
|
5020
|
+
return [ ...byClient.values() ].flatMap(groups => [ ...groups.values() ]);
|
|
5021
|
+
}
|
|
5022
|
+
|
|
5023
|
+
function chunks(values, size) {
|
|
5024
|
+
return Array.from({
|
|
5025
|
+
length: Math.ceil(values.length / size)
|
|
5026
|
+
}, (_, index) => values.slice(index * size, (index + 1) * size));
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
function collectEntryDocUris(resolvedFieldEntries) {
|
|
5030
|
+
return entryDocRefs(resolvedFieldEntries).map(ref => ref.id);
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
function isEngineContext(ctx) {
|
|
5034
|
+
return "client" in ctx;
|
|
5035
|
+
}
|
|
5036
|
+
|
|
5037
|
+
function loadCallContext({client: client, instanceId: instanceId, options: options}) {
|
|
5038
|
+
return loadContext({
|
|
5039
|
+
client: client,
|
|
5040
|
+
instanceId: instanceId,
|
|
5041
|
+
options: {
|
|
5042
|
+
clientForGdr: options.clientForGdr,
|
|
5043
|
+
refSurface: options.refSurface,
|
|
5044
|
+
...options.actor ? {
|
|
5045
|
+
actor: options.actor
|
|
5046
|
+
} : {},
|
|
5047
|
+
...options.clock ? {
|
|
5048
|
+
clock: options.clock
|
|
5049
|
+
} : {},
|
|
5050
|
+
...options.executionContext ? {
|
|
5051
|
+
executionContext: options.executionContext
|
|
5052
|
+
} : {},
|
|
5053
|
+
...options.telemetry ? {
|
|
5054
|
+
telemetry: options.telemetry
|
|
5055
|
+
} : {}
|
|
5056
|
+
}
|
|
5057
|
+
});
|
|
5058
|
+
}
|
|
5059
|
+
|
|
5060
|
+
async function retryOnRevisionConflict(args) {
|
|
5061
|
+
const {client: client, instanceId: instanceId, options: options, commit: commit, onExhausted: onExhausted} = args;
|
|
5062
|
+
for (let attempt = 1; attempt <= CONCURRENT_COMMIT_MAX_ATTEMPTS; attempt++) {
|
|
5063
|
+
const ctx = await loadCallContext({
|
|
5064
|
+
client: client,
|
|
5065
|
+
instanceId: instanceId,
|
|
5066
|
+
options: options
|
|
4564
5067
|
});
|
|
4565
5068
|
try {
|
|
4566
5069
|
return await commit(ctx);
|
|
@@ -4576,29 +5079,31 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
|
|
|
4576
5079
|
if (!instance) throw new InstanceNotFoundError({
|
|
4577
5080
|
instanceId: instanceId
|
|
4578
5081
|
});
|
|
4579
|
-
|
|
5082
|
+
return buildEngineContext({
|
|
4580
5083
|
client: client,
|
|
4581
|
-
clientForGdr: clientForGdr,
|
|
5084
|
+
clientForGdr: options.clientForGdr,
|
|
5085
|
+
refSurface: options.refSurface,
|
|
4582
5086
|
instance: instance,
|
|
5087
|
+
definition: parseDefinitionSnapshot(instance),
|
|
5088
|
+
...options.actor !== void 0 ? {
|
|
5089
|
+
actor: options.actor
|
|
5090
|
+
} : {},
|
|
5091
|
+
...options.clock !== void 0 ? {
|
|
5092
|
+
clock: options.clock
|
|
5093
|
+
} : {},
|
|
5094
|
+
...options.executionContext !== void 0 ? {
|
|
5095
|
+
executionContext: options.executionContext
|
|
5096
|
+
} : {},
|
|
5097
|
+
...options.telemetry !== void 0 ? {
|
|
5098
|
+
telemetry: options.telemetry
|
|
5099
|
+
} : {},
|
|
4583
5100
|
...options.overlay !== void 0 ? {
|
|
4584
5101
|
overlay: options.overlay
|
|
5102
|
+
} : {},
|
|
5103
|
+
...options.settlingCohorts !== void 0 ? {
|
|
5104
|
+
settlingCohorts: options.settlingCohorts
|
|
4585
5105
|
} : {}
|
|
4586
5106
|
});
|
|
4587
|
-
return {
|
|
4588
|
-
client: client,
|
|
4589
|
-
clientForGdr: clientForGdr,
|
|
4590
|
-
refSurface: refSurface,
|
|
4591
|
-
clock: clock,
|
|
4592
|
-
now: clock(),
|
|
4593
|
-
executionContext: resolveExecutionContext(options?.executionContext),
|
|
4594
|
-
telemetry: resolveTelemetry(options.telemetry),
|
|
4595
|
-
...options?.actor !== void 0 ? {
|
|
4596
|
-
actor: options.actor
|
|
4597
|
-
} : {},
|
|
4598
|
-
instance: instance,
|
|
4599
|
-
definition: definition,
|
|
4600
|
-
snapshot: snapshot
|
|
4601
|
-
};
|
|
4602
5107
|
}
|
|
4603
5108
|
|
|
4604
5109
|
async function ctxConditionParams(ctx, opts) {
|
|
@@ -4636,6 +5141,9 @@ async function buildEngineContext(args) {
|
|
|
4636
5141
|
now: clock(),
|
|
4637
5142
|
executionContext: resolveExecutionContext(args.executionContext),
|
|
4638
5143
|
telemetry: resolveTelemetry(args.telemetry),
|
|
5144
|
+
...args.settlingCohorts !== void 0 ? {
|
|
5145
|
+
settlingCohorts: args.settlingCohorts
|
|
5146
|
+
} : {},
|
|
4639
5147
|
...args.actor !== void 0 ? {
|
|
4640
5148
|
actor: args.actor
|
|
4641
5149
|
} : {},
|
|
@@ -4644,7 +5152,10 @@ async function buildEngineContext(args) {
|
|
|
4644
5152
|
snapshot: await hydrateSnapshot({
|
|
4645
5153
|
client: client,
|
|
4646
5154
|
clientForGdr: clientForGdr,
|
|
4647
|
-
instance: instance
|
|
5155
|
+
instance: instance,
|
|
5156
|
+
...args.overlay !== void 0 ? {
|
|
5157
|
+
overlay: args.overlay
|
|
5158
|
+
} : {}
|
|
4648
5159
|
})
|
|
4649
5160
|
};
|
|
4650
5161
|
}
|
|
@@ -4767,10 +5278,6 @@ function recordProcessedRequest({mutation: mutation, record: record, now: now})
|
|
|
4767
5278
|
} ];
|
|
4768
5279
|
}
|
|
4769
5280
|
|
|
4770
|
-
const SYNC_COMMIT = {
|
|
4771
|
-
visibility: "sync"
|
|
4772
|
-
}, ENGINE_API_VERSION = "2026-04-29";
|
|
4773
|
-
|
|
4774
5281
|
function resolveGuardRead(args) {
|
|
4775
5282
|
const {expr: expr, ctx: ctx, deref: deref} = args;
|
|
4776
5283
|
if (expr === "$self") return selfGdr(ctx.instance);
|
|
@@ -4793,63 +5300,342 @@ function resolveGuardRead(args) {
|
|
|
4793
5300
|
throw new Error(`Guard read "${expr}" is not a supported deploy-time value — use "$self", "$now", "$fields.<name>[.path]", or "$effects['<name>'][.path]" (guards store resolved values; the lake cannot see $fields or $effects)`);
|
|
4794
5301
|
}
|
|
4795
5302
|
|
|
4796
|
-
function resolveIdRefTarget(expr, ctx) {
|
|
4797
|
-
const value = resolveGuardRead({
|
|
4798
|
-
expr: expr,
|
|
4799
|
-
ctx: ctx,
|
|
4800
|
-
deref: !1
|
|
4801
|
-
});
|
|
4802
|
-
if (typeof value == "string" && isGdrUri(value)) return {
|
|
4803
|
-
parsed: parseGdr(value)
|
|
4804
|
-
};
|
|
4805
|
-
if (value && typeof value == "object") {
|
|
4806
|
-
const v2 = value;
|
|
4807
|
-
if (typeof v2.id == "string" && isGdrUri(v2.id)) return typeof v2.type == "string" ? {
|
|
4808
|
-
parsed: parseGdr(v2.id),
|
|
4809
|
-
type: v2.type
|
|
4810
|
-
} : {
|
|
4811
|
-
parsed: parseGdr(v2.id)
|
|
4812
|
-
};
|
|
5303
|
+
function resolveIdRefTarget(expr, ctx) {
|
|
5304
|
+
const value = resolveGuardRead({
|
|
5305
|
+
expr: expr,
|
|
5306
|
+
ctx: ctx,
|
|
5307
|
+
deref: !1
|
|
5308
|
+
});
|
|
5309
|
+
if (typeof value == "string" && isGdrUri(value)) return {
|
|
5310
|
+
parsed: parseGdr(value)
|
|
5311
|
+
};
|
|
5312
|
+
if (value && typeof value == "object") {
|
|
5313
|
+
const v2 = value;
|
|
5314
|
+
if (typeof v2.id == "string" && isGdrUri(v2.id)) return typeof v2.type == "string" ? {
|
|
5315
|
+
parsed: parseGdr(v2.id),
|
|
5316
|
+
type: v2.type
|
|
5317
|
+
} : {
|
|
5318
|
+
parsed: parseGdr(v2.id)
|
|
5319
|
+
};
|
|
5320
|
+
}
|
|
5321
|
+
return null;
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5324
|
+
function resolveIdRefTargets(idRefs, ctx) {
|
|
5325
|
+
const targets = [];
|
|
5326
|
+
for (const expr of idRefs ?? []) {
|
|
5327
|
+
const target = resolveIdRefTarget(expr, ctx);
|
|
5328
|
+
if (target === null) return null;
|
|
5329
|
+
targets.push(target);
|
|
5330
|
+
}
|
|
5331
|
+
return targets.length === 0 ? null : targets;
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
function assertSingleResource(targets) {
|
|
5335
|
+
const resource = resourceFromParsed(targets[0].parsed);
|
|
5336
|
+
for (const g of targets) {
|
|
5337
|
+
const r = resourceFromParsed(g.parsed);
|
|
5338
|
+
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.`);
|
|
5339
|
+
}
|
|
5340
|
+
return resource;
|
|
5341
|
+
}
|
|
5342
|
+
|
|
5343
|
+
function bareIdRefs(targets) {
|
|
5344
|
+
return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
|
|
5345
|
+
}
|
|
5346
|
+
|
|
5347
|
+
function resolveMatchTypes(targets, authorTypes) {
|
|
5348
|
+
if (authorTypes !== void 0) return authorTypes;
|
|
5349
|
+
const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
|
|
5350
|
+
return inferred.length > 0 ? inferred : void 0;
|
|
5351
|
+
}
|
|
5352
|
+
|
|
5353
|
+
function resolveMetadata(metadata, ctx) {
|
|
5354
|
+
const out = {};
|
|
5355
|
+
for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
|
|
5356
|
+
expr: expr,
|
|
5357
|
+
ctx: ctx,
|
|
5358
|
+
deref: !0
|
|
5359
|
+
});
|
|
5360
|
+
return out;
|
|
5361
|
+
}
|
|
5362
|
+
|
|
5363
|
+
function isRecord(value) {
|
|
5364
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
5365
|
+
}
|
|
5366
|
+
|
|
5367
|
+
function isClientProjectUser(value) {
|
|
5368
|
+
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");
|
|
5369
|
+
}
|
|
5370
|
+
|
|
5371
|
+
function objectProperty(value, property) {
|
|
5372
|
+
if (!isRecord(value)) return;
|
|
5373
|
+
const propertyValue = value[property];
|
|
5374
|
+
return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
function stringProperty(value, property) {
|
|
5378
|
+
const propertyValue = Reflect.get(value, property);
|
|
5379
|
+
return typeof propertyValue == "string" ? propertyValue : void 0;
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
function apiErrorType(error) {
|
|
5383
|
+
const response = objectProperty(error, "response"), body = objectProperty(response, "body");
|
|
5384
|
+
if (!body) return;
|
|
5385
|
+
const nestedError = objectProperty(body, "error");
|
|
5386
|
+
return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
|
|
5387
|
+
}
|
|
5388
|
+
|
|
5389
|
+
function isProjectUserNotFoundError(error) {
|
|
5390
|
+
return apiErrorType(error) === "projectUserNotFoundError";
|
|
5391
|
+
}
|
|
5392
|
+
|
|
5393
|
+
const memberJoinCache = /* @__PURE__ */ new WeakMap;
|
|
5394
|
+
|
|
5395
|
+
function joinCacheFor(client) {
|
|
5396
|
+
let cache = memberJoinCache.get(client);
|
|
5397
|
+
return cache === void 0 && (cache = /* @__PURE__ */ new Map, memberJoinCache.set(client, cache)),
|
|
5398
|
+
cache;
|
|
5399
|
+
}
|
|
5400
|
+
|
|
5401
|
+
async function projectMemberIds(request, projectId) {
|
|
5402
|
+
const project = await request({
|
|
5403
|
+
uri: `/projects/${encodeURIComponent(projectId)}`
|
|
5404
|
+
}), members = isRecord(project) ? project.members : void 0;
|
|
5405
|
+
return Array.isArray(members) ? members.map(member => isRecord(member) ? member.id : void 0).filter(id => typeof id == "string") : [];
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
async function resolveGlobalProjectUser(args) {
|
|
5409
|
+
const {client: client, request: request, projectId: projectId, id: id} = args, cache = joinCacheFor(client), key = `${projectId}:${id}`, hit = cache.get(key);
|
|
5410
|
+
if (hit !== void 0) return hit === null ? {
|
|
5411
|
+
status: "missing"
|
|
5412
|
+
} : {
|
|
5413
|
+
status: "resolved",
|
|
5414
|
+
user: hit
|
|
5415
|
+
};
|
|
5416
|
+
try {
|
|
5417
|
+
await ingestMemberJoin({
|
|
5418
|
+
request: request,
|
|
5419
|
+
projectId: projectId,
|
|
5420
|
+
cache: cache
|
|
5421
|
+
});
|
|
5422
|
+
const found = cache.get(key);
|
|
5423
|
+
return found != null ? {
|
|
5424
|
+
status: "resolved",
|
|
5425
|
+
user: found
|
|
5426
|
+
} : (cache.set(key, null), {
|
|
5427
|
+
status: "missing"
|
|
5428
|
+
});
|
|
5429
|
+
} catch (cause) {
|
|
5430
|
+
return {
|
|
5431
|
+
status: "inaccessible",
|
|
5432
|
+
cause: cause
|
|
5433
|
+
};
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
|
|
5437
|
+
async function ingestMemberJoin(args) {
|
|
5438
|
+
const {request: request, projectId: projectId, cache: cache} = args, memberIds = await projectMemberIds(request, projectId);
|
|
5439
|
+
if (memberIds.length === 0) return;
|
|
5440
|
+
const response = await request({
|
|
5441
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
|
|
5442
|
+
});
|
|
5443
|
+
for (const row of Array.isArray(response) ? response : [ response ]) isClientProjectUser(row) && typeof row.sanityUserId == "string" && cache.set(`${projectId}:${row.sanityUserId}`, row);
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
function clientProjectUserDirectory(client, projectId) {
|
|
5447
|
+
return {
|
|
5448
|
+
findById: async id => {
|
|
5449
|
+
if (!client.request) return {
|
|
5450
|
+
status: "inaccessible",
|
|
5451
|
+
cause: new Error("Project-user resolution requires WorkflowClient.request")
|
|
5452
|
+
};
|
|
5453
|
+
if (classifyPrincipalId(id).namespace === "global") return resolveGlobalProjectUser({
|
|
5454
|
+
client: client,
|
|
5455
|
+
request: client.request,
|
|
5456
|
+
projectId: projectId,
|
|
5457
|
+
id: id
|
|
5458
|
+
});
|
|
5459
|
+
try {
|
|
5460
|
+
const response = await client.request({
|
|
5461
|
+
uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
|
|
5462
|
+
}), candidate = Array.isArray(response) ? response[0] : response;
|
|
5463
|
+
return candidate == null ? {
|
|
5464
|
+
status: "missing"
|
|
5465
|
+
} : isClientProjectUser(candidate) ? {
|
|
5466
|
+
status: "resolved",
|
|
5467
|
+
user: candidate
|
|
5468
|
+
} : {
|
|
5469
|
+
status: "inaccessible",
|
|
5470
|
+
cause: new Error("Project-user response had an invalid shape")
|
|
5471
|
+
};
|
|
5472
|
+
} catch (cause) {
|
|
5473
|
+
return isProjectUserNotFoundError(cause) ? {
|
|
5474
|
+
status: "missing"
|
|
5475
|
+
} : {
|
|
5476
|
+
status: "inaccessible",
|
|
5477
|
+
cause: cause
|
|
5478
|
+
};
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
};
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
function resolveClientActor(client, args) {
|
|
5485
|
+
return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
|
|
5486
|
+
}
|
|
5487
|
+
|
|
5488
|
+
async function resolveActor(directory, actor) {
|
|
5489
|
+
if (actor.kind !== "person") return {
|
|
5490
|
+
status: "not-person",
|
|
5491
|
+
actor: actor
|
|
5492
|
+
};
|
|
5493
|
+
const personActor = {
|
|
5494
|
+
...actor,
|
|
5495
|
+
kind: "person"
|
|
5496
|
+
}, lookup = await directory.findById(personActor.id);
|
|
5497
|
+
return lookup.status === "resolved" ? {
|
|
5498
|
+
status: "resolved",
|
|
5499
|
+
actor: personActor,
|
|
5500
|
+
user: lookup.user
|
|
5501
|
+
} : lookup.status === "inaccessible" ? {
|
|
5502
|
+
status: "inaccessible",
|
|
5503
|
+
actor: personActor,
|
|
5504
|
+
...lookup.cause === void 0 ? {} : {
|
|
5505
|
+
cause: lookup.cause
|
|
5506
|
+
}
|
|
5507
|
+
} : {
|
|
5508
|
+
status: "missing",
|
|
5509
|
+
actor: personActor
|
|
5510
|
+
};
|
|
5511
|
+
}
|
|
5512
|
+
|
|
5513
|
+
const IDENTITY_KINDS = /* @__PURE__ */ new Set([ "actor", "assignee", "assignees" ]);
|
|
5514
|
+
|
|
5515
|
+
async function localizeGuardMetadata(args) {
|
|
5516
|
+
const {doc: doc, guard: guard, client: client, instance: instance, definition: definition} = args;
|
|
5517
|
+
if (doc.resourceType !== "dataset" || client.request === void 0) return doc;
|
|
5518
|
+
const request = client.request, {projectId: projectId} = datasetResourceParts(doc.resourceId), shapes = metadataShapes({
|
|
5519
|
+
guard: guard,
|
|
5520
|
+
instance: instance,
|
|
5521
|
+
definition: definition
|
|
5522
|
+
}), globals = collectMetadataGlobals({
|
|
5523
|
+
metadata: doc.metadata,
|
|
5524
|
+
shapes: shapes
|
|
5525
|
+
});
|
|
5526
|
+
if (globals.size === 0) return doc;
|
|
5527
|
+
const map = /* @__PURE__ */ new Map;
|
|
5528
|
+
for (const id of globals) {
|
|
5529
|
+
const lookup = await resolveGlobalProjectUser({
|
|
5530
|
+
client: client,
|
|
5531
|
+
request: request,
|
|
5532
|
+
projectId: projectId,
|
|
5533
|
+
id: id
|
|
5534
|
+
});
|
|
5535
|
+
lookup.status === "resolved" && map.set(id, lookup.user.id);
|
|
4813
5536
|
}
|
|
4814
|
-
return
|
|
5537
|
+
return map.size === 0 ? doc : {
|
|
5538
|
+
...doc,
|
|
5539
|
+
metadata: rewriteMetadata({
|
|
5540
|
+
metadata: doc.metadata,
|
|
5541
|
+
shapes: shapes,
|
|
5542
|
+
map: map
|
|
5543
|
+
})
|
|
5544
|
+
};
|
|
4815
5545
|
}
|
|
4816
5546
|
|
|
4817
|
-
function
|
|
4818
|
-
const
|
|
4819
|
-
for (const expr of
|
|
4820
|
-
const
|
|
4821
|
-
|
|
4822
|
-
|
|
5547
|
+
function metadataShapes(args) {
|
|
5548
|
+
const out = /* @__PURE__ */ new Map;
|
|
5549
|
+
for (const [key, expr] of Object.entries(args.guard.metadata ?? {})) {
|
|
5550
|
+
const shape = shapeOfRead({
|
|
5551
|
+
expr: expr,
|
|
5552
|
+
instance: args.instance,
|
|
5553
|
+
definition: args.definition
|
|
5554
|
+
});
|
|
5555
|
+
shape !== void 0 && out.set(key, shape);
|
|
4823
5556
|
}
|
|
4824
|
-
return
|
|
5557
|
+
return out;
|
|
4825
5558
|
}
|
|
4826
5559
|
|
|
4827
|
-
function
|
|
4828
|
-
const
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
}
|
|
4833
|
-
return resource;
|
|
5560
|
+
function shapeOfRead(args) {
|
|
5561
|
+
const fieldRead = FIELD_READ.exec(args.expr);
|
|
5562
|
+
if (fieldRead !== null) return shapeOfFieldRead(args.instance, fieldRead);
|
|
5563
|
+
const effectsRead = EFFECTS_READ.exec(args.expr);
|
|
5564
|
+
if (effectsRead !== null) return shapeOfEffectsRead(args.definition, effectsRead);
|
|
4834
5565
|
}
|
|
4835
5566
|
|
|
4836
|
-
function
|
|
4837
|
-
|
|
5567
|
+
function shapeOfFieldRead(instance, fieldRead) {
|
|
5568
|
+
const entry = (instance.fields ?? []).find(s => s.name === fieldRead[1]);
|
|
5569
|
+
if (entry !== void 0) return narrowByPath({
|
|
5570
|
+
type: entry._type,
|
|
5571
|
+
fields: Reflect.get(entry, "fields"),
|
|
5572
|
+
of: Reflect.get(entry, "of")
|
|
5573
|
+
}, fieldRead[2]);
|
|
4838
5574
|
}
|
|
4839
5575
|
|
|
4840
|
-
function
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
5576
|
+
function shapeOfEffectsRead(definition, effectsRead) {
|
|
5577
|
+
const outputs = findEffect(definition, effectsRead[1])?.outputs ?? [], path = effectsRead[2];
|
|
5578
|
+
if (path === void 0) return;
|
|
5579
|
+
const [head, ...rest] = path.split("."), output = outputs.find(shape => shape.name === head);
|
|
5580
|
+
if (output !== void 0) return narrowByPath({
|
|
5581
|
+
type: output.type,
|
|
5582
|
+
fields: output.fields,
|
|
5583
|
+
of: output.of
|
|
5584
|
+
}, rest.length > 0 ? rest.join(".") : void 0);
|
|
4844
5585
|
}
|
|
4845
5586
|
|
|
4846
|
-
function
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
5587
|
+
function narrowByPath(shape, path) {
|
|
5588
|
+
if (path === void 0) return shape;
|
|
5589
|
+
if (typeof shape.type != "string" || !IDENTITY_KINDS.has(shape.type)) return;
|
|
5590
|
+
const steps = identityPathSteps(shape.type, path);
|
|
5591
|
+
if (steps === void 0) return;
|
|
5592
|
+
const itemType = shape.type === "assignees" ? "assignee" : shape.type;
|
|
5593
|
+
if (steps.length === 0) return {
|
|
5594
|
+
type: itemType
|
|
5595
|
+
};
|
|
5596
|
+
if (steps.length === 1 && steps[0] === "id") return {
|
|
5597
|
+
type: itemType,
|
|
5598
|
+
idLeaf: !0
|
|
5599
|
+
};
|
|
5600
|
+
}
|
|
5601
|
+
|
|
5602
|
+
function identityPathSteps(kind, path) {
|
|
5603
|
+
const segments = path.split(".");
|
|
5604
|
+
return kind !== "assignees" ? segments : /^\d+$/.test(segments[0] ?? "") ? segments.slice(1) : void 0;
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5607
|
+
function collectMetadataGlobals(args) {
|
|
5608
|
+
const found = /* @__PURE__ */ new Set;
|
|
5609
|
+
for (const [key, shape] of args.shapes) {
|
|
5610
|
+
const value = args.metadata[key];
|
|
5611
|
+
if (shape.idLeaf === !0) {
|
|
5612
|
+
typeof value == "string" && classifyPrincipalId(value).namespace === "global" && found.add(value);
|
|
5613
|
+
continue;
|
|
5614
|
+
}
|
|
5615
|
+
for (const id of collectDeclaredGlobalIds({
|
|
5616
|
+
...shape,
|
|
5617
|
+
value: value
|
|
5618
|
+
})) found.add(id);
|
|
5619
|
+
}
|
|
5620
|
+
return found;
|
|
5621
|
+
}
|
|
5622
|
+
|
|
5623
|
+
function rewriteMetadata(args) {
|
|
5624
|
+
const out = {
|
|
5625
|
+
...args.metadata
|
|
5626
|
+
};
|
|
5627
|
+
for (const [key, shape] of args.shapes) {
|
|
5628
|
+
const value = out[key];
|
|
5629
|
+
if (shape.idLeaf === !0) {
|
|
5630
|
+
typeof value == "string" && (out[key] = args.map.get(value) ?? value);
|
|
5631
|
+
continue;
|
|
5632
|
+
}
|
|
5633
|
+
out[key] = rewriteDeclaredPrincipalIds({
|
|
5634
|
+
...shape,
|
|
5635
|
+
value: value,
|
|
5636
|
+
map: args.map
|
|
5637
|
+
});
|
|
5638
|
+
}
|
|
4853
5639
|
return out;
|
|
4854
5640
|
}
|
|
4855
5641
|
|
|
@@ -4885,151 +5671,6 @@ function parseGuardDocument(doc) {
|
|
|
4885
5671
|
});
|
|
4886
5672
|
}
|
|
4887
5673
|
|
|
4888
|
-
const REQUEST_TAG = {
|
|
4889
|
-
engine: "workflow",
|
|
4890
|
-
deploy: "workflow.deploy",
|
|
4891
|
-
deleteDefinition: "workflow.delete-definition",
|
|
4892
|
-
start: "workflow.start",
|
|
4893
|
-
fireAction: "workflow.fire-action",
|
|
4894
|
-
editField: "workflow.edit-field",
|
|
4895
|
-
completeEffect: "workflow.complete-effect",
|
|
4896
|
-
commitEffectOps: "workflow.commit-effect-ops",
|
|
4897
|
-
tick: "workflow.tick",
|
|
4898
|
-
evaluate: "workflow.evaluate",
|
|
4899
|
-
evaluateStart: "workflow.evaluate-start",
|
|
4900
|
-
diagnose: "workflow.diagnose",
|
|
4901
|
-
availableActions: "workflow.available-actions",
|
|
4902
|
-
setStage: "workflow.set-stage",
|
|
4903
|
-
abort: "workflow.abort",
|
|
4904
|
-
getInstance: "workflow.get-instance",
|
|
4905
|
-
children: "workflow.children",
|
|
4906
|
-
instancesForDocument: "workflow.instances-for-document",
|
|
4907
|
-
definitionsForDocument: "workflow.definitions-for-document",
|
|
4908
|
-
query: "workflow.query",
|
|
4909
|
-
discover: "workflow.discover",
|
|
4910
|
-
guardQuery: "workflow.guard.query",
|
|
4911
|
-
guardDeploy: "workflow.guard.deploy",
|
|
4912
|
-
guardRefresh: "workflow.guard.refresh",
|
|
4913
|
-
guardRetract: "workflow.guard.retract",
|
|
4914
|
-
effectList: "workflow.effect.list",
|
|
4915
|
-
effectFind: "workflow.effect.find",
|
|
4916
|
-
drain: "workflow.drain",
|
|
4917
|
-
effect: "workflow.effect",
|
|
4918
|
-
verifyDefinitions: "workflow.verify-definitions",
|
|
4919
|
-
accessResolveActor: "workflow.access.resolve-actor",
|
|
4920
|
-
accessGrants: "workflow.access.grants"
|
|
4921
|
-
}, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
|
|
4922
|
-
|
|
4923
|
-
function unwrapPatch(patch) {
|
|
4924
|
-
return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
|
|
4925
|
-
}
|
|
4926
|
-
|
|
4927
|
-
const wrapperCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
|
|
4928
|
-
|
|
4929
|
-
function unwrapRequestTag(client) {
|
|
4930
|
-
let current = client;
|
|
4931
|
-
for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
|
|
4932
|
-
return current;
|
|
4933
|
-
}
|
|
4934
|
-
|
|
4935
|
-
function withRequestTag(client, fallback) {
|
|
4936
|
-
let byTag = wrapperCache.get(client);
|
|
4937
|
-
byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
|
|
4938
|
-
const cached = byTag.get(fallback);
|
|
4939
|
-
if (cached !== void 0) return cached;
|
|
4940
|
-
const wrapped = buildTaggedClient(client, fallback);
|
|
4941
|
-
return byTag.set(fallback, wrapped), wrapped;
|
|
4942
|
-
}
|
|
4943
|
-
|
|
4944
|
-
function isWorkflowsFamilyPrefix(prefix) {
|
|
4945
|
-
return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
|
|
4946
|
-
}
|
|
4947
|
-
|
|
4948
|
-
function clientRequestTagPrefix(client) {
|
|
4949
|
-
const probe = client;
|
|
4950
|
-
return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
|
|
4951
|
-
}
|
|
4952
|
-
|
|
4953
|
-
function buildTaggedClient(client, fallback) {
|
|
4954
|
-
const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip && tag.startsWith("workflow.") ? tag.slice(9) : tag, stamp = options => options === void 0 ? {
|
|
4955
|
-
tag: normalize(fallback)
|
|
4956
|
-
} : options.tag === void 0 ? {
|
|
4957
|
-
...options,
|
|
4958
|
-
tag: normalize(fallback)
|
|
4959
|
-
} : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
|
|
4960
|
-
...options,
|
|
4961
|
-
tag: normalize(options.tag)
|
|
4962
|
-
} : options, wrapPatch = patch => {
|
|
4963
|
-
let target = patch;
|
|
4964
|
-
const wrapped = {
|
|
4965
|
-
get [RAW_PATCH]() {
|
|
4966
|
-
return target;
|
|
4967
|
-
},
|
|
4968
|
-
set: props => (target = target.set(props), wrapped),
|
|
4969
|
-
setIfMissing: props => (target = target.setIfMissing(props), wrapped),
|
|
4970
|
-
unset: paths => (target = target.unset(paths), wrapped),
|
|
4971
|
-
ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
|
|
4972
|
-
commit: options => target.commit(stamp(options))
|
|
4973
|
-
};
|
|
4974
|
-
return wrapped;
|
|
4975
|
-
}, wrapTransaction = tx => {
|
|
4976
|
-
let target = tx;
|
|
4977
|
-
const wrapped = {
|
|
4978
|
-
create: doc => (target = target.create(doc), wrapped),
|
|
4979
|
-
patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
|
|
4980
|
-
delete: id => (target = target.delete(id), wrapped),
|
|
4981
|
-
commit: options => target.commit(stamp(options))
|
|
4982
|
-
};
|
|
4983
|
-
return wrapped;
|
|
4984
|
-
};
|
|
4985
|
-
return {
|
|
4986
|
-
[RAW_CLIENT]: unwrapRequestTag(client),
|
|
4987
|
-
fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
|
|
4988
|
-
getDocument: (id, options) => client.getDocument(id, stamp(options)),
|
|
4989
|
-
patch: documentId => wrapPatch(client.patch(documentId)),
|
|
4990
|
-
create: (doc, options) => client.create(doc, stamp(options)),
|
|
4991
|
-
transaction: () => wrapTransaction(client.transaction()),
|
|
4992
|
-
...client.withConfig !== void 0 ? {
|
|
4993
|
-
withConfig: config => withRequestTag(client.withConfig(config), fallback)
|
|
4994
|
-
} : {},
|
|
4995
|
-
...client.action !== void 0 ? {
|
|
4996
|
-
action: (action, options) => client.action(action, stamp(options))
|
|
4997
|
-
} : {},
|
|
4998
|
-
...client.request !== void 0 ? {
|
|
4999
|
-
request: opts => client.request(stamp(opts))
|
|
5000
|
-
} : {}
|
|
5001
|
-
};
|
|
5002
|
-
}
|
|
5003
|
-
|
|
5004
|
-
const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
|
|
5005
|
-
|
|
5006
|
-
function pinApiVersion(client) {
|
|
5007
|
-
const raw = unwrapRequestTag(client);
|
|
5008
|
-
if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
|
|
5009
|
-
let sibling = pinCache.get(raw);
|
|
5010
|
-
return sibling === void 0 && (sibling = raw.withConfig({
|
|
5011
|
-
apiVersion: ENGINE_API_VERSION
|
|
5012
|
-
}), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
|
|
5013
|
-
}
|
|
5014
|
-
|
|
5015
|
-
function taggedResolver(resolver, fallback) {
|
|
5016
|
-
if (resolver !== void 0) return parsed => {
|
|
5017
|
-
const client = resolver(parsed);
|
|
5018
|
-
return client === void 0 ? void 0 : withRequestTag(pinApiVersion(client), fallback);
|
|
5019
|
-
};
|
|
5020
|
-
}
|
|
5021
|
-
|
|
5022
|
-
function taggedScope(args, tag) {
|
|
5023
|
-
const resourceClients = taggedResolver(args.resourceClients, tag);
|
|
5024
|
-
return {
|
|
5025
|
-
...args,
|
|
5026
|
-
client: withRequestTag(pinApiVersion(args.client), tag),
|
|
5027
|
-
...resourceClients !== void 0 ? {
|
|
5028
|
-
resourceClients: resourceClients
|
|
5029
|
-
} : {}
|
|
5030
|
-
};
|
|
5031
|
-
}
|
|
5032
|
-
|
|
5033
5674
|
async function fetchGuards(args) {
|
|
5034
5675
|
return (await args.client.fetch(args.query, args.params, {
|
|
5035
5676
|
tag: REQUEST_TAG.guardQuery
|
|
@@ -5046,16 +5687,20 @@ function guardsForResource(client) {
|
|
|
5046
5687
|
});
|
|
5047
5688
|
}
|
|
5048
5689
|
|
|
5049
|
-
function
|
|
5690
|
+
function instancesGuardQuery(instanceIds) {
|
|
5050
5691
|
return {
|
|
5051
|
-
query: "*[_type == $guardType && sourceInstanceId
|
|
5692
|
+
query: "*[_type == $guardType && sourceInstanceId in $instanceIds] | order(_id asc)",
|
|
5052
5693
|
params: {
|
|
5053
5694
|
guardType: GUARD_DOC_TYPE,
|
|
5054
|
-
|
|
5695
|
+
instanceIds: [ ...instanceIds ]
|
|
5055
5696
|
}
|
|
5056
5697
|
};
|
|
5057
5698
|
}
|
|
5058
5699
|
|
|
5700
|
+
function instanceGuardQuery(instanceId) {
|
|
5701
|
+
return instancesGuardQuery([ instanceId ]);
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5059
5704
|
function verdictGuardsForInstance(client, instanceId) {
|
|
5060
5705
|
const {query: query, params: params} = instanceGuardQuery(instanceId);
|
|
5061
5706
|
return fetchGuards({
|
|
@@ -5157,7 +5802,7 @@ function dedupById(guards) {
|
|
|
5157
5802
|
return [ ...new Map(guards.map(g => [ g._id, g ])).values() ].sort((a, b) => a._id.localeCompare(b._id));
|
|
5158
5803
|
}
|
|
5159
5804
|
|
|
5160
|
-
const GUARD_OWNER = "robot:workflow-engine";
|
|
5805
|
+
const GUARD_OWNER = "robot:workflow-engine", DELETE_CHUNK_SIZE = 200;
|
|
5161
5806
|
|
|
5162
5807
|
function resolveGuardRoute(guard, ctx) {
|
|
5163
5808
|
const targets = resolveIdRefTargets(guard.match.idRefs, ctx);
|
|
@@ -5210,10 +5855,9 @@ function resolveGuard({guard: guard, instance: instance, stageName: stageName, n
|
|
|
5210
5855
|
};
|
|
5211
5856
|
}
|
|
5212
5857
|
|
|
5213
|
-
async function upsertGuard(
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
})) {
|
|
5858
|
+
async function upsertGuard(args) {
|
|
5859
|
+
const {client: client, doc: doc, exists: exists} = args;
|
|
5860
|
+
if (!exists) {
|
|
5217
5861
|
await client.create(doc, {
|
|
5218
5862
|
...SYNC_COMMIT,
|
|
5219
5863
|
tag: REQUEST_TAG.guardDeploy
|
|
@@ -5239,7 +5883,9 @@ function resolvedStageGuards(args) {
|
|
|
5239
5883
|
});
|
|
5240
5884
|
resolved !== null && out.push({
|
|
5241
5885
|
client: args.clientForGdr(resolved.routeGdr),
|
|
5242
|
-
|
|
5886
|
+
resourceKey: resourceGdr(resourceFromParsed(resolved.routeGdr)),
|
|
5887
|
+
value: resolved.doc,
|
|
5888
|
+
guard: guard
|
|
5243
5889
|
});
|
|
5244
5890
|
}
|
|
5245
5891
|
return out;
|
|
@@ -5256,12 +5902,54 @@ function resolvedStageGuardRoutes(args) {
|
|
|
5256
5902
|
const route = resolveGuardRoute(guard, ctx);
|
|
5257
5903
|
route !== null && out.push({
|
|
5258
5904
|
client: args.clientForGdr(route.routeGdr),
|
|
5259
|
-
|
|
5905
|
+
resourceKey: resourceGdr(resourceFromParsed(route.routeGdr)),
|
|
5906
|
+
value: route.guardId
|
|
5260
5907
|
});
|
|
5261
5908
|
}
|
|
5262
5909
|
return out;
|
|
5263
5910
|
}
|
|
5264
5911
|
|
|
5912
|
+
function groupByResource(routed) {
|
|
5913
|
+
const groups = /* @__PURE__ */ new Map;
|
|
5914
|
+
for (const item of routed) {
|
|
5915
|
+
const existing = groups.get(item.resourceKey);
|
|
5916
|
+
if (existing !== void 0) {
|
|
5917
|
+
existing.values.push(item.value);
|
|
5918
|
+
continue;
|
|
5919
|
+
}
|
|
5920
|
+
groups.set(item.resourceKey, {
|
|
5921
|
+
client: item.client,
|
|
5922
|
+
resourceKey: item.resourceKey,
|
|
5923
|
+
values: [ item.value ]
|
|
5924
|
+
});
|
|
5925
|
+
}
|
|
5926
|
+
return [ ...groups.values() ];
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
async function existingGuardIds(groups) {
|
|
5930
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: values}) => {
|
|
5931
|
+
const ids = values.map(doc => doc._id), existing = await client.fetch("*[_id in $ids]._id", {
|
|
5932
|
+
ids: ids
|
|
5933
|
+
}, {
|
|
5934
|
+
tag: REQUEST_TAG.guardDeploy
|
|
5935
|
+
});
|
|
5936
|
+
return [ resourceKey, new Set(existing) ];
|
|
5937
|
+
}));
|
|
5938
|
+
return new Map(entries);
|
|
5939
|
+
}
|
|
5940
|
+
|
|
5941
|
+
async function observedGuards(groups) {
|
|
5942
|
+
const entries = await Promise.all(groups.map(async ({client: client, resourceKey: resourceKey, values: ids}) => {
|
|
5943
|
+
const guards = await client.fetch("*[_id in $ids]{_id, predicate, _rev}", {
|
|
5944
|
+
ids: ids
|
|
5945
|
+
}, {
|
|
5946
|
+
tag: REQUEST_TAG.guardRetract
|
|
5947
|
+
});
|
|
5948
|
+
return [ resourceKey, new Map(guards.map(guard => [ guard._id, guard ])) ];
|
|
5949
|
+
}));
|
|
5950
|
+
return new Map(entries);
|
|
5951
|
+
}
|
|
5952
|
+
|
|
5265
5953
|
async function committedInstance(args) {
|
|
5266
5954
|
return getInstanceDocument(args.client, args.instance._id);
|
|
5267
5955
|
}
|
|
@@ -5269,10 +5957,22 @@ async function committedInstance(args) {
|
|
|
5269
5957
|
async function deployStageGuards(args) {
|
|
5270
5958
|
const live = await committedInstance(args);
|
|
5271
5959
|
if (live === void 0 || live.currentStage !== args.stageName || live.abortedAt !== void 0) return;
|
|
5960
|
+
const routed = resolvedStageGuards(args), existingByResource = await existingGuardIds(groupByResource(routed));
|
|
5272
5961
|
let deployed = 0;
|
|
5273
|
-
for (const {client: client, doc:
|
|
5962
|
+
for (const {client: client, resourceKey: resourceKey, value: doc, guard: guard} of routed) {
|
|
5274
5963
|
try {
|
|
5275
|
-
await
|
|
5964
|
+
const localized = await localizeGuardMetadata({
|
|
5965
|
+
doc: doc,
|
|
5966
|
+
guard: guard,
|
|
5967
|
+
client: client,
|
|
5968
|
+
instance: args.instance,
|
|
5969
|
+
definition: args.definition
|
|
5970
|
+
});
|
|
5971
|
+
await upsertGuard({
|
|
5972
|
+
client: client,
|
|
5973
|
+
doc: localized,
|
|
5974
|
+
exists: existingByResource.get(resourceKey)?.has(doc._id) ?? !1
|
|
5975
|
+
});
|
|
5276
5976
|
} catch (cause) {
|
|
5277
5977
|
throw deployed > 0 ? new PartialGuardDeployError({
|
|
5278
5978
|
stageName: args.stageName,
|
|
@@ -5285,13 +5985,11 @@ async function deployStageGuards(args) {
|
|
|
5285
5985
|
}
|
|
5286
5986
|
|
|
5287
5987
|
async function retractStageGuards(args) {
|
|
5288
|
-
const observed = [];
|
|
5289
|
-
for (const {client: client,
|
|
5290
|
-
const guard =
|
|
5291
|
-
tag: REQUEST_TAG.guardRetract
|
|
5292
|
-
});
|
|
5988
|
+
const observed = [], routed = resolvedStageGuardRoutes(args), guardsByResource = await observedGuards(groupByResource(routed));
|
|
5989
|
+
for (const {client: client, resourceKey: resourceKey, value: guardId} of routed) {
|
|
5990
|
+
const guard = guardsByResource.get(resourceKey)?.get(guardId);
|
|
5293
5991
|
if (guard) {
|
|
5294
|
-
if (guard._rev === void 0) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
5992
|
+
if (guard._rev === void 0 || guard._rev === null) throw new Error(`Cannot retract guard ${guardId}: persisted document has no revision`);
|
|
5295
5993
|
observed.push({
|
|
5296
5994
|
client: client,
|
|
5297
5995
|
guardId: guardId,
|
|
@@ -5322,10 +6020,11 @@ async function deleteOrphanedDefinitionGuards(args) {
|
|
|
5322
6020
|
let count = 0;
|
|
5323
6021
|
for (const {client: resourceClient, guards: guards} of perClient) {
|
|
5324
6022
|
const own = guards.filter(guard => guard.sourceInstanceId.startsWith(ownPartitionPrefix));
|
|
5325
|
-
if (own.length
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
6023
|
+
if (own.length !== 0) for (let start = 0; start < own.length; start += DELETE_CHUNK_SIZE) {
|
|
6024
|
+
const chunk = own.slice(start, start + DELETE_CHUNK_SIZE), tx = resourceClient.transaction();
|
|
6025
|
+
for (const guard of chunk) tx.delete(guard._id);
|
|
6026
|
+
await tx.commit(), count += chunk.length;
|
|
6027
|
+
}
|
|
5329
6028
|
}
|
|
5330
6029
|
return count;
|
|
5331
6030
|
}
|
|
@@ -5391,7 +6090,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5391
6090
|
...actor !== void 0 ? {
|
|
5392
6091
|
actor: actor
|
|
5393
6092
|
} : {}
|
|
5394
|
-
}), mutation.completedAt = at, mutation.abortedAt = at
|
|
6093
|
+
}), mutation.completedAt = at, mutation.abortedAt = at;
|
|
6094
|
+
const instance = readInstanceDoc(await persist(ctx, mutation));
|
|
5395
6095
|
await retractStageGuards({
|
|
5396
6096
|
client: ctx.client,
|
|
5397
6097
|
clientForGdr: ctx.clientForGdr,
|
|
@@ -5411,7 +6111,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
|
|
|
5411
6111
|
});
|
|
5412
6112
|
return {
|
|
5413
6113
|
fired: !0,
|
|
5414
|
-
stage: stage.name
|
|
6114
|
+
stage: stage.name,
|
|
6115
|
+
instance: instance
|
|
5415
6116
|
};
|
|
5416
6117
|
}
|
|
5417
6118
|
|
|
@@ -6162,18 +6863,42 @@ async function fetchGrants(args) {
|
|
|
6162
6863
|
});
|
|
6163
6864
|
}
|
|
6164
6865
|
|
|
6165
|
-
async function
|
|
6866
|
+
async function advisoryCanForCall(args) {
|
|
6867
|
+
const actor = args.options?.actor;
|
|
6868
|
+
if (!(args.options?.grants === void 0 || actor === void 0)) return advisoryCan({
|
|
6869
|
+
instance: args.instance,
|
|
6870
|
+
identity: lakePrincipalId({
|
|
6871
|
+
actor: actor,
|
|
6872
|
+
localPrincipalId: args.options.localPrincipalId
|
|
6873
|
+
}),
|
|
6874
|
+
grants: args.options.grants
|
|
6875
|
+
});
|
|
6876
|
+
}
|
|
6877
|
+
|
|
6878
|
+
async function advisoryCan({instance: instance, identity: identity, grants: grants}) {
|
|
6166
6879
|
if (grants === void 0) return;
|
|
6167
6880
|
const can = {};
|
|
6168
6881
|
for (const permission of DOCUMENT_VALUE_PERMISSIONS) can[permission] = await grantsPermissionOn({
|
|
6169
6882
|
document: instance,
|
|
6170
6883
|
grants: grants,
|
|
6171
6884
|
permission: permission,
|
|
6172
|
-
userId:
|
|
6885
|
+
userId: identity
|
|
6173
6886
|
});
|
|
6174
6887
|
return can;
|
|
6175
6888
|
}
|
|
6176
6889
|
|
|
6890
|
+
function requirementDescriptor(requirement) {
|
|
6891
|
+
return {
|
|
6892
|
+
name: requirement.name,
|
|
6893
|
+
...requirement.title !== void 0 ? {
|
|
6894
|
+
title: requirement.title
|
|
6895
|
+
} : {},
|
|
6896
|
+
...requirement.description !== void 0 ? {
|
|
6897
|
+
description: requirement.description
|
|
6898
|
+
} : {}
|
|
6899
|
+
};
|
|
6900
|
+
}
|
|
6901
|
+
|
|
6177
6902
|
function subjectDenialLabels(denied) {
|
|
6178
6903
|
return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
|
|
6179
6904
|
}
|
|
@@ -6194,10 +6919,10 @@ class ActionDisabledError extends WorkflowError {
|
|
|
6194
6919
|
|
|
6195
6920
|
class StartNotAllowedError extends WorkflowError {
|
|
6196
6921
|
definition;
|
|
6197
|
-
|
|
6922
|
+
unmetRequirements;
|
|
6198
6923
|
constructor(args) {
|
|
6199
|
-
super("start-not-allowed", `startInstance refused
|
|
6200
|
-
this.name = "StartNotAllowedError", this.definition = args.definition, this.
|
|
6924
|
+
super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
|
|
6925
|
+
this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
|
|
6201
6926
|
}
|
|
6202
6927
|
}
|
|
6203
6928
|
|
|
@@ -6213,7 +6938,7 @@ const disabledReasonDetail = {
|
|
|
6213
6938
|
"stage-terminal": r => `stage "${r.stage}" is terminal`,
|
|
6214
6939
|
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6215
6940
|
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6216
|
-
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
|
|
6941
|
+
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
|
|
6217
6942
|
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
6218
6943
|
};
|
|
6219
6944
|
|
|
@@ -6282,11 +7007,10 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
|
|
|
6282
7007
|
}
|
|
6283
7008
|
});
|
|
6284
7009
|
if (action.filter !== void 0) {
|
|
6285
|
-
const can =
|
|
7010
|
+
const can = await advisoryCanForCall({
|
|
6286
7011
|
instance: ctx.instance,
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
}) : void 0;
|
|
7012
|
+
options: options
|
|
7013
|
+
});
|
|
6290
7014
|
if (!await ctxEvaluateCondition({
|
|
6291
7015
|
ctx: ctx,
|
|
6292
7016
|
condition: action.filter,
|
|
@@ -6539,30 +7263,12 @@ async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: acti
|
|
|
6539
7263
|
};
|
|
6540
7264
|
}
|
|
6541
7265
|
|
|
6542
|
-
async function primeInitialStage(
|
|
6543
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
7266
|
+
async function primeInitialStage(args) {
|
|
7267
|
+
const {client: client, instanceId: instanceId, refSurface: refSurface, clientForGdr: clientForGdr} = args, instance = await getInstanceDocument(client, instanceId);
|
|
6544
7268
|
if (!instance || instance.stages.length > 0) return;
|
|
6545
|
-
const
|
|
7269
|
+
const ctx = await buildCascadeStepContext(args, instance), {definition: definition} = ctx, stage = definition.stages.find(s => s.name === instance.currentStage);
|
|
6546
7270
|
if (stage === void 0) return;
|
|
6547
|
-
const ctx =
|
|
6548
|
-
client: client,
|
|
6549
|
-
clientForGdr: clientForGdr,
|
|
6550
|
-
refSurface: refSurface,
|
|
6551
|
-
instance: instance,
|
|
6552
|
-
definition: definition,
|
|
6553
|
-
...clock ? {
|
|
6554
|
-
clock: clock
|
|
6555
|
-
} : {},
|
|
6556
|
-
...actor ? {
|
|
6557
|
-
actor: actor
|
|
6558
|
-
} : {},
|
|
6559
|
-
...executionContext ? {
|
|
6560
|
-
executionContext: executionContext
|
|
6561
|
-
} : {},
|
|
6562
|
-
...telemetry ? {
|
|
6563
|
-
telemetry: telemetry
|
|
6564
|
-
} : {}
|
|
6565
|
-
}), now = ctx.now, discards = [], initialStageEntry = {
|
|
7271
|
+
const now = ctx.now, discards = [], initialStageEntry = {
|
|
6566
7272
|
_key: randomKey(),
|
|
6567
7273
|
name: stage.name,
|
|
6568
7274
|
enteredAt: now,
|
|
@@ -6631,29 +7337,37 @@ async function primeInitialStage({client: client, instanceId: instanceId, actor:
|
|
|
6631
7337
|
|
|
6632
7338
|
const CASCADE_LIMIT = 100;
|
|
6633
7339
|
|
|
6634
|
-
async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
6635
|
-
const
|
|
7340
|
+
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}) {
|
|
7341
|
+
const contextOptions = {
|
|
7342
|
+
clientForGdr: clientForGdr,
|
|
7343
|
+
refSurface: refSurface,
|
|
7344
|
+
...actor ? {
|
|
7345
|
+
actor: actor
|
|
7346
|
+
} : {},
|
|
7347
|
+
...clock ? {
|
|
7348
|
+
clock: clock
|
|
7349
|
+
} : {},
|
|
7350
|
+
...executionContext ? {
|
|
7351
|
+
executionContext: executionContext
|
|
7352
|
+
} : {},
|
|
7353
|
+
...telemetry ? {
|
|
7354
|
+
telemetry: telemetry
|
|
7355
|
+
} : {},
|
|
7356
|
+
...overlay ? {
|
|
7357
|
+
overlay: overlay
|
|
7358
|
+
} : {},
|
|
7359
|
+
...settlingCohorts ? {
|
|
7360
|
+
settlingCohorts: settlingCohorts
|
|
7361
|
+
} : {}
|
|
7362
|
+
}, ctx = instance === void 0 ? await loadContext({
|
|
6636
7363
|
client: client,
|
|
6637
7364
|
instanceId: instanceId,
|
|
6638
|
-
options:
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
...clock ? {
|
|
6645
|
-
clock: clock
|
|
6646
|
-
} : {},
|
|
6647
|
-
...executionContext ? {
|
|
6648
|
-
executionContext: executionContext
|
|
6649
|
-
} : {},
|
|
6650
|
-
...telemetry ? {
|
|
6651
|
-
telemetry: telemetry
|
|
6652
|
-
} : {},
|
|
6653
|
-
...overlay ? {
|
|
6654
|
-
overlay: overlay
|
|
6655
|
-
} : {}
|
|
6656
|
-
}
|
|
7365
|
+
options: contextOptions
|
|
7366
|
+
}) : await buildEngineContext({
|
|
7367
|
+
client: client,
|
|
7368
|
+
instance: instance,
|
|
7369
|
+
definition: parseDefinitionSnapshot(instance),
|
|
7370
|
+
...contextOptions
|
|
6657
7371
|
});
|
|
6658
7372
|
if (isTerminal(ctx)) return {
|
|
6659
7373
|
moved: !1
|
|
@@ -6683,10 +7397,10 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
|
|
|
6683
7397
|
});
|
|
6684
7398
|
}
|
|
6685
7399
|
|
|
6686
|
-
async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
7400
|
+
async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts}) {
|
|
6687
7401
|
let count = 0;
|
|
6688
7402
|
for (;;) {
|
|
6689
|
-
|
|
7403
|
+
const drained = await drainCondemnedChildren({
|
|
6690
7404
|
client: client,
|
|
6691
7405
|
instanceId: instanceId,
|
|
6692
7406
|
actor: actor,
|
|
@@ -6695,7 +7409,8 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6695
7409
|
clock: clock,
|
|
6696
7410
|
executionContext: executionContext,
|
|
6697
7411
|
telemetry: telemetry
|
|
6698
|
-
})
|
|
7412
|
+
});
|
|
7413
|
+
if (!(await runCascadeHop({
|
|
6699
7414
|
client: client,
|
|
6700
7415
|
instanceId: instanceId,
|
|
6701
7416
|
actor: actor,
|
|
@@ -6704,7 +7419,11 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6704
7419
|
clock: clock,
|
|
6705
7420
|
executionContext: executionContext,
|
|
6706
7421
|
telemetry: telemetry,
|
|
6707
|
-
overlay: overlay
|
|
7422
|
+
overlay: overlay,
|
|
7423
|
+
settlingCohorts: settlingCohorts,
|
|
7424
|
+
...drained.drained ? {} : {
|
|
7425
|
+
instance: drained.instance
|
|
7426
|
+
}
|
|
6708
7427
|
})).moved) return count;
|
|
6709
7428
|
if (count++, count >= CASCADE_LIMIT) throw new CascadeLimitError({
|
|
6710
7429
|
instanceId: instanceId,
|
|
@@ -6713,39 +7432,50 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
|
|
|
6713
7432
|
}
|
|
6714
7433
|
}
|
|
6715
7434
|
|
|
6716
|
-
async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set}) {
|
|
6717
|
-
if (draining.has(instanceId)) return
|
|
7435
|
+
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}) {
|
|
7436
|
+
if (draining.has(instanceId)) return {
|
|
7437
|
+
instance: preloadedInstance,
|
|
7438
|
+
drained: !1
|
|
7439
|
+
};
|
|
6718
7440
|
draining.add(instanceId);
|
|
6719
|
-
const instance = await getInstanceDocument(client, instanceId);
|
|
6720
|
-
if (!instance) return
|
|
7441
|
+
const instance = preloadedInstance ?? await getInstanceDocument(client, instanceId);
|
|
7442
|
+
if (!instance) return {
|
|
7443
|
+
instance: void 0,
|
|
7444
|
+
drained: !1
|
|
7445
|
+
};
|
|
6721
7446
|
const condemned = condemnedSubworkflows(instance);
|
|
6722
|
-
if (condemned.length
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
7447
|
+
if (condemned.length === 0) return {
|
|
7448
|
+
instance: instance,
|
|
7449
|
+
drained: !1
|
|
7450
|
+
};
|
|
7451
|
+
for (const row of condemned) await settleCondemnedRow({
|
|
7452
|
+
client: client,
|
|
7453
|
+
ownerId: instanceId,
|
|
7454
|
+
row: row,
|
|
7455
|
+
actor: actor,
|
|
7456
|
+
clientForGdr: clientForGdr,
|
|
7457
|
+
refSurface: refSurface,
|
|
7458
|
+
clock: clock,
|
|
7459
|
+
executionContext: executionContext,
|
|
7460
|
+
telemetry: telemetry,
|
|
7461
|
+
draining: draining
|
|
7462
|
+
});
|
|
7463
|
+
return await stampDrainedRows({
|
|
7464
|
+
client: client,
|
|
7465
|
+
instance: instance,
|
|
7466
|
+
condemned: condemned,
|
|
7467
|
+
clock: clock,
|
|
7468
|
+
executionContext: executionContext
|
|
7469
|
+
}), {
|
|
7470
|
+
instance: instance,
|
|
7471
|
+
drained: !0
|
|
7472
|
+
};
|
|
6743
7473
|
}
|
|
6744
7474
|
|
|
6745
7475
|
async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
|
|
6746
7476
|
const childId = toBareId(row.ref.id);
|
|
6747
7477
|
try {
|
|
6748
|
-
await abortInstance({
|
|
7478
|
+
const result = await abortInstance({
|
|
6749
7479
|
client: client,
|
|
6750
7480
|
instanceId: childId,
|
|
6751
7481
|
reason: row.abortPending?.reason ?? "condemned by parent",
|
|
@@ -6765,7 +7495,8 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6765
7495
|
telemetry: telemetry
|
|
6766
7496
|
} : {}
|
|
6767
7497
|
}
|
|
6768
|
-
})
|
|
7498
|
+
});
|
|
7499
|
+
await drainCondemnedChildren({
|
|
6769
7500
|
client: client,
|
|
6770
7501
|
instanceId: childId,
|
|
6771
7502
|
actor: actor,
|
|
@@ -6774,7 +7505,10 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6774
7505
|
clock: clock,
|
|
6775
7506
|
executionContext: executionContext,
|
|
6776
7507
|
telemetry: telemetry,
|
|
6777
|
-
draining: draining
|
|
7508
|
+
draining: draining,
|
|
7509
|
+
...result.fired ? {
|
|
7510
|
+
instance: result.instance
|
|
7511
|
+
} : {}
|
|
6778
7512
|
});
|
|
6779
7513
|
} catch (cause) {
|
|
6780
7514
|
if (cause instanceof InstanceNotFoundError) return;
|
|
@@ -6787,9 +7521,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
|
|
|
6787
7521
|
}
|
|
6788
7522
|
|
|
6789
7523
|
async function stampDrainedRows({client: client, instance: instance, condemned: condemned, clock: clock, executionContext: executionContext}) {
|
|
6790
|
-
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => toBareId(row.ref.id)),
|
|
6791
|
-
ids: ids
|
|
6792
|
-
}), byId = new Map(children.map(c => [ assertReadableModel(c)._id, c ])), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
|
|
7524
|
+
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => 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 => {
|
|
6793
7525
|
if (row.resolved !== void 0 || !condemnedKeys.has(row._key)) return row;
|
|
6794
7526
|
const child = byId.get(toBareId(row.ref.id)), resolved = child !== void 0 ? terminalResolution(child) : {
|
|
6795
7527
|
at: now,
|
|
@@ -6811,6 +7543,16 @@ async function stampDrainedRows({client: client, instance: instance, condemned:
|
|
|
6811
7543
|
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
6812
7544
|
}
|
|
6813
7545
|
|
|
7546
|
+
async function loadInstancesById(client, ids) {
|
|
7547
|
+
const children = await client.fetch("*[_id in $ids]", {
|
|
7548
|
+
ids: ids
|
|
7549
|
+
});
|
|
7550
|
+
return new Map(children.filter(child => child._type === WORKFLOW_INSTANCE_TYPE).map(child => {
|
|
7551
|
+
const instance = readInstanceDoc(child);
|
|
7552
|
+
return [ instance._id, instance ];
|
|
7553
|
+
}));
|
|
7554
|
+
}
|
|
7555
|
+
|
|
6814
7556
|
function terminalResolution(child) {
|
|
6815
7557
|
const status = resolvedChildStatus(child);
|
|
6816
7558
|
if (!(status === void 0 || child.completedAt === void 0 || child.completedAt === null)) return {
|
|
@@ -6833,28 +7575,18 @@ function subworkflowResolvedEntry({row: row, at: at, status: status}) {
|
|
|
6833
7575
|
};
|
|
6834
7576
|
}
|
|
6835
7577
|
|
|
6836
|
-
async function propagateToAncestors(
|
|
6837
|
-
const loaded = await loadPropagationPair(
|
|
6838
|
-
if (loaded === void 0) return;
|
|
6839
|
-
const {child: child, parent: parent} = loaded, definition = parseDefinitionSnapshot(parent), ctx = await buildEngineContext({
|
|
7578
|
+
async function propagateToAncestors(args) {
|
|
7579
|
+
const {instance: instance, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, loaded = await loadPropagationPair({
|
|
6840
7580
|
client: client,
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
definition: definition,
|
|
6845
|
-
...clock ? {
|
|
6846
|
-
clock: clock
|
|
6847
|
-
} : {},
|
|
6848
|
-
...actor ? {
|
|
6849
|
-
actor: actor
|
|
6850
|
-
} : {},
|
|
6851
|
-
...executionContext ? {
|
|
6852
|
-
executionContext: executionContext
|
|
6853
|
-
} : {},
|
|
6854
|
-
...telemetry ? {
|
|
6855
|
-
telemetry: telemetry
|
|
7581
|
+
instanceId: instanceId,
|
|
7582
|
+
...instance !== void 0 ? {
|
|
7583
|
+
instance: instance
|
|
6856
7584
|
} : {}
|
|
6857
|
-
})
|
|
7585
|
+
});
|
|
7586
|
+
if (loaded === void 0) return;
|
|
7587
|
+
const {child: child, parent: parent} = loaded;
|
|
7588
|
+
if (stepArgs.settlingCohorts?.has(parent._id)) return;
|
|
7589
|
+
const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent), row = mutation.subworkflows.find(r => toBareId(r.ref.id) === child._id);
|
|
6858
7590
|
if (row === void 0) {
|
|
6859
7591
|
await recordOrphanedPropagation({
|
|
6860
7592
|
ctx: ctx,
|
|
@@ -6869,29 +7601,11 @@ async function propagateToAncestors({client: client, instanceId: instanceId, act
|
|
|
6869
7601
|
child: child,
|
|
6870
7602
|
now: ctx.now
|
|
6871
7603
|
}), parentTerminal = parent.completedAt !== void 0;
|
|
6872
|
-
changed && await persist(ctx, mutation), !parentTerminal &&
|
|
6873
|
-
client: client,
|
|
6874
|
-
instanceId: parent._id,
|
|
6875
|
-
actor: actor,
|
|
6876
|
-
clientForGdr: clientForGdr,
|
|
6877
|
-
refSurface: refSurface,
|
|
6878
|
-
clock: clock,
|
|
6879
|
-
executionContext: executionContext,
|
|
6880
|
-
telemetry: telemetry
|
|
6881
|
-
}), await propagateToAncestors({
|
|
6882
|
-
client: client,
|
|
6883
|
-
instanceId: parent._id,
|
|
6884
|
-
actor: actor,
|
|
6885
|
-
clientForGdr: clientForGdr,
|
|
6886
|
-
refSurface: refSurface,
|
|
6887
|
-
clock: clock,
|
|
6888
|
-
executionContext: executionContext,
|
|
6889
|
-
telemetry: telemetry
|
|
6890
|
-
}));
|
|
7604
|
+
changed && await persist(ctx, mutation), !parentTerminal && await cascadeAndPropagateParent(stepArgs, parent);
|
|
6891
7605
|
}
|
|
6892
7606
|
|
|
6893
|
-
async function loadPropagationPair(client, instanceId) {
|
|
6894
|
-
const child = await getInstanceDocument(client, instanceId);
|
|
7607
|
+
async function loadPropagationPair({client: client, instanceId: instanceId, instance: instance}) {
|
|
7608
|
+
const child = instance ?? await getInstanceDocument(client, instanceId);
|
|
6895
7609
|
if (!child) return;
|
|
6896
7610
|
const parentGdr = parentRef(child);
|
|
6897
7611
|
if (parentGdr === void 0) return;
|
|
@@ -6902,6 +7616,83 @@ async function loadPropagationPair(client, instanceId) {
|
|
|
6902
7616
|
};
|
|
6903
7617
|
}
|
|
6904
7618
|
|
|
7619
|
+
async function propagateSpawnBatch(args) {
|
|
7620
|
+
const {childIds: childIds, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, parent = await getInstanceDocument(client, instanceId);
|
|
7621
|
+
if (parent === void 0) return;
|
|
7622
|
+
const children = await loadInstancesById(client, childIds);
|
|
7623
|
+
if (children.size !== childIds.length) throw new Error(`Spawn batch for ${instanceId} could not reload every child`);
|
|
7624
|
+
const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent);
|
|
7625
|
+
stampSpawnBatch({
|
|
7626
|
+
mutation: mutation,
|
|
7627
|
+
parent: parent,
|
|
7628
|
+
children: children,
|
|
7629
|
+
childIds: childIds,
|
|
7630
|
+
now: ctx.now
|
|
7631
|
+
}) && await persist(ctx, mutation), parent.completedAt === void 0 && await cascadeAndPropagateParent(stepArgs, parent);
|
|
7632
|
+
}
|
|
7633
|
+
|
|
7634
|
+
async function buildCascadeStepContext(args, instance) {
|
|
7635
|
+
return buildEngineContext({
|
|
7636
|
+
client: args.client,
|
|
7637
|
+
clientForGdr: args.clientForGdr,
|
|
7638
|
+
refSurface: args.refSurface,
|
|
7639
|
+
instance: instance,
|
|
7640
|
+
definition: parseDefinitionSnapshot(instance),
|
|
7641
|
+
...args.clock ? {
|
|
7642
|
+
clock: args.clock
|
|
7643
|
+
} : {},
|
|
7644
|
+
...args.actor ? {
|
|
7645
|
+
actor: args.actor
|
|
7646
|
+
} : {},
|
|
7647
|
+
...args.executionContext ? {
|
|
7648
|
+
executionContext: args.executionContext
|
|
7649
|
+
} : {},
|
|
7650
|
+
...args.telemetry ? {
|
|
7651
|
+
telemetry: args.telemetry
|
|
7652
|
+
} : {},
|
|
7653
|
+
...args.settlingCohorts ? {
|
|
7654
|
+
settlingCohorts: args.settlingCohorts
|
|
7655
|
+
} : {}
|
|
7656
|
+
});
|
|
7657
|
+
}
|
|
7658
|
+
|
|
7659
|
+
async function cascadeAndPropagateParent(args, parent) {
|
|
7660
|
+
await cascadeAutoTransitions({
|
|
7661
|
+
...args,
|
|
7662
|
+
instanceId: parent._id
|
|
7663
|
+
}), await propagateToAncestors({
|
|
7664
|
+
...args,
|
|
7665
|
+
instanceId: parent._id
|
|
7666
|
+
});
|
|
7667
|
+
}
|
|
7668
|
+
|
|
7669
|
+
function stampSpawnBatch({mutation: mutation, parent: parent, children: children, childIds: childIds, now: now}) {
|
|
7670
|
+
let changed = !1;
|
|
7671
|
+
for (const childId of childIds) {
|
|
7672
|
+
const child = requireSpawnBatchChild({
|
|
7673
|
+
parent: parent,
|
|
7674
|
+
children: children,
|
|
7675
|
+
childId: childId
|
|
7676
|
+
}), row = mutation.subworkflows.find(entry => toBareId(entry.ref.id) === childId);
|
|
7677
|
+
if (row === void 0) throw new Error(`Spawn batch child ${childId} has no registry row on parent ${parent._id}`);
|
|
7678
|
+
changed = stampResolvedChild({
|
|
7679
|
+
mutation: mutation,
|
|
7680
|
+
row: row,
|
|
7681
|
+
child: child,
|
|
7682
|
+
now: now
|
|
7683
|
+
}) || changed;
|
|
7684
|
+
}
|
|
7685
|
+
return changed;
|
|
7686
|
+
}
|
|
7687
|
+
|
|
7688
|
+
function requireSpawnBatchChild({parent: parent, children: children, childId: childId}) {
|
|
7689
|
+
const child = children.get(childId);
|
|
7690
|
+
if (child === void 0) throw new Error(`Spawn batch child ${childId} disappeared`);
|
|
7691
|
+
const expectedParent = parentRef(child);
|
|
7692
|
+
if (expectedParent === void 0 || toBareId(expectedParent.id) !== parent._id) throw new Error(`Spawn batch child ${childId} does not belong to parent ${parent._id}`);
|
|
7693
|
+
return child;
|
|
7694
|
+
}
|
|
7695
|
+
|
|
6905
7696
|
function stampResolvedChild({mutation: mutation, row: row, child: child, now: now}) {
|
|
6906
7697
|
if (row.resolved !== void 0) return !1;
|
|
6907
7698
|
const resolved = terminalResolution(child);
|
|
@@ -7037,36 +7828,14 @@ async function persist(ctx, mutation) {
|
|
|
7037
7828
|
for (const {body: body} of pendingCreates) tx.create(body);
|
|
7038
7829
|
tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
|
|
7039
7830
|
await tx.commit(), mutation.pendingCreates = [];
|
|
7040
|
-
const actorForPriming = ctx.actor;
|
|
7041
|
-
for (const {body: body
|
|
7042
|
-
|
|
7043
|
-
client: ctx.client,
|
|
7044
|
-
instanceId: body._id,
|
|
7045
|
-
actor: actorForPriming,
|
|
7046
|
-
clientForGdr: ctx.clientForGdr,
|
|
7047
|
-
refSurface: ctx.refSurface,
|
|
7048
|
-
clock: ctx.clock,
|
|
7049
|
-
executionContext: ctx.executionContext,
|
|
7050
|
-
telemetry: ctx.telemetry
|
|
7051
|
-
}), await cascadeAutoTransitions({
|
|
7052
|
-
client: ctx.client,
|
|
7053
|
-
instanceId: body._id,
|
|
7054
|
-
actor: actorForPriming,
|
|
7055
|
-
clientForGdr: ctx.clientForGdr,
|
|
7056
|
-
refSurface: ctx.refSurface,
|
|
7057
|
-
clock: ctx.clock,
|
|
7058
|
-
executionContext: ctx.executionContext,
|
|
7059
|
-
telemetry: ctx.telemetry
|
|
7060
|
-
}), await propagateToAncestors({
|
|
7061
|
-
client: ctx.client,
|
|
7831
|
+
const actorForPriming = ctx.actor, settlingCohorts = new Set(ctx.settlingCohorts).add(ctx.instance._id);
|
|
7832
|
+
for (const {body: body} of pendingCreates) try {
|
|
7833
|
+
const stepArgs = spawnStepArgs(ctx, {
|
|
7062
7834
|
instanceId: body._id,
|
|
7063
7835
|
actor: actorForPriming,
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
executionContext: ctx.executionContext,
|
|
7068
|
-
telemetry: ctx.telemetry
|
|
7069
|
-
}), ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7836
|
+
settlingCohorts: settlingCohorts
|
|
7837
|
+
});
|
|
7838
|
+
await primeInitialStage(stepArgs), await cascadeAutoTransitions(stepArgs);
|
|
7070
7839
|
} catch (cause) {
|
|
7071
7840
|
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7072
7841
|
instanceId: ctx.instance._id,
|
|
@@ -7074,11 +7843,50 @@ async function persist(ctx, mutation) {
|
|
|
7074
7843
|
reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
|
|
7075
7844
|
});
|
|
7076
7845
|
}
|
|
7846
|
+
await settleSpawnBatch(ctx, {
|
|
7847
|
+
pendingCreates: pendingCreates,
|
|
7848
|
+
actor: actorForPriming,
|
|
7849
|
+
settlingCohorts: settlingCohorts
|
|
7850
|
+
});
|
|
7851
|
+
for (const {started: started} of pendingCreates) ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7077
7852
|
const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
|
|
7078
7853
|
if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
|
|
7079
7854
|
return reloaded;
|
|
7080
7855
|
}
|
|
7081
7856
|
|
|
7857
|
+
async function settleSpawnBatch(ctx, args) {
|
|
7858
|
+
try {
|
|
7859
|
+
await propagateSpawnBatch({
|
|
7860
|
+
...spawnStepArgs(ctx, {
|
|
7861
|
+
instanceId: ctx.instance._id,
|
|
7862
|
+
actor: args.actor,
|
|
7863
|
+
settlingCohorts: args.settlingCohorts
|
|
7864
|
+
}),
|
|
7865
|
+
childIds: args.pendingCreates.map(({body: body}) => body._id)
|
|
7866
|
+
});
|
|
7867
|
+
} catch (cause) {
|
|
7868
|
+
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7869
|
+
instanceId: ctx.instance._id,
|
|
7870
|
+
guardError: cause,
|
|
7871
|
+
reason: "spawned children failed to propagate after the spawn transaction committed"
|
|
7872
|
+
});
|
|
7873
|
+
}
|
|
7874
|
+
}
|
|
7875
|
+
|
|
7876
|
+
function spawnStepArgs(ctx, args) {
|
|
7877
|
+
return {
|
|
7878
|
+
client: ctx.client,
|
|
7879
|
+
instanceId: args.instanceId,
|
|
7880
|
+
actor: args.actor,
|
|
7881
|
+
clientForGdr: ctx.clientForGdr,
|
|
7882
|
+
refSurface: ctx.refSurface,
|
|
7883
|
+
clock: ctx.clock,
|
|
7884
|
+
executionContext: ctx.executionContext,
|
|
7885
|
+
telemetry: ctx.telemetry,
|
|
7886
|
+
settlingCohorts: args.settlingCohorts ?? ctx.settlingCohorts
|
|
7887
|
+
};
|
|
7888
|
+
}
|
|
7889
|
+
|
|
7082
7890
|
function stampExecutionContext(ctx, mutation) {
|
|
7083
7891
|
const stamp = ctx.executionContext, appended = mutation.history.slice(ctx.instance.history.length);
|
|
7084
7892
|
mutation.history = [ ...mutation.history.slice(0, ctx.instance.history.length), ...stampHistoryEntries(appended, stamp) ];
|
|
@@ -7206,24 +8014,25 @@ function buildEffectSettlement(pending, outcome) {
|
|
|
7206
8014
|
}
|
|
7207
8015
|
|
|
7208
8016
|
function validateEffectOutputs(args) {
|
|
7209
|
-
const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [];
|
|
8017
|
+
const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [], normalized = {};
|
|
7210
8018
|
for (const [key, value] of Object.entries(outputs)) {
|
|
7211
8019
|
const shape = byName.get(key);
|
|
7212
8020
|
if (shape === void 0) {
|
|
7213
8021
|
issues.push(`"${key}" is not a declared output`);
|
|
7214
8022
|
continue;
|
|
7215
8023
|
}
|
|
7216
|
-
const
|
|
7217
|
-
|
|
8024
|
+
const check = effectOutputCheck(shape, value);
|
|
8025
|
+
"issues" in check ? issues.push(...check.issues.map(i => `"${key}": ${i}`)) : normalized[key] = check.output;
|
|
7218
8026
|
}
|
|
7219
8027
|
if (issues.length > 0) throw new EffectOutputsInvalidError({
|
|
7220
8028
|
effect: effectName,
|
|
7221
8029
|
issues: issues
|
|
7222
8030
|
});
|
|
8031
|
+
return normalized;
|
|
7223
8032
|
}
|
|
7224
8033
|
|
|
7225
|
-
function
|
|
7226
|
-
return
|
|
8034
|
+
function effectOutputCheck(shape, value) {
|
|
8035
|
+
return parseFieldValue({
|
|
7227
8036
|
entryType: shape.type,
|
|
7228
8037
|
value: value,
|
|
7229
8038
|
...shape.fields !== void 0 ? {
|
|
@@ -7269,15 +8078,15 @@ function validateCompletionInput({pending: pending, definition: definition, stat
|
|
|
7269
8078
|
effect: pending.name,
|
|
7270
8079
|
issues: [ "outputs cannot accompany a failed completion — report outputs on a done completion instead" ]
|
|
7271
8080
|
});
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
8081
|
+
const normalizedOutputs = outputs !== void 0 ? validateEffectOutputs({
|
|
8082
|
+
outputs: outputs,
|
|
8083
|
+
declared: findEffect(definition, pending.name)?.outputs ?? [],
|
|
8084
|
+
effectName: pending.name
|
|
8085
|
+
}) : void 0;
|
|
8086
|
+
return {
|
|
8087
|
+
ops: ops !== void 0 ? validateEffectOps(ops, pending.name) : [],
|
|
8088
|
+
outputs: normalizedOutputs
|
|
8089
|
+
};
|
|
7281
8090
|
}
|
|
7282
8091
|
|
|
7283
8092
|
async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, actor: actor}) {
|
|
@@ -7286,7 +8095,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7286
8095
|
record: requestRecord,
|
|
7287
8096
|
now: ctx.now
|
|
7288
8097
|
});
|
|
7289
|
-
const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
|
|
8098
|
+
const pending = requirePendingEffect(ctx.instance, effectKey), {ops: validatedOps, outputs: validatedOutputs} = validateCompletionInput({
|
|
7290
8099
|
pending: pending,
|
|
7291
8100
|
definition: ctx.definition,
|
|
7292
8101
|
status: status,
|
|
@@ -7305,7 +8114,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
|
|
|
7305
8114
|
detail: detail,
|
|
7306
8115
|
error: error,
|
|
7307
8116
|
durationMs: durationMs,
|
|
7308
|
-
outputs:
|
|
8117
|
+
outputs: validatedOutputs
|
|
7309
8118
|
});
|
|
7310
8119
|
mutation.effectHistory.push(settlement.run);
|
|
7311
8120
|
const wroteEffectOutputs = status === "done" && outputs !== void 0;
|
|
@@ -7503,6 +8312,64 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
|
|
|
7503
8312
|
};
|
|
7504
8313
|
}
|
|
7505
8314
|
|
|
8315
|
+
const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
|
|
8316
|
+
|
|
8317
|
+
function isResetActivityTarget(value) {
|
|
8318
|
+
return RESET_ACTIVITY_TARGETS.includes(value);
|
|
8319
|
+
}
|
|
8320
|
+
|
|
8321
|
+
async function resetActivity(args) {
|
|
8322
|
+
const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
|
|
8323
|
+
client: client,
|
|
8324
|
+
instanceId: instanceId,
|
|
8325
|
+
options: options
|
|
8326
|
+
});
|
|
8327
|
+
return commitResetActivity({
|
|
8328
|
+
ctx: ctx,
|
|
8329
|
+
activity: activity,
|
|
8330
|
+
to: to,
|
|
8331
|
+
requestRecord: requestRecord,
|
|
8332
|
+
actor: options?.actor
|
|
8333
|
+
});
|
|
8334
|
+
}
|
|
8335
|
+
|
|
8336
|
+
async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
|
|
8337
|
+
if (assertRequestUnprocessed({
|
|
8338
|
+
instance: ctx.instance,
|
|
8339
|
+
record: requestRecord,
|
|
8340
|
+
now: ctx.now
|
|
8341
|
+
}), isTerminal(ctx)) return {
|
|
8342
|
+
fired: !1
|
|
8343
|
+
};
|
|
8344
|
+
const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
|
|
8345
|
+
if (openStage2 === void 0 || entry === void 0) throw new ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
|
|
8346
|
+
const from = entry.status;
|
|
8347
|
+
if (from === to) return {
|
|
8348
|
+
fired: !1
|
|
8349
|
+
};
|
|
8350
|
+
if (!isTerminalActivityStatus(from)) throw new 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.`);
|
|
8351
|
+
return recordProcessedRequest({
|
|
8352
|
+
mutation: mutation,
|
|
8353
|
+
record: requestRecord,
|
|
8354
|
+
now: ctx.now
|
|
8355
|
+
}), applyActivityStatusChange({
|
|
8356
|
+
entry: entry,
|
|
8357
|
+
history: mutation.history,
|
|
8358
|
+
stage: openStage2.name,
|
|
8359
|
+
to: to,
|
|
8360
|
+
at: ctx.now,
|
|
8361
|
+
...actor !== void 0 ? {
|
|
8362
|
+
actor: actor
|
|
8363
|
+
} : {}
|
|
8364
|
+
}), await persist(ctx, mutation), {
|
|
8365
|
+
fired: !0,
|
|
8366
|
+
stage: openStage2.name,
|
|
8367
|
+
activity: activity,
|
|
8368
|
+
from: from,
|
|
8369
|
+
to: to
|
|
8370
|
+
};
|
|
8371
|
+
}
|
|
8372
|
+
|
|
7506
8373
|
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
|
|
7507
8374
|
|
|
7508
8375
|
async function resolveAccess(taggedClient, args = {}) {
|
|
@@ -7512,10 +8379,13 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7512
8379
|
client: client,
|
|
7513
8380
|
requestFn: requestFn,
|
|
7514
8381
|
resourcePath: args.grantsFromPath
|
|
7515
|
-
}) : Promise.resolve(void 0), [
|
|
7516
|
-
if (
|
|
8382
|
+
}) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
8383
|
+
if (identity === void 0) throw new ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
|
|
7517
8384
|
return {
|
|
7518
|
-
actor: actor,
|
|
8385
|
+
actor: identity.actor,
|
|
8386
|
+
...identity.localPrincipalId !== void 0 ? {
|
|
8387
|
+
localPrincipalId: identity.localPrincipalId
|
|
8388
|
+
} : {},
|
|
7519
8389
|
...grants !== void 0 ? {
|
|
7520
8390
|
grants: grants
|
|
7521
8391
|
} : {}
|
|
@@ -7525,7 +8395,7 @@ async function resolveAccess(taggedClient, args = {}) {
|
|
|
7525
8395
|
function cachedActor(client, requestFn) {
|
|
7526
8396
|
const cached = actorCache.get(client);
|
|
7527
8397
|
if (cached !== void 0) return cached;
|
|
7528
|
-
const pending = fetchActor(requestFn).catch(err => {
|
|
8398
|
+
const pending = fetchActor(client, requestFn).catch(err => {
|
|
7529
8399
|
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
7530
8400
|
});
|
|
7531
8401
|
return actorCache.set(client, pending), pending;
|
|
@@ -7552,27 +8422,90 @@ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resou
|
|
|
7552
8422
|
byPath.set(resourcePath, cached)), cached;
|
|
7553
8423
|
}
|
|
7554
8424
|
|
|
7555
|
-
async function fetchActor(requestFn) {
|
|
7556
|
-
|
|
8425
|
+
async function fetchActor(client, requestFn) {
|
|
8426
|
+
const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalId = usableId(globalUser.user), id = globalId ?? resourceId;
|
|
8427
|
+
if (id === void 0) return;
|
|
8428
|
+
refuseProjectPrincipalWithoutGlobal({
|
|
8429
|
+
resourceId: resourceId,
|
|
8430
|
+
globalId: globalId,
|
|
8431
|
+
globalUser: globalUser
|
|
8432
|
+
});
|
|
8433
|
+
const roleNames = (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
8434
|
+
return {
|
|
8435
|
+
actor: {
|
|
8436
|
+
kind: "person",
|
|
8437
|
+
id: id,
|
|
8438
|
+
...roleNames.length > 0 ? {
|
|
8439
|
+
roles: roleNames
|
|
8440
|
+
} : {}
|
|
8441
|
+
},
|
|
8442
|
+
...resourceId !== void 0 && resourceId !== id ? {
|
|
8443
|
+
localPrincipalId: resourceId
|
|
8444
|
+
} : {}
|
|
8445
|
+
};
|
|
8446
|
+
}
|
|
8447
|
+
|
|
8448
|
+
function refuseProjectPrincipalWithoutGlobal(args) {
|
|
8449
|
+
const {resourceId: resourceId, globalId: globalId, globalUser: globalUser} = args;
|
|
8450
|
+
if (globalId !== void 0 || resourceId === void 0 || classifyPrincipalId(resourceId).namespace !== "project") return;
|
|
8451
|
+
const reason = "reason" in globalUser ? globalUser.reason : "no record";
|
|
8452
|
+
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 ? {
|
|
8453
|
+
cause: globalUser.cause
|
|
8454
|
+
} : void 0);
|
|
8455
|
+
}
|
|
8456
|
+
|
|
8457
|
+
function usableId(user) {
|
|
8458
|
+
if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
|
|
8459
|
+
}
|
|
8460
|
+
|
|
8461
|
+
async function fetchCurrentUser(requestFn, hostDescription) {
|
|
7557
8462
|
try {
|
|
7558
|
-
|
|
8463
|
+
return await requestFn({
|
|
7559
8464
|
uri: "/users/me",
|
|
7560
8465
|
tag: REQUEST_TAG.accessResolveActor
|
|
7561
8466
|
});
|
|
7562
8467
|
} catch (err) {
|
|
7563
|
-
throw new Error(
|
|
8468
|
+
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.`, {
|
|
7564
8469
|
cause: err
|
|
7565
8470
|
});
|
|
7566
8471
|
}
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
8472
|
+
}
|
|
8473
|
+
|
|
8474
|
+
async function fetchGlobalUser(client) {
|
|
8475
|
+
if (typeof client.withConfig != "function") return {
|
|
8476
|
+
user: void 0,
|
|
8477
|
+
reason: "the client cannot reach the global API host (no withConfig)"
|
|
8478
|
+
};
|
|
8479
|
+
let globalRequest, globalClient;
|
|
8480
|
+
try {
|
|
8481
|
+
globalClient = client.withConfig({
|
|
8482
|
+
useProjectHostname: !1
|
|
8483
|
+
}), globalRequest = lazyRequest(globalClient);
|
|
8484
|
+
} catch (err) {
|
|
8485
|
+
return {
|
|
8486
|
+
user: void 0,
|
|
8487
|
+
reason: `building the global-host sibling client failed: ${errorMessage(err)}`,
|
|
8488
|
+
cause: err
|
|
8489
|
+
};
|
|
8490
|
+
}
|
|
8491
|
+
if (globalRequest === void 0) return {
|
|
8492
|
+
user: void 0,
|
|
8493
|
+
reason: "the global-host sibling client cannot issue requests"
|
|
7575
8494
|
};
|
|
8495
|
+
try {
|
|
8496
|
+
return {
|
|
8497
|
+
user: await globalRequest({
|
|
8498
|
+
uri: "/users/me",
|
|
8499
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
8500
|
+
})
|
|
8501
|
+
};
|
|
8502
|
+
} catch (err) {
|
|
8503
|
+
return {
|
|
8504
|
+
user: void 0,
|
|
8505
|
+
reason: `global-host /users/me failed: ${errorMessage(err)}`,
|
|
8506
|
+
cause: err
|
|
8507
|
+
};
|
|
8508
|
+
}
|
|
7576
8509
|
}
|
|
7577
8510
|
|
|
7578
8511
|
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
@@ -7748,35 +8681,48 @@ async function subjectResourceGrants(args) {
|
|
|
7748
8681
|
const resolved = await Promise.all([ ...clients.entries() ].map(async ([key, entry]) => {
|
|
7749
8682
|
const path = aclPathForResource(entry.resource);
|
|
7750
8683
|
if (path === void 0) return;
|
|
7751
|
-
const grants = await grantsForClientPath(entry.client, path);
|
|
7752
|
-
|
|
8684
|
+
const [grants, actorId] = await Promise.all([ grantsForClientPath(entry.client, path), resourceActorId(entry.client) ]);
|
|
8685
|
+
if (!(grants === void 0 || actorId === void 0)) return [ key, {
|
|
8686
|
+
grants: grants,
|
|
8687
|
+
actorId: actorId
|
|
8688
|
+
} ];
|
|
7753
8689
|
}));
|
|
7754
8690
|
return new Map(resolved.filter(entry => entry !== void 0));
|
|
7755
8691
|
}
|
|
7756
8692
|
|
|
8693
|
+
async function resourceActorId(client) {
|
|
8694
|
+
try {
|
|
8695
|
+
const access = await resolveAccess(client);
|
|
8696
|
+
return lakePrincipalId(access);
|
|
8697
|
+
} catch (err) {
|
|
8698
|
+
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: ${errorMessage(err)}`);
|
|
8699
|
+
return;
|
|
8700
|
+
}
|
|
8701
|
+
}
|
|
8702
|
+
|
|
7757
8703
|
async function evaluateInstance(args) {
|
|
7758
8704
|
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
7759
8705
|
validateTag(tag);
|
|
7760
|
-
const
|
|
8706
|
+
const [access, instance] = await Promise.all([ resolveAccess(client, {
|
|
7761
8707
|
...args.grantsFromPath !== void 0 ? {
|
|
7762
8708
|
grantsFromPath: args.grantsFromPath
|
|
7763
8709
|
} : {}
|
|
7764
|
-
}),
|
|
8710
|
+
}), reload({
|
|
7765
8711
|
client: client,
|
|
7766
8712
|
instanceId: instanceId,
|
|
7767
8713
|
tag: tag
|
|
7768
|
-
}), definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
8714
|
+
}) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7769
8715
|
client: client,
|
|
7770
8716
|
workflowResource: workflowResource,
|
|
7771
8717
|
resourceClients: resourceClients
|
|
7772
|
-
}), snapshot = await hydrateSnapshot({
|
|
8718
|
+
}), [snapshot, guards, resourceGrants] = await Promise.all([ hydrateSnapshot({
|
|
7773
8719
|
client: client,
|
|
7774
8720
|
clientForGdr: clientForGdr,
|
|
7775
8721
|
instance: instance
|
|
7776
|
-
}),
|
|
8722
|
+
}), verdictGuardsForInstance(client, instance._id), subjectResourceGrants({
|
|
7777
8723
|
clientForGdr: clientForGdr,
|
|
7778
8724
|
instance: instance
|
|
7779
|
-
});
|
|
8725
|
+
}) ]);
|
|
7780
8726
|
return evaluateFromSnapshot({
|
|
7781
8727
|
instance: instance,
|
|
7782
8728
|
definition: definition,
|
|
@@ -7785,6 +8731,9 @@ async function evaluateInstance(args) {
|
|
|
7785
8731
|
guards: guards,
|
|
7786
8732
|
now: now,
|
|
7787
8733
|
resourceGrants: resourceGrants,
|
|
8734
|
+
...localPrincipalId !== void 0 ? {
|
|
8735
|
+
localPrincipalId: localPrincipalId
|
|
8736
|
+
} : {},
|
|
7788
8737
|
...grants !== void 0 ? {
|
|
7789
8738
|
grants: grants
|
|
7790
8739
|
} : {}
|
|
@@ -7840,9 +8789,12 @@ async function evaluateFromSnapshot(args) {
|
|
|
7840
8789
|
definition: definition,
|
|
7841
8790
|
snapshot: snapshot,
|
|
7842
8791
|
now: now
|
|
7843
|
-
},
|
|
7844
|
-
instance: instance,
|
|
8792
|
+
}, anchorIdentity = lakePrincipalId({
|
|
7845
8793
|
actor: actor,
|
|
8794
|
+
localPrincipalId: args.localPrincipalId
|
|
8795
|
+
}), can = await advisoryCan({
|
|
8796
|
+
instance: instance,
|
|
8797
|
+
identity: anchorIdentity,
|
|
7846
8798
|
grants: grants
|
|
7847
8799
|
}), scope = await renderConditionScope(scopeSource, {
|
|
7848
8800
|
actor: actor,
|
|
@@ -7859,11 +8811,10 @@ async function evaluateFromSnapshot(args) {
|
|
|
7859
8811
|
activityName: activityName
|
|
7860
8812
|
})), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
|
|
7861
8813
|
instance: instance,
|
|
7862
|
-
|
|
8814
|
+
identity: anchorIdentity,
|
|
7863
8815
|
guards: args.guards
|
|
7864
8816
|
}), subjectDenials = await forecastSubjectDenials({
|
|
7865
8817
|
instance: instance,
|
|
7866
|
-
actor: actor,
|
|
7867
8818
|
snapshot: snapshot,
|
|
7868
8819
|
resourceGrants: args.resourceGrants
|
|
7869
8820
|
}), subjectPermissionReason = subjectDenials.length > 0 ? {
|
|
@@ -8007,20 +8958,20 @@ async function editPredicateInsight(args) {
|
|
|
8007
8958
|
}
|
|
8008
8959
|
|
|
8009
8960
|
async function forecastSubjectDenials(args) {
|
|
8010
|
-
const {instance: instance,
|
|
8961
|
+
const {instance: instance, snapshot: snapshot, resourceGrants: resourceGrants} = args;
|
|
8011
8962
|
if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
|
|
8012
8963
|
const denials = [], seen = /* @__PURE__ */ new Set;
|
|
8013
8964
|
for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
|
|
8014
8965
|
if (seen.has(ref.id)) continue;
|
|
8015
8966
|
seen.add(ref.id);
|
|
8016
|
-
const
|
|
8017
|
-
if (
|
|
8967
|
+
const access = resourceGrants.get(resourceGdr(resource));
|
|
8968
|
+
if (access === void 0) continue;
|
|
8018
8969
|
const doc = snapshot.docs.find(d => d._id === ref.id);
|
|
8019
8970
|
doc !== void 0 && await subjectUpdateAllowed({
|
|
8020
8971
|
doc: doc,
|
|
8021
8972
|
parsed: parsed,
|
|
8022
|
-
grants: grants,
|
|
8023
|
-
actorId:
|
|
8973
|
+
grants: access.grants,
|
|
8974
|
+
actorId: access.actorId
|
|
8024
8975
|
}) === !1 && denials.push({
|
|
8025
8976
|
subject: ref.id,
|
|
8026
8977
|
resource: resourceGdr(resource),
|
|
@@ -8101,12 +9052,12 @@ async function explainActivityConditions({activity: activity, activityScope: act
|
|
|
8101
9052
|
snapshot: snapshot,
|
|
8102
9053
|
sites: sites
|
|
8103
9054
|
}), requirementEntries = [];
|
|
8104
|
-
for (const
|
|
9055
|
+
for (const requirement of activity.requirements ?? []) requirementEntries.push([ requirement, await explainAt({
|
|
8105
9056
|
kind: "requirement",
|
|
8106
9057
|
activity: activity.name,
|
|
8107
|
-
requirement: name
|
|
8108
|
-
},
|
|
8109
|
-
const requirementInsights = Object.fromEntries(requirementEntries), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([
|
|
9058
|
+
requirement: requirement.name
|
|
9059
|
+
}, requirement.query) ]);
|
|
9060
|
+
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({
|
|
8110
9061
|
site: {
|
|
8111
9062
|
kind: "activity-filter",
|
|
8112
9063
|
activity: activity.name
|
|
@@ -8252,12 +9203,12 @@ function actionEvaluationIdentity(action) {
|
|
|
8252
9203
|
};
|
|
8253
9204
|
}
|
|
8254
9205
|
|
|
8255
|
-
async function instanceGuardReason({instance: instance,
|
|
9206
|
+
async function instanceGuardReason({instance: instance, identity: identity, guards: guards}) {
|
|
8256
9207
|
if (guards === void 0 || guards.length === 0) return;
|
|
8257
9208
|
const denied = await instanceWriteDenials({
|
|
8258
9209
|
instance: instance,
|
|
8259
9210
|
guards: guards,
|
|
8260
|
-
identity:
|
|
9211
|
+
identity: identity
|
|
8261
9212
|
});
|
|
8262
9213
|
if (denied.length !== 0) return {
|
|
8263
9214
|
kind: "mutation-guard-denied",
|
|
@@ -8296,24 +9247,24 @@ function inFlightFilter() {
|
|
|
8296
9247
|
return "!defined(completedAt)";
|
|
8297
9248
|
}
|
|
8298
9249
|
|
|
8299
|
-
const FIELD_REFS_DOC = "count(fields[value.id in $documents]) > 0 || count(fields[count(value[id in $documents]) > 0]) > 0",
|
|
9250
|
+
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";
|
|
8300
9251
|
|
|
8301
9252
|
function documentPrefilter(documents, params) {
|
|
8302
9253
|
for (const document of documents) if (!isGdrUri(document)) throw new ContractViolationError(`every document must be a resource-qualified GDR URI (e.g. "dataset:project:dataset:doc-id"); got: ${JSON.stringify(document)}`);
|
|
8303
9254
|
return params.documents = [ ...documents ], params.bareIds = documents.map(extractDocumentId),
|
|
8304
|
-
`_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${
|
|
9255
|
+
`_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${LIVE_SUBWORKFLOW_REFS_DOC} || ${FIELD_REFS_DOC} || ${OPEN_STAGE_REFS_DOC}`;
|
|
8305
9256
|
}
|
|
8306
9257
|
|
|
8307
9258
|
function documentArm(filter, params) {
|
|
8308
9259
|
if (filter.documents === void 0 && filter.document === void 0) return;
|
|
8309
|
-
const documents = [ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ];
|
|
9260
|
+
const documents = [ .../* @__PURE__ */ new Set([ ...filter.documents ?? [], ...filter.document !== void 0 ? [ filter.document ] : [] ]) ].sort();
|
|
8310
9261
|
return documentPrefilter(documents, params);
|
|
8311
9262
|
}
|
|
8312
9263
|
|
|
8313
9264
|
function idsArm(filter, params) {
|
|
8314
9265
|
if (filter.ids !== void 0) {
|
|
8315
9266
|
for (const id of filter.ids) if (isGdrUri(id)) throw new 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)}`);
|
|
8316
|
-
return params.ids = [ ...filter.ids ], "_id in $ids";
|
|
9267
|
+
return params.ids = [ ...new Set(filter.ids) ].sort(), "_id in $ids";
|
|
8317
9268
|
}
|
|
8318
9269
|
}
|
|
8319
9270
|
|
|
@@ -8727,11 +9678,10 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
|
|
|
8727
9678
|
}
|
|
8728
9679
|
|
|
8729
9680
|
async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
|
|
8730
|
-
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can =
|
|
9681
|
+
const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
|
|
8731
9682
|
instance: ctx.instance,
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
}) : void 0, predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
|
|
9683
|
+
options: options
|
|
9684
|
+
}), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
|
|
8735
9685
|
ctx: ctx,
|
|
8736
9686
|
condition: site.effective,
|
|
8737
9687
|
opts: {
|
|
@@ -9089,8 +10039,7 @@ async function abortAndPropagate(args) {
|
|
|
9089
10039
|
executionContext: executionContext,
|
|
9090
10040
|
telemetry: telemetry
|
|
9091
10041
|
})
|
|
9092
|
-
})
|
|
9093
|
-
return await drainCondemnedChildren({
|
|
10042
|
+
}), drained = await drainCondemnedChildren({
|
|
9094
10043
|
client: client,
|
|
9095
10044
|
instanceId: instanceId,
|
|
9096
10045
|
actor: actor,
|
|
@@ -9102,8 +10051,12 @@ async function abortAndPropagate(args) {
|
|
|
9102
10051
|
} : {},
|
|
9103
10052
|
...telemetry !== void 0 ? {
|
|
9104
10053
|
telemetry: telemetry
|
|
10054
|
+
} : {},
|
|
10055
|
+
...result.fired ? {
|
|
10056
|
+
instance: result.instance
|
|
9105
10057
|
} : {}
|
|
9106
|
-
})
|
|
10058
|
+
});
|
|
10059
|
+
return await propagateToAncestors({
|
|
9107
10060
|
client: client,
|
|
9108
10061
|
instanceId: instanceId,
|
|
9109
10062
|
actor: actor,
|
|
@@ -9115,6 +10068,9 @@ async function abortAndPropagate(args) {
|
|
|
9115
10068
|
} : {},
|
|
9116
10069
|
...telemetry !== void 0 ? {
|
|
9117
10070
|
telemetry: telemetry
|
|
10071
|
+
} : {},
|
|
10072
|
+
...result.fired && !drained.drained ? {
|
|
10073
|
+
instance: drained.instance
|
|
9118
10074
|
} : {}
|
|
9119
10075
|
}), result.fired;
|
|
9120
10076
|
}
|
|
@@ -9222,6 +10178,9 @@ function buildEngineCallOptions(args) {
|
|
|
9222
10178
|
actor: args.actor,
|
|
9223
10179
|
clientForGdr: args.clientForGdr,
|
|
9224
10180
|
refSurface: args.refSurface,
|
|
10181
|
+
...args.localPrincipalId !== void 0 ? {
|
|
10182
|
+
localPrincipalId: args.localPrincipalId
|
|
10183
|
+
} : {},
|
|
9225
10184
|
...args.grants !== void 0 ? {
|
|
9226
10185
|
grants: args.grants
|
|
9227
10186
|
} : {},
|
|
@@ -9363,6 +10322,15 @@ async function abortInstances(args) {
|
|
|
9363
10322
|
return aborted;
|
|
9364
10323
|
}
|
|
9365
10324
|
|
|
10325
|
+
function projectStartSliceRow(instance) {
|
|
10326
|
+
const subject = (instance.fields ?? []).find(field => field._type === "subject")?.value;
|
|
10327
|
+
return {
|
|
10328
|
+
definition: instance.definition,
|
|
10329
|
+
subject: typeof subject == "object" && subject !== null && "id" in subject && isGdrUri(subject.id) ? subject.id : null,
|
|
10330
|
+
completedAt: instance.completedAt ?? null
|
|
10331
|
+
};
|
|
10332
|
+
}
|
|
10333
|
+
|
|
9366
10334
|
async function fetchStartSlice(args) {
|
|
9367
10335
|
const {client: client, tag: tag} = args, {query: query, params: params} = instancesQuery({
|
|
9368
10336
|
tag: tag,
|
|
@@ -9370,7 +10338,7 @@ async function fetchStartSlice(args) {
|
|
|
9370
10338
|
includeCompleted: !0
|
|
9371
10339
|
}
|
|
9372
10340
|
});
|
|
9373
|
-
return (await client.fetch(query, params)).map(assertReadableModel);
|
|
10341
|
+
return (await client.fetch(query, params)).map(assertReadableModel).map(projectStartSliceRow);
|
|
9374
10342
|
}
|
|
9375
10343
|
|
|
9376
10344
|
const workflow = {
|
|
@@ -9519,6 +10487,9 @@ const workflow = {
|
|
|
9519
10487
|
...access.grants !== void 0 ? {
|
|
9520
10488
|
grants: access.grants
|
|
9521
10489
|
} : {},
|
|
10490
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10491
|
+
localPrincipalId: access.localPrincipalId
|
|
10492
|
+
} : {},
|
|
9522
10493
|
clock: clock,
|
|
9523
10494
|
clientForGdr: clientForGdr,
|
|
9524
10495
|
refSurface: refSurface,
|
|
@@ -9587,6 +10558,9 @@ const workflow = {
|
|
|
9587
10558
|
...access.grants !== void 0 ? {
|
|
9588
10559
|
grants: access.grants
|
|
9589
10560
|
} : {},
|
|
10561
|
+
...access.localPrincipalId !== void 0 ? {
|
|
10562
|
+
localPrincipalId: access.localPrincipalId
|
|
10563
|
+
} : {},
|
|
9590
10564
|
clock: clock,
|
|
9591
10565
|
clientForGdr: clientForGdr,
|
|
9592
10566
|
refSurface: refSurface,
|
|
@@ -9746,7 +10720,7 @@ const workflow = {
|
|
|
9746
10720
|
});
|
|
9747
10721
|
},
|
|
9748
10722
|
tick: async rawArgs => {
|
|
9749
|
-
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({
|
|
10723
|
+
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({
|
|
9750
10724
|
client: client,
|
|
9751
10725
|
instanceId: instanceId,
|
|
9752
10726
|
tag: tag
|
|
@@ -9754,7 +10728,7 @@ const workflow = {
|
|
|
9754
10728
|
await assertInstanceWriteAllowed({
|
|
9755
10729
|
instance: current,
|
|
9756
10730
|
guards: guards,
|
|
9757
|
-
identity:
|
|
10731
|
+
identity: lakePrincipalId(access)
|
|
9758
10732
|
});
|
|
9759
10733
|
const {cascaded: cascaded, instance: instance} = await cascadeAndReload({
|
|
9760
10734
|
client: client,
|
|
@@ -9871,6 +10845,59 @@ const workflow = {
|
|
|
9871
10845
|
}
|
|
9872
10846
|
});
|
|
9873
10847
|
},
|
|
10848
|
+
resetActivity: async rawArgs => {
|
|
10849
|
+
const args = taggedScope(rawArgs, REQUEST_TAG.resetActivity), {client: client, tag: tag, instanceId: instanceId, activity: activity, executionContext: executionContext} = args, to = args.to ?? "active";
|
|
10850
|
+
if (!isResetActivityTarget(to)) throw new ContractViolationError(`resetActivity: "to" must be "active" or "skipped"; got ${JSON.stringify(args.to)}`);
|
|
10851
|
+
return runCommitVerb({
|
|
10852
|
+
args: args,
|
|
10853
|
+
op: "resetActivity",
|
|
10854
|
+
run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
|
|
10855
|
+
const result = await resetActivity({
|
|
10856
|
+
client: client,
|
|
10857
|
+
instanceId: instanceId,
|
|
10858
|
+
activity: activity,
|
|
10859
|
+
to: to,
|
|
10860
|
+
...record !== void 0 ? {
|
|
10861
|
+
requestRecord: record
|
|
10862
|
+
} : {},
|
|
10863
|
+
options: engineOptionsForActor({
|
|
10864
|
+
actor: actor,
|
|
10865
|
+
clock: clock,
|
|
10866
|
+
clientForGdr: clientForGdr,
|
|
10867
|
+
refSurface: refSurface,
|
|
10868
|
+
executionContext: executionContext,
|
|
10869
|
+
telemetry: args.telemetry
|
|
10870
|
+
})
|
|
10871
|
+
}), cascaded = result.fired ? await cascade({
|
|
10872
|
+
client: client,
|
|
10873
|
+
instanceId: instanceId,
|
|
10874
|
+
actor: actor,
|
|
10875
|
+
clientForGdr: clientForGdr,
|
|
10876
|
+
refSurface: refSurface,
|
|
10877
|
+
clock: clock,
|
|
10878
|
+
...executionContext !== void 0 ? {
|
|
10879
|
+
executionContext: executionContext
|
|
10880
|
+
} : {},
|
|
10881
|
+
...args.telemetry !== void 0 ? {
|
|
10882
|
+
telemetry: args.telemetry
|
|
10883
|
+
} : {}
|
|
10884
|
+
}) : 0;
|
|
10885
|
+
return resolveTelemetry(args.telemetry).log(WorkflowActivityReset, {
|
|
10886
|
+
...definitionHashFragment(before.pinnedContentHash),
|
|
10887
|
+
instanceId: instanceId,
|
|
10888
|
+
changed: result.fired
|
|
10889
|
+
}), {
|
|
10890
|
+
instance: await reload({
|
|
10891
|
+
client: client,
|
|
10892
|
+
instanceId: instanceId,
|
|
10893
|
+
tag: tag
|
|
10894
|
+
}),
|
|
10895
|
+
cascaded: cascaded,
|
|
10896
|
+
changed: result.fired
|
|
10897
|
+
};
|
|
10898
|
+
}
|
|
10899
|
+
});
|
|
10900
|
+
},
|
|
9874
10901
|
getInstance: async rawArgs => {
|
|
9875
10902
|
const args = taggedScope(rawArgs, REQUEST_TAG.getInstance), {client: client, tag: tag, instanceId: instanceId} = args;
|
|
9876
10903
|
return validateTag(tag), reload({
|
|
@@ -10017,21 +11044,18 @@ const workflow = {
|
|
|
10017
11044
|
return (await client.fetch(query, params)).map(readInstanceDoc).filter(instance => instanceWatchesDocument(instance, document));
|
|
10018
11045
|
},
|
|
10019
11046
|
definitionsForDocument: async rawArgs => {
|
|
10020
|
-
const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document
|
|
11047
|
+
const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document} = args;
|
|
10021
11048
|
validateTag(tag);
|
|
10022
|
-
const clock = args.clock ?? wallClock, deployed = (await client.fetch(
|
|
11049
|
+
const clock = args.clock ?? wallClock, deployed = (await client.fetch(latestDefinitionsGroq(), {
|
|
10023
11050
|
tag: tag
|
|
10024
|
-
})).map(assertReadableModel)
|
|
11051
|
+
})).map(assertReadableModel);
|
|
10025
11052
|
let slice;
|
|
10026
11053
|
return applicableDefinitions({
|
|
10027
|
-
definitions:
|
|
11054
|
+
definitions: deployed,
|
|
10028
11055
|
document: document,
|
|
10029
11056
|
scope: {
|
|
10030
11057
|
tag: tag,
|
|
10031
11058
|
now: clock(),
|
|
10032
|
-
...subject !== void 0 ? {
|
|
10033
|
-
subject: subject
|
|
10034
|
-
} : {},
|
|
10035
11059
|
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10036
11060
|
client: client,
|
|
10037
11061
|
tag: tag
|
|
@@ -10054,34 +11078,17 @@ const workflow = {
|
|
|
10054
11078
|
}), missingRequired = missingRequiredInputs({
|
|
10055
11079
|
entryDefs: definition.fields ?? [],
|
|
10056
11080
|
initialFields: initialFields ?? []
|
|
10057
|
-
}),
|
|
10058
|
-
if (allowed === void 0) return {
|
|
10059
|
-
allowed: invalidInitialFields.length === 0,
|
|
10060
|
-
outcome: "satisfied",
|
|
10061
|
-
unboundReads: [],
|
|
10062
|
-
missingRequired: missingRequired,
|
|
10063
|
-
invalidInitialFields: invalidInitialFields
|
|
10064
|
-
};
|
|
10065
|
-
const unboundReads = unboundAllowedReadsWithSubject({
|
|
10066
|
-
allowed: allowed,
|
|
10067
|
-
fields: startFieldsParam({
|
|
10068
|
-
entryDefs: definition.fields ?? [],
|
|
10069
|
-
initialFields: initialFields ?? []
|
|
10070
|
-
}),
|
|
10071
|
-
definition: definition
|
|
10072
|
-
}), insight = await startAllowedInsight({
|
|
11081
|
+
}), verdict = await startRequirementVerdict({
|
|
10073
11082
|
client: client,
|
|
10074
11083
|
tag: tag,
|
|
10075
11084
|
definition: definition,
|
|
10076
|
-
allowed: allowed,
|
|
10077
11085
|
initialFields: initialFields ?? [],
|
|
10078
|
-
now: clock()
|
|
10079
|
-
|
|
11086
|
+
now: clock(),
|
|
11087
|
+
preflight: !0
|
|
11088
|
+
});
|
|
10080
11089
|
return {
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
insight: insight,
|
|
10084
|
-
unboundReads: unboundReads,
|
|
11090
|
+
...verdict,
|
|
11091
|
+
allowed: invalidInitialFields.length === 0 && verdict.allowed,
|
|
10085
11092
|
missingRequired: missingRequired,
|
|
10086
11093
|
invalidInitialFields: invalidInitialFields
|
|
10087
11094
|
};
|
|
@@ -10093,11 +11100,10 @@ const workflow = {
|
|
|
10093
11100
|
}
|
|
10094
11101
|
};
|
|
10095
11102
|
|
|
10096
|
-
|
|
10097
|
-
const {client: client, tag: tag, definition: definition,
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
definition: definition,
|
|
11103
|
+
function startPredicateContext(args) {
|
|
11104
|
+
const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now} = args;
|
|
11105
|
+
let slice;
|
|
11106
|
+
return {
|
|
10101
11107
|
fields: startFieldsParam({
|
|
10102
11108
|
entryDefs: definition.fields ?? [],
|
|
10103
11109
|
initialFields: initialFields
|
|
@@ -10105,12 +11111,71 @@ async function startAllowedInsight(args) {
|
|
|
10105
11111
|
scope: {
|
|
10106
11112
|
tag: tag,
|
|
10107
11113
|
now: now,
|
|
10108
|
-
fetchDataset: () => fetchStartSlice({
|
|
11114
|
+
fetchDataset: () => slice ??= fetchStartSlice({
|
|
10109
11115
|
client: client,
|
|
10110
11116
|
tag: tag
|
|
10111
11117
|
})
|
|
10112
11118
|
}
|
|
10113
|
-
}
|
|
11119
|
+
};
|
|
11120
|
+
}
|
|
11121
|
+
|
|
11122
|
+
async function startRequirementVerdict(args) {
|
|
11123
|
+
const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now, preflight: preflight = !1} = args, declared = definition.start?.requirements ?? [];
|
|
11124
|
+
if (declared.length === 0) return {
|
|
11125
|
+
allowed: !0,
|
|
11126
|
+
outcome: "satisfied",
|
|
11127
|
+
requirements: [],
|
|
11128
|
+
unboundReads: []
|
|
11129
|
+
};
|
|
11130
|
+
const {fields: fields, scope: scope} = startPredicateContext({
|
|
11131
|
+
client: client,
|
|
11132
|
+
tag: tag,
|
|
11133
|
+
definition: definition,
|
|
11134
|
+
initialFields: initialFields,
|
|
11135
|
+
now: now
|
|
11136
|
+
}), subjectEntry = (definition.fields ?? []).find(isSubjectEntry)?.name, requirements = [], unbound = /* @__PURE__ */ new Set;
|
|
11137
|
+
for (const requirement of declared) {
|
|
11138
|
+
const descriptor = requirementDescriptor(requirement);
|
|
11139
|
+
if (requirement.type === "singleSubject") {
|
|
11140
|
+
if (preflight && subjectEntry !== void 0 && !Object.hasOwn(fields, subjectEntry)) unbound.add(subjectEntry),
|
|
11141
|
+
requirements.push({
|
|
11142
|
+
...descriptor,
|
|
11143
|
+
outcome: "unevaluable"
|
|
11144
|
+
}); else {
|
|
11145
|
+
const refused = await singleSubjectRequirementRefused({
|
|
11146
|
+
definition: definition,
|
|
11147
|
+
fields: fields,
|
|
11148
|
+
scope: scope
|
|
11149
|
+
});
|
|
11150
|
+
requirements.push({
|
|
11151
|
+
...descriptor,
|
|
11152
|
+
outcome: refused ? "unsatisfied" : "satisfied"
|
|
11153
|
+
});
|
|
11154
|
+
}
|
|
11155
|
+
continue;
|
|
11156
|
+
}
|
|
11157
|
+
const missing = unboundRequirementReads(requirement.query, fields);
|
|
11158
|
+
missing.forEach(name => unbound.add(name));
|
|
11159
|
+
const insight = await explainStartRequirement({
|
|
11160
|
+
query: requirement.query,
|
|
11161
|
+
definition: definition,
|
|
11162
|
+
fields: fields,
|
|
11163
|
+
scope: scope
|
|
11164
|
+
});
|
|
11165
|
+
requirements.push({
|
|
11166
|
+
...descriptor,
|
|
11167
|
+
outcome: preflight && missing.length > 0 ? "unevaluable" : insight.outcome,
|
|
11168
|
+
insight: insight
|
|
11169
|
+
});
|
|
11170
|
+
}
|
|
11171
|
+
let outcome = "satisfied";
|
|
11172
|
+
return requirements.some(requirement => requirement.outcome === "unsatisfied") ? outcome = "unsatisfied" : requirements.some(requirement => requirement.outcome === "unevaluable") && (outcome = "unevaluable"),
|
|
11173
|
+
{
|
|
11174
|
+
allowed: outcome === "satisfied",
|
|
11175
|
+
outcome: outcome,
|
|
11176
|
+
requirements: requirements,
|
|
11177
|
+
unboundReads: [ ...unbound ]
|
|
11178
|
+
};
|
|
10114
11179
|
}
|
|
10115
11180
|
|
|
10116
11181
|
async function startFreshInstance(args) {
|
|
@@ -10210,19 +11275,16 @@ async function assertStartInputs(args) {
|
|
|
10210
11275
|
initialFields: initialFields,
|
|
10211
11276
|
definitionName: definition.name
|
|
10212
11277
|
});
|
|
10213
|
-
const
|
|
10214
|
-
if (allowed === void 0) return;
|
|
10215
|
-
const insight = await startAllowedInsight({
|
|
11278
|
+
const unmetRequirements = (await startRequirementVerdict({
|
|
10216
11279
|
client: client,
|
|
10217
11280
|
tag: tag,
|
|
10218
11281
|
definition: definition,
|
|
10219
|
-
allowed: allowed,
|
|
10220
11282
|
initialFields: initialFields,
|
|
10221
11283
|
now: now
|
|
10222
|
-
});
|
|
10223
|
-
if (
|
|
11284
|
+
})).requirements.filter(requirement => requirement.outcome !== "satisfied").map(requirementDescriptor);
|
|
11285
|
+
if (unmetRequirements.length > 0) throw new StartNotAllowedError({
|
|
10224
11286
|
definition: definition.name,
|
|
10225
|
-
|
|
11287
|
+
unmetRequirements: unmetRequirements
|
|
10226
11288
|
});
|
|
10227
11289
|
}
|
|
10228
11290
|
|
|
@@ -10255,97 +11317,6 @@ async function resolveStartFields(args) {
|
|
|
10255
11317
|
};
|
|
10256
11318
|
}
|
|
10257
11319
|
|
|
10258
|
-
function isRecord(value) {
|
|
10259
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
10260
|
-
}
|
|
10261
|
-
|
|
10262
|
-
function isClientProjectUser(value) {
|
|
10263
|
-
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");
|
|
10264
|
-
}
|
|
10265
|
-
|
|
10266
|
-
function objectProperty(value, property) {
|
|
10267
|
-
if (!isRecord(value)) return;
|
|
10268
|
-
const propertyValue = value[property];
|
|
10269
|
-
return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
|
|
10270
|
-
}
|
|
10271
|
-
|
|
10272
|
-
function stringProperty(value, property) {
|
|
10273
|
-
const propertyValue = Reflect.get(value, property);
|
|
10274
|
-
return typeof propertyValue == "string" ? propertyValue : void 0;
|
|
10275
|
-
}
|
|
10276
|
-
|
|
10277
|
-
function apiErrorType(error) {
|
|
10278
|
-
const response = objectProperty(error, "response"), body = objectProperty(response, "body");
|
|
10279
|
-
if (!body) return;
|
|
10280
|
-
const nestedError = objectProperty(body, "error");
|
|
10281
|
-
return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
|
|
10282
|
-
}
|
|
10283
|
-
|
|
10284
|
-
function isProjectUserNotFoundError(error) {
|
|
10285
|
-
return apiErrorType(error) === "projectUserNotFoundError";
|
|
10286
|
-
}
|
|
10287
|
-
|
|
10288
|
-
function clientProjectUserDirectory(client, projectId) {
|
|
10289
|
-
return {
|
|
10290
|
-
findById: async id => {
|
|
10291
|
-
if (!client.request) return {
|
|
10292
|
-
status: "inaccessible",
|
|
10293
|
-
cause: new Error("Project-user resolution requires WorkflowClient.request")
|
|
10294
|
-
};
|
|
10295
|
-
try {
|
|
10296
|
-
const response = await client.request({
|
|
10297
|
-
uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
|
|
10298
|
-
}), candidate = Array.isArray(response) ? response[0] : response;
|
|
10299
|
-
return candidate == null ? {
|
|
10300
|
-
status: "missing"
|
|
10301
|
-
} : isClientProjectUser(candidate) ? {
|
|
10302
|
-
status: "resolved",
|
|
10303
|
-
user: candidate
|
|
10304
|
-
} : {
|
|
10305
|
-
status: "inaccessible",
|
|
10306
|
-
cause: new Error("Project-user response had an invalid shape")
|
|
10307
|
-
};
|
|
10308
|
-
} catch (cause) {
|
|
10309
|
-
return isProjectUserNotFoundError(cause) ? {
|
|
10310
|
-
status: "missing"
|
|
10311
|
-
} : {
|
|
10312
|
-
status: "inaccessible",
|
|
10313
|
-
cause: cause
|
|
10314
|
-
};
|
|
10315
|
-
}
|
|
10316
|
-
}
|
|
10317
|
-
};
|
|
10318
|
-
}
|
|
10319
|
-
|
|
10320
|
-
function resolveClientActor(client, args) {
|
|
10321
|
-
return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
|
|
10322
|
-
}
|
|
10323
|
-
|
|
10324
|
-
async function resolveActor(directory, actor) {
|
|
10325
|
-
if (actor.kind !== "person") return {
|
|
10326
|
-
status: "not-person",
|
|
10327
|
-
actor: actor
|
|
10328
|
-
};
|
|
10329
|
-
const personActor = {
|
|
10330
|
-
...actor,
|
|
10331
|
-
kind: "person"
|
|
10332
|
-
}, lookup = await directory.findById(personActor.id);
|
|
10333
|
-
return lookup.status === "resolved" ? {
|
|
10334
|
-
status: "resolved",
|
|
10335
|
-
actor: personActor,
|
|
10336
|
-
user: lookup.user
|
|
10337
|
-
} : lookup.status === "inaccessible" ? {
|
|
10338
|
-
status: "inaccessible",
|
|
10339
|
-
actor: personActor,
|
|
10340
|
-
...lookup.cause === void 0 ? {} : {
|
|
10341
|
-
cause: lookup.cause
|
|
10342
|
-
}
|
|
10343
|
-
} : {
|
|
10344
|
-
status: "missing",
|
|
10345
|
-
actor: personActor
|
|
10346
|
-
};
|
|
10347
|
-
}
|
|
10348
|
-
|
|
10349
11320
|
const EFFECT_COMMIT_QUEUE_DEPTH = 32, EFFECT_COMMIT_DISPATCH_CAP = 200;
|
|
10350
11321
|
|
|
10351
11322
|
class EffectCommitQueueOverflowError extends WorkflowError {
|
|
@@ -10524,7 +11495,7 @@ function isCancelledCompletion(data) {
|
|
|
10524
11495
|
}
|
|
10525
11496
|
|
|
10526
11497
|
async function drainEffectsInternal(args) {
|
|
10527
|
-
const {tag: tag, workflowResource: workflowResource, instanceId: instanceId, effectHandlers: effectHandlers, missingHandler: missingHandler, logger: logger, handlerClient:
|
|
11498
|
+
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({
|
|
10528
11499
|
client: handlerClient,
|
|
10529
11500
|
workflowResource: workflowResource,
|
|
10530
11501
|
resourceClients: handlerResourceClients
|
|
@@ -10890,22 +11861,30 @@ function createInstanceSession(args) {
|
|
|
10890
11861
|
}, tickScope = opScope(REQUEST_TAG.tick), fireScope = opScope(REQUEST_TAG.fireAction), editScope = opScope(REQUEST_TAG.editField), evalScope = opScope(REQUEST_TAG.evaluate);
|
|
10891
11862
|
let overlay = /* @__PURE__ */ new Map;
|
|
10892
11863
|
const previews = /* @__PURE__ */ new Map;
|
|
10893
|
-
let heldGuards = [], committing = !1, buffered
|
|
10894
|
-
const
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
11864
|
+
let heldGuards = [], committing = !1, buffered;
|
|
11865
|
+
const bufferedDocuments = /* @__PURE__ */ new Map;
|
|
11866
|
+
let deferredUpdateError;
|
|
11867
|
+
const flushDeferredError = () => {
|
|
11868
|
+
if (deferredUpdateError === void 0) return;
|
|
11869
|
+
const failure = deferredUpdateError;
|
|
11870
|
+
throw deferredUpdateError = void 0, failure;
|
|
11871
|
+
}, selfUri = () => gdrFromResource(instance.workflowResource, instance._id), applyDocument = (ld, target) => {
|
|
11872
|
+
const owned = {
|
|
11873
|
+
doc: structuredClone(ld.doc),
|
|
11874
|
+
resource: ld.resource
|
|
11875
|
+
}, uri = gdrFromResource(owned.resource, owned.doc._id);
|
|
11876
|
+
if (uri === selfUri()) {
|
|
11877
|
+
const rawStamp = owned.doc._updatedAt;
|
|
11878
|
+
!isParseableInstant(rawStamp) || owned.doc._type !== WORKFLOW_INSTANCE_TYPE ? asHeldInstance(owned.doc) : Date.parse(rawStamp) > Date.parse(instance._updatedAt) && (instance = asHeldInstance(owned.doc));
|
|
11879
|
+
return;
|
|
10907
11880
|
}
|
|
11881
|
+
target.set(uri, owned);
|
|
11882
|
+
}, applyUpdate = docs => {
|
|
11883
|
+
const next = /* @__PURE__ */ new Map;
|
|
11884
|
+
for (const ld of docs) applyDocument(ld, next);
|
|
10908
11885
|
overlay = next;
|
|
11886
|
+
}, applyDocumentUpdate = doc => {
|
|
11887
|
+
applyDocument(doc, overlay);
|
|
10909
11888
|
}, access = () => resolveAccess(client, {
|
|
10910
11889
|
...args.grantsFromPath !== void 0 ? {
|
|
10911
11890
|
grantsFromPath: args.grantsFromPath
|
|
@@ -10963,17 +11942,23 @@ function createInstanceSession(args) {
|
|
|
10963
11942
|
refSurface: evalScope.refSurface
|
|
10964
11943
|
});
|
|
10965
11944
|
}, evaluateWith = async ({held: held, guards: guards, self: self}) => {
|
|
10966
|
-
const {actor: actor, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
11945
|
+
const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
|
|
10967
11946
|
clientForGdr: evalScope.clientForGdr,
|
|
10968
11947
|
instance: instance
|
|
11948
|
+
}), normalizedSelf = await normalizeInstanceIdentities({
|
|
11949
|
+
client: evalScope.client,
|
|
11950
|
+
instance: self
|
|
10969
11951
|
});
|
|
10970
11952
|
return evaluateFromSnapshot({
|
|
10971
|
-
instance:
|
|
11953
|
+
instance: normalizedSelf,
|
|
10972
11954
|
definition: definitionOf(),
|
|
10973
11955
|
actor: actor,
|
|
10974
|
-
snapshot: snapshotFrom(held,
|
|
11956
|
+
snapshot: snapshotFrom(held, normalizedSelf),
|
|
10975
11957
|
guards: guards,
|
|
10976
11958
|
resourceGrants: resourceGrants,
|
|
11959
|
+
...localPrincipalId !== void 0 ? {
|
|
11960
|
+
localPrincipalId: localPrincipalId
|
|
11961
|
+
} : {},
|
|
10977
11962
|
...clock !== void 0 ? {
|
|
10978
11963
|
now: clock()
|
|
10979
11964
|
} : {},
|
|
@@ -11019,8 +12004,13 @@ function createInstanceSession(args) {
|
|
|
11019
12004
|
committing = !0;
|
|
11020
12005
|
const held = new Map(overlay);
|
|
11021
12006
|
try {
|
|
11022
|
-
const {actor: actor} = await access();
|
|
11023
|
-
return await run(
|
|
12007
|
+
const {actor: actor, localPrincipalId: localPrincipalId} = await access();
|
|
12008
|
+
return await run({
|
|
12009
|
+
actor: actor,
|
|
12010
|
+
...localPrincipalId !== void 0 ? {
|
|
12011
|
+
localPrincipalId: localPrincipalId
|
|
12012
|
+
} : {}
|
|
12013
|
+
}, held);
|
|
11024
12014
|
} finally {
|
|
11025
12015
|
if (committing = !1, buffered !== void 0) {
|
|
11026
12016
|
const next = buffered;
|
|
@@ -11031,6 +12021,12 @@ function createInstanceSession(args) {
|
|
|
11031
12021
|
deferredUpdateError = err;
|
|
11032
12022
|
}
|
|
11033
12023
|
}
|
|
12024
|
+
for (const next of bufferedDocuments.values()) try {
|
|
12025
|
+
applyDocumentUpdate(next);
|
|
12026
|
+
} catch (err) {
|
|
12027
|
+
deferredUpdateError = err;
|
|
12028
|
+
}
|
|
12029
|
+
bufferedDocuments.clear();
|
|
11034
12030
|
}
|
|
11035
12031
|
};
|
|
11036
12032
|
return {
|
|
@@ -11038,15 +12034,26 @@ function createInstanceSession(args) {
|
|
|
11038
12034
|
return subscriptionDocumentsForInstance(instance);
|
|
11039
12035
|
},
|
|
11040
12036
|
update(docs) {
|
|
11041
|
-
if (committing) buffered = docs; else try {
|
|
12037
|
+
if (committing) buffered = docs, bufferedDocuments.clear(); else try {
|
|
11042
12038
|
applyUpdate(docs);
|
|
11043
12039
|
} catch (err) {
|
|
11044
12040
|
throw deferredUpdateError = void 0, err;
|
|
11045
12041
|
}
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
12042
|
+
flushDeferredError();
|
|
12043
|
+
},
|
|
12044
|
+
updateDocument(doc) {
|
|
12045
|
+
if (committing) {
|
|
12046
|
+
const uri = gdrFromResource(doc.resource, doc.doc._id);
|
|
12047
|
+
bufferedDocuments.set(uri, {
|
|
12048
|
+
doc: structuredClone(doc.doc),
|
|
12049
|
+
resource: doc.resource
|
|
12050
|
+
});
|
|
12051
|
+
} else try {
|
|
12052
|
+
applyDocumentUpdate(doc);
|
|
12053
|
+
} catch (err) {
|
|
12054
|
+
throw deferredUpdateError = void 0, err;
|
|
11049
12055
|
}
|
|
12056
|
+
flushDeferredError();
|
|
11050
12057
|
},
|
|
11051
12058
|
updateGuards(guards) {
|
|
11052
12059
|
heldGuards = guards.map(guard => parseGuardDocument(structuredClone(guard)));
|
|
@@ -11078,11 +12085,14 @@ function createInstanceSession(args) {
|
|
|
11078
12085
|
site !== void 0 && previews.delete(siteKey(site));
|
|
11079
12086
|
},
|
|
11080
12087
|
tick() {
|
|
11081
|
-
return commit(async (actor, held) => {
|
|
12088
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11082
12089
|
await assertInstanceWriteAllowed({
|
|
11083
12090
|
instance: instance,
|
|
11084
12091
|
guards: heldGuards,
|
|
11085
|
-
identity:
|
|
12092
|
+
identity: lakePrincipalId({
|
|
12093
|
+
actor: actor,
|
|
12094
|
+
localPrincipalId: localPrincipalId
|
|
12095
|
+
})
|
|
11086
12096
|
});
|
|
11087
12097
|
const before = await reload({
|
|
11088
12098
|
client: tickScope.client,
|
|
@@ -11109,7 +12119,7 @@ function createInstanceSession(args) {
|
|
|
11109
12119
|
});
|
|
11110
12120
|
},
|
|
11111
12121
|
fireAction({activity: activity, action: action, params: params}) {
|
|
11112
|
-
return commit(async (actor, held) => {
|
|
12122
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11113
12123
|
assertActionAllowed({
|
|
11114
12124
|
evaluation: await evaluateWith({
|
|
11115
12125
|
held: held,
|
|
@@ -11125,6 +12135,9 @@ function createInstanceSession(args) {
|
|
|
11125
12135
|
activity: activity,
|
|
11126
12136
|
action: action,
|
|
11127
12137
|
actor: actor,
|
|
12138
|
+
...localPrincipalId !== void 0 ? {
|
|
12139
|
+
localPrincipalId: localPrincipalId
|
|
12140
|
+
} : {},
|
|
11128
12141
|
clientForGdr: fireScope.clientForGdr,
|
|
11129
12142
|
refSurface: fireScope.refSurface,
|
|
11130
12143
|
...grants !== void 0 ? {
|
|
@@ -11167,7 +12180,7 @@ function createInstanceSession(args) {
|
|
|
11167
12180
|
} catch (err) {
|
|
11168
12181
|
return Promise.reject(err);
|
|
11169
12182
|
}
|
|
11170
|
-
return commit(async (actor, held) => {
|
|
12183
|
+
return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
|
|
11171
12184
|
assertEditAllowed(await evaluateWith({
|
|
11172
12185
|
held: held,
|
|
11173
12186
|
guards: heldGuards,
|
|
@@ -11184,6 +12197,9 @@ function createInstanceSession(args) {
|
|
|
11184
12197
|
value: value
|
|
11185
12198
|
} : {},
|
|
11186
12199
|
actor: actor,
|
|
12200
|
+
...localPrincipalId !== void 0 ? {
|
|
12201
|
+
localPrincipalId: localPrincipalId
|
|
12202
|
+
} : {},
|
|
11187
12203
|
clientForGdr: editScope.clientForGdr,
|
|
11188
12204
|
refSurface: editScope.refSurface,
|
|
11189
12205
|
...grants !== void 0 ? {
|
|
@@ -11294,6 +12310,7 @@ function createEngine(args) {
|
|
|
11294
12310
|
availableActions: rest => workflow.availableActions(withScope(rest)),
|
|
11295
12311
|
setStage: rest => workflow.setStage(withScope(rest)),
|
|
11296
12312
|
abortInstance: rest => workflow.abortInstance(withScope(rest)),
|
|
12313
|
+
resetActivity: rest => workflow.resetActivity(withScope(rest)),
|
|
11297
12314
|
deleteDefinition: rest => workflow.deleteDefinition(withScope(rest)),
|
|
11298
12315
|
getInstance: rest => workflow.getInstance(withScope(rest)),
|
|
11299
12316
|
subscriptionDocumentsForInstance: rest => workflow.getInstance(withScope(rest)).then(subscriptionDocumentsForInstance),
|
|
@@ -11860,4 +12877,4 @@ function displayDescription(typeKey) {
|
|
|
11860
12877
|
if (typeKey) return DISPLAY[typeKey]?.description;
|
|
11861
12878
|
}
|
|
11862
12879
|
|
|
11863
|
-
export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DRIVER_KINDS, DRIVER_KIND_DISPLAY, DefinitionInUseError, DefinitionNotFoundError, EFFECT_COMMIT_DISPATCH_CAP, EFFECT_COMMIT_QUEUE_DEPTH, ENGINE_API_VERSION, EXECUTION_KINDS, EXECUTOR_CLASSIFICATIONS, EXECUTOR_CLASSIFICATION_DISPLAY, EditFieldDeniedError, EffectCommitQueueOverflowError, EffectNotFoundError, EffectOpsInvalidError, EffectOutputsInvalidError, FIELD_KIND_DISPLAY, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GROUP_KIND_DISPLAY, GUARD_DOC_TYPE, GUARD_OWNER, GUARD_PREDICATE_VARS, HISTORY_DISPLAY, InitialFieldsInvalidError, InstanceNotFoundError, MAX_COUNTERFACTUAL_INDEX2 as MAX_COUNTERFACTUAL_INDEX, MissingHandlerError, ModelVersionAheadError, MutationGuardDeniedError, MutationGuardDocSchema, OP_DISPLAY, PartialGuardDeployError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, RefResourceUndeclaredError, RequiredFieldNotProvidedError,
|
|
12880
|
+
export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_KIND_DISPLAY, ACTOR_KINDS, ANONYMOUS_IDENTITY, AUTHORING_DISPLAY, ActionDisabledError, ActionParamsInvalidError, CONDITION_VARS, CONTEXT_ENTRY_DISPLAY, CascadeLimitError, ConcurrentCommitEffectOpsError, ConcurrentCompleteEffectError, ConcurrentEditFieldError, ConcurrentFireActionError, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_CONTENT_PERSPECTIVE, DEFAULT_EFFECT_LEASE_MS, DEFAULT_IDEMPOTENCY_TTL_MS, DEFAULT_TRANSITION_WHEN, DISPLAY, DRIVER_KINDS, DRIVER_KIND_DISPLAY, DefinitionInUseError, DefinitionNotFoundError, EFFECT_COMMIT_DISPATCH_CAP, EFFECT_COMMIT_QUEUE_DEPTH, ENGINE_API_VERSION, EXECUTION_KINDS, EXECUTOR_CLASSIFICATIONS, EXECUTOR_CLASSIFICATION_DISPLAY, EditFieldDeniedError, EffectCommitQueueOverflowError, EffectNotFoundError, EffectOpsInvalidError, EffectOutputsInvalidError, FIELD_KIND_DISPLAY, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GROUP_KIND_DISPLAY, GUARD_DOC_TYPE, GUARD_OWNER, GUARD_PREDICATE_VARS, HISTORY_DISPLAY, InitialFieldsInvalidError, InstanceNotFoundError, MAX_COUNTERFACTUAL_INDEX2 as MAX_COUNTERFACTUAL_INDEX, MissingHandlerError, ModelVersionAheadError, MutationGuardDeniedError, MutationGuardDocSchema, OP_DISPLAY, PartialGuardDeployError, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, ReaderModelAcknowledgementError, RefResourceUndeclaredError, RequiredFieldNotProvidedError, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StaleEffectClaimError, StartNotAllowedError, StartNotPrimedError, StartNotSettledError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowActionFired, WorkflowActivityReset, WorkflowDefinitionDeleted, WorkflowDefinitionDeployed, WorkflowEffectCompleted, WorkflowEffectStateReported, WorkflowEffectsDrained, WorkflowError, WorkflowFieldEdited, WorkflowInstanceAborted, WorkflowInstanceSchema, WorkflowInstanceStarted, WorkflowInstanceTicked, WorkflowStageSet, WorkflowStageTransitioned, WorkflowStateDivergedError, abortReason, acceptsDocumentType, aclPathForResource, actionDisabledDetail, actionRendering, actionVerdict, activityAutonomyOf, analyzeCondition2 as analyzeCondition, applicableDefinitions, assertReadableModel, assertReaderModelAcknowledgement, atomReadsDataset2 as atomReadsDataset, autonomySummary, availableActions, buildInitialFields, buildSnapshot, checklistLines, classifyPrincipalId, clientConfigFromResource, clientProjectUserDirectory, compileGuard, computeDiffEntries, conditionFieldReadNames, conditionSitesOf, contentDocQuery, contentDraftFallback, contentReleaseName, contextMap, createEngine, createTelemetryIntake, datasetResourceParts, defaultLoggerFactory, definitionDeployedData, definitionLookupGroq, definitionsListGroq, deniedGuardLabels, deniedGuardRefs, denyingGuards, deployStageGuards, deriveActivityKind, deriveExecutorClassification, deriveWorkflowAutonomy, describeAtom, describeAutonomyWait, describeCondition, describeDefinition, describeFieldInsight, describeNode, describeSite, describeSiteHeading, diagnoseInputFromEvaluation, diagnoseInstance, diffEntry, displayDescription, displayTitle, documentActionDenials, documentPrefilter, driverKind, effectOutputsMap, entryDocRefs, errorMessage, evaluateFromSnapshot, evaluateMutationGuard, evaluateStartFilter, expandResourceAliases, explainCondition2 as explainCondition, explainStartRequirement, extractDocumentId, fieldTreeShape, findCurrentActivityEntry, findOpenStageEntry, formatRead, gdrFromResource, gdrRef, gdrUri, groupMembershipNames, groupSitesOf, guardMatches, guardsForDefinition, guardsForInstance, guardsForResource, guillemets2 as guillemets, hasSingleSubjectRequirement, hashDefinitionContent, humanize2 as humanize, inFlightFilter, initialFieldIssues, instanceDocId, instanceGuardQuery, instanceWatchesDocument, instancesGuardQuery, instancesQuery, isCascadeFired, isClaimExpired, isClientProjectUser, isComparisonOp, isDefinitionApplicable, isFilterScopedOut, isGdr, isInputSourced, isNotesEntry, isProjectUserNotFoundError, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTelemetryEnvDenied, isTerminalActivityStatus, isTerminalStage, isTodoListEntry, isTodoListItem, isUnprimed, lakeGuardId, lakePrincipalId, latestDefinitionsGroq, latestDeployedDefinitions, lintEffectOutputs, minReaderModelOf, missingRequiredInputs, modelVersionOf, narrateAutonomyWaits, noopTelemetry, parentRef, parseDefinitionInput, parseDefinitionSnapshot, parseGdr, parseGuardDocument, parseInstanceDocument, parseResourceGdr, processShellUserProperties, projectStartSliceRow, projectToWatchRef, quoted2 as quoted, readInstanceDoc, readsRaw, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refsOf, rejectedRefTypes, releaseDocId, releaseRef, remediationsFor, requiredModelFeatures, requiredReaderModel, resolveAccess, resolveActor, resolveClientActor, resolveFieldEntry$1 as resolveFieldEntry, resourceAliasesToMap, resourceFromParsed, resourceGdr, retractStageGuards, sameResource, scalarValidationIssues, schemaTreeShape, sentenceCase, silentLogger, singleSubjectRequirementRefused, stageAutonomyOf, startFieldsParam, startKindOf, startRefusal, stripSystemFields, subjectDenialLabels, subscriptionDocument, subscriptionDocumentsForInstance, sweepStaleClaims, tagScopeFilter, terminalState, toBareId, tryParseGdr, unboundRequirementReads, unsatisfiedTransitionSummaries, validateDefinition, validateTag, verdictGuardsForInstance, wallClock, whatIfCondition2 as whatIfCondition, withAssignment, workflow };
|