@sanity/workflow-engine 0.18.0 → 0.19.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 +9 -0
- package/DATAMODEL.md +53 -0
- package/dist/_chunks-cjs/invariants.cjs +87 -17
- package/dist/_chunks-es/invariants.js +87 -17
- package/dist/define.d.cts +212 -4
- package/dist/define.d.ts +212 -4
- package/dist/index.cjs +2334 -1864
- package/dist/index.d.cts +455 -9
- package/dist/index.d.ts +455 -9
- package/dist/index.js +2313 -1855
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -262,6 +262,11 @@ const HIGH_FREQUENCY_SAMPLE_MS = 6e4, WorkflowDefinitionDeployed = defineWorkflo
|
|
|
262
262
|
name: "Editorial Workflows Effects Drained",
|
|
263
263
|
version: 1,
|
|
264
264
|
description: "A drain pass ran — drainedCount/drainedEffects report the successful dispatches. Unsampled when non-empty (outcome counts must be complete; volume is bounded by real effect work); empty polls are machine-cadence noise, throttled engine-side to at most one per minute"
|
|
265
|
+
}), WorkflowEffectStateReported = defineWorkflowEvent({
|
|
266
|
+
name: "Editorial Workflows Effect State Reported",
|
|
267
|
+
version: 1,
|
|
268
|
+
description: "A running effect handler committed mid-dispatch field state through commitEffectOps. Sampled (high-frequency by design — a dispatch may report many times): an adoption and usage signal, not an exact per-run report count",
|
|
269
|
+
maxSampleRate: HIGH_FREQUENCY_SAMPLE_MS
|
|
265
270
|
}), WorkflowEffectCompleted = defineWorkflowEvent({
|
|
266
271
|
name: "Editorial Workflows Effect Completed",
|
|
267
272
|
version: 1,
|
|
@@ -2234,6 +2239,21 @@ class StartNotSettledError extends invariants.WorkflowError {
|
|
|
2234
2239
|
}
|
|
2235
2240
|
}
|
|
2236
2241
|
|
|
2242
|
+
class StaleEffectClaimError extends invariants.WorkflowError {
|
|
2243
|
+
instanceId;
|
|
2244
|
+
effectKey;
|
|
2245
|
+
reason;
|
|
2246
|
+
constructor(args) {
|
|
2247
|
+
super("stale-effect-claim", `Mid-dispatch report for effect entry "${args.effectKey}" on ${args.instanceId} rejected: ${staleClaimDetail(args.reason)}. Nothing was written. Stop reporting from this dispatch — a newer dispatch (or none) owns the entry now.`),
|
|
2248
|
+
this.name = "StaleEffectClaimError", this.instanceId = args.instanceId, this.effectKey = args.effectKey,
|
|
2249
|
+
this.reason = args.reason;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
function staleClaimDetail(reason) {
|
|
2254
|
+
return reason === "unclaimed" ? "the entry holds no claim" : reason === "claim-superseded" ? "the claim was taken over by another dispatch" : "the claim's lease has expired";
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2237
2257
|
const CONCURRENT_COMMIT_MAX_ATTEMPTS = 3;
|
|
2238
2258
|
|
|
2239
2259
|
function lostRaceMessage(args) {
|
|
@@ -2290,6 +2310,20 @@ class ConcurrentCompleteEffectError extends invariants.WorkflowError {
|
|
|
2290
2310
|
}
|
|
2291
2311
|
}
|
|
2292
2312
|
|
|
2313
|
+
class ConcurrentCommitEffectOpsError extends invariants.WorkflowError {
|
|
2314
|
+
instanceId;
|
|
2315
|
+
effectKey;
|
|
2316
|
+
attempts;
|
|
2317
|
+
constructor(args) {
|
|
2318
|
+
super("concurrent-commit-effect-ops", lostRaceMessage({
|
|
2319
|
+
what: `Mid-dispatch report for effect entry "${args.effectKey}"`,
|
|
2320
|
+
instanceId: args.instanceId,
|
|
2321
|
+
attempts: args.attempts
|
|
2322
|
+
})), this.name = "ConcurrentCommitEffectOpsError", this.instanceId = args.instanceId,
|
|
2323
|
+
this.effectKey = args.effectKey, this.attempts = args.attempts;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2293
2327
|
class CascadeLimitError extends invariants.WorkflowError {
|
|
2294
2328
|
instanceId;
|
|
2295
2329
|
limit;
|
|
@@ -2624,8 +2658,17 @@ async function applyFieldUpdateWhere(op, ctx) {
|
|
|
2624
2658
|
fields: entry.of
|
|
2625
2659
|
}
|
|
2626
2660
|
});
|
|
2627
|
-
if (merge === null || typeof merge != "object" || Array.isArray(merge)) throw new
|
|
2628
|
-
|
|
2661
|
+
if (merge === null || typeof merge != "object" || Array.isArray(merge)) throw new invariants.FieldValueShapeError({
|
|
2662
|
+
entryType: entry._type,
|
|
2663
|
+
entryName: entry.name,
|
|
2664
|
+
mode: "value",
|
|
2665
|
+
issues: [ `field.updateWhere value must resolve to an object of fields to merge (target "${op.target.field}")` ]
|
|
2666
|
+
});
|
|
2667
|
+
requireNoReservedMergeKeys({
|
|
2668
|
+
merge: merge,
|
|
2669
|
+
entry: entry,
|
|
2670
|
+
op: op
|
|
2671
|
+
});
|
|
2629
2672
|
const matches = await rowMatches({
|
|
2630
2673
|
where: op.where,
|
|
2631
2674
|
rows: rows,
|
|
@@ -2671,9 +2714,14 @@ function requireMergeableRows(entry, op) {
|
|
|
2671
2714
|
if (entry._type !== "array") throw new Error(`${op.type} target ${op.target.scope}:"${op.target.field}" is a ${entry._type} entry — updateWhere merges declared row sub-fields, so it targets \`array\` entries only`);
|
|
2672
2715
|
}
|
|
2673
2716
|
|
|
2674
|
-
function requireNoReservedMergeKeys(
|
|
2675
|
-
const reserved = [ "_key", "_type" ].filter(key => key in merge);
|
|
2676
|
-
if (reserved.length !== 0) throw new
|
|
2717
|
+
function requireNoReservedMergeKeys(args) {
|
|
2718
|
+
const {merge: merge, entry: entry, op: op} = args, reserved = [ "_key", "_type" ].filter(key => key in merge);
|
|
2719
|
+
if (reserved.length !== 0) throw new invariants.FieldValueShapeError({
|
|
2720
|
+
entryType: entry._type,
|
|
2721
|
+
entryName: entry.name,
|
|
2722
|
+
mode: "value",
|
|
2723
|
+
issues: [ `field.updateWhere merge writes the reserved row key${reserved.length === 1 ? "" : "s"} ${reserved.map(k => `"${k}"`).join(", ")} (target "${op.target.field}") — row identity and bookkeeping are engine-stamped, never merged` ]
|
|
2724
|
+
});
|
|
2677
2725
|
}
|
|
2678
2726
|
|
|
2679
2727
|
function requireArrayValue(entry, op) {
|
|
@@ -3441,20 +3489,11 @@ function remediationsFor(diagnosis) {
|
|
|
3441
3489
|
}));
|
|
3442
3490
|
}
|
|
3443
3491
|
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
for (const [key, groq] of Object.entries(args.bindings ?? {})) resolved[key] = await invariants.runGroq({
|
|
3447
|
-
groq: groq,
|
|
3448
|
-
params: args.params,
|
|
3449
|
-
snapshot: args.snapshot
|
|
3450
|
-
});
|
|
3451
|
-
return {
|
|
3452
|
-
...resolved,
|
|
3453
|
-
...args.staticInput
|
|
3454
|
-
};
|
|
3492
|
+
function isClaimExpired(claim, now) {
|
|
3493
|
+
return claim.leaseExpiresAt === void 0 || hasPassed(claim.leaseExpiresAt, now);
|
|
3455
3494
|
}
|
|
3456
3495
|
|
|
3457
|
-
const EXECUTION_KINDS = {
|
|
3496
|
+
const EFFECT_RUN_STATUSES = [ "done", "failed", "cancelled" ], EXECUTION_KINDS = {
|
|
3458
3497
|
interactive: "interactive",
|
|
3459
3498
|
server: "server",
|
|
3460
3499
|
cli: "cli",
|
|
@@ -4013,7 +4052,7 @@ function coerceToGdr(raw, workflowResource) {
|
|
|
4013
4052
|
} : null;
|
|
4014
4053
|
}
|
|
4015
4054
|
|
|
4016
|
-
const
|
|
4055
|
+
const NonEmpty = invariants.NonEmptyString, UnknownRecord = v__namespace.record(v__namespace.string(), v__namespace.unknown()), PersistedChoiceOptionsSchema = v__namespace.looseObject({
|
|
4017
4056
|
list: v__namespace.array(v__namespace.looseObject({
|
|
4018
4057
|
title: v__namespace.string(),
|
|
4019
4058
|
value: v__namespace.union([ v__namespace.string(), v__namespace.number() ])
|
|
@@ -4073,7 +4112,7 @@ const OptionalRefTypes = v__namespace.exactOptional(v__namespace.array(v__namesp
|
|
|
4073
4112
|
})), v__namespace.looseObject(invariants.tolerantEntries()({
|
|
4074
4113
|
...fieldArm("subject", invariants.fieldValueSchemas.subject),
|
|
4075
4114
|
types: OptionalRefTypes
|
|
4076
|
-
})), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("release.ref", invariants.fieldValueSchemas["release.ref"]))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("string", invariants.fieldValueSchemas.string))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("text", invariants.fieldValueSchemas.text))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("number", invariants.fieldValueSchemas.number))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("boolean", invariants.fieldValueSchemas.boolean))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("date", invariants.fieldValueSchemas.date))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("datetime", invariants.fieldValueSchemas.datetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("url", invariants.fieldValueSchemas.url))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("actor", invariants.fieldValueSchemas.actor))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignee", invariants.fieldValueSchemas.assignee))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignees", invariants.fieldValueSchemas.assignees))), v__namespace.looseObject(invariants.tolerantEntries()({
|
|
4115
|
+
})), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("release.ref", invariants.fieldValueSchemas["release.ref"]))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("string", invariants.fieldValueSchemas.string))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("text", invariants.fieldValueSchemas.text))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("number", invariants.fieldValueSchemas.number))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("progress", invariants.fieldValueSchemas.progress))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("boolean", invariants.fieldValueSchemas.boolean))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("date", invariants.fieldValueSchemas.date))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("datetime", invariants.fieldValueSchemas.datetime))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("url", invariants.fieldValueSchemas.url))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("actor", invariants.fieldValueSchemas.actor))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignee", invariants.fieldValueSchemas.assignee))), v__namespace.looseObject(invariants.tolerantEntries()(fieldArm("assignees", invariants.fieldValueSchemas.assignees))), v__namespace.looseObject(invariants.tolerantEntries()({
|
|
4077
4116
|
...fieldArm("object", v__namespace.union([ v__namespace.null(), UnknownRecord ])),
|
|
4078
4117
|
fields: v__namespace.array(PersistedFieldShapeSchema)
|
|
4079
4118
|
})), v__namespace.looseObject(invariants.tolerantEntries()({
|
|
@@ -4086,7 +4125,8 @@ const OptionalRefTypes = v__namespace.exactOptional(v__namespace.array(v__namesp
|
|
|
4086
4125
|
_type: v__namespace.literal("pendingEffect.claim"),
|
|
4087
4126
|
claimedAt: invariants.IsoTimestamp,
|
|
4088
4127
|
claimedBy: invariants.ActorShape,
|
|
4089
|
-
leaseExpiresAt: v__namespace.exactOptional(invariants.IsoTimestamp)
|
|
4128
|
+
leaseExpiresAt: v__namespace.exactOptional(invariants.IsoTimestamp),
|
|
4129
|
+
claimToken: v__namespace.exactOptional(NonEmpty)
|
|
4090
4130
|
}), PendingEffectSchema = invariants.tolerantObject()({
|
|
4091
4131
|
_key: NonEmpty,
|
|
4092
4132
|
_type: v__namespace.exactOptional(v__namespace.literal("pendingEffect")),
|
|
@@ -4502,6 +4542,10 @@ function collectEntryDocUris(resolvedFieldEntries) {
|
|
|
4502
4542
|
return entryDocRefs(resolvedFieldEntries).map(ref => ref.id);
|
|
4503
4543
|
}
|
|
4504
4544
|
|
|
4545
|
+
function isEngineContext(ctx) {
|
|
4546
|
+
return "client" in ctx;
|
|
4547
|
+
}
|
|
4548
|
+
|
|
4505
4549
|
function loadCallContext({client: client, instanceId: instanceId, options: options}) {
|
|
4506
4550
|
return loadContext({
|
|
4507
4551
|
client: client,
|
|
@@ -4677,6 +4721,19 @@ async function resolveActivityFieldEntries(args) {
|
|
|
4677
4721
|
});
|
|
4678
4722
|
}
|
|
4679
4723
|
|
|
4724
|
+
async function resolveBindings(args) {
|
|
4725
|
+
const resolved = {};
|
|
4726
|
+
for (const [key, groq] of Object.entries(args.bindings ?? {})) resolved[key] = await invariants.runGroq({
|
|
4727
|
+
groq: groq,
|
|
4728
|
+
params: args.params,
|
|
4729
|
+
snapshot: args.snapshot
|
|
4730
|
+
});
|
|
4731
|
+
return {
|
|
4732
|
+
...resolved,
|
|
4733
|
+
...args.staticInput
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4680
4737
|
const DEFAULT_IDEMPOTENCY_TTL_MS = 1440 * 60 * 1e3;
|
|
4681
4738
|
|
|
4682
4739
|
class RequestAlreadyProcessedError extends Error {
|
|
@@ -4851,6 +4908,7 @@ const REQUEST_TAG = {
|
|
|
4851
4908
|
fireAction: "workflow.fire-action",
|
|
4852
4909
|
editField: "workflow.edit-field",
|
|
4853
4910
|
completeEffect: "workflow.complete-effect",
|
|
4911
|
+
commitEffectOps: "workflow.commit-effect-ops",
|
|
4854
4912
|
tick: "workflow.tick",
|
|
4855
4913
|
evaluate: "workflow.evaluate",
|
|
4856
4914
|
evaluateStart: "workflow.evaluate-start",
|
|
@@ -6120,1965 +6178,2134 @@ async function fetchGrants(args) {
|
|
|
6120
6178
|
});
|
|
6121
6179
|
}
|
|
6122
6180
|
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
const
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
resourcePath: args.grantsFromPath
|
|
6132
|
-
}) : Promise.resolve(void 0), [actor, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
6133
|
-
if (actor === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
|
|
6134
|
-
return {
|
|
6135
|
-
actor: actor,
|
|
6136
|
-
...grants !== void 0 ? {
|
|
6137
|
-
grants: grants
|
|
6138
|
-
} : {}
|
|
6139
|
-
};
|
|
6140
|
-
}
|
|
6141
|
-
|
|
6142
|
-
function cachedActor(client, requestFn) {
|
|
6143
|
-
const cached = actorCache.get(client);
|
|
6144
|
-
if (cached !== void 0) return cached;
|
|
6145
|
-
const pending = fetchActor(requestFn).catch(err => {
|
|
6146
|
-
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
6147
|
-
});
|
|
6148
|
-
return actorCache.set(client, pending), pending;
|
|
6149
|
-
}
|
|
6150
|
-
|
|
6151
|
-
function grantsForClientPath(taggedClient, resourcePath) {
|
|
6152
|
-
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
6153
|
-
return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
|
|
6154
|
-
client: client,
|
|
6155
|
-
requestFn: requestFn,
|
|
6156
|
-
resourcePath: resourcePath
|
|
6181
|
+
async function advisoryCan({instance: instance, actor: actor, grants: grants}) {
|
|
6182
|
+
if (grants === void 0) return;
|
|
6183
|
+
const can = {};
|
|
6184
|
+
for (const permission of invariants.DOCUMENT_VALUE_PERMISSIONS) can[permission] = await grantsPermissionOn({
|
|
6185
|
+
document: instance,
|
|
6186
|
+
grants: grants,
|
|
6187
|
+
permission: permission,
|
|
6188
|
+
userId: actor.id
|
|
6157
6189
|
});
|
|
6190
|
+
return can;
|
|
6158
6191
|
}
|
|
6159
6192
|
|
|
6160
|
-
function
|
|
6161
|
-
return
|
|
6162
|
-
}
|
|
6163
|
-
|
|
6164
|
-
function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
|
|
6165
|
-
let byPath = grantsCache.get(client);
|
|
6166
|
-
byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
|
|
6167
|
-
let cached = byPath.get(resourcePath);
|
|
6168
|
-
return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
|
|
6169
|
-
byPath.set(resourcePath, cached)), cached;
|
|
6193
|
+
function subjectDenialLabels(denied) {
|
|
6194
|
+
return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
|
|
6170
6195
|
}
|
|
6171
6196
|
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6197
|
+
class ActionDisabledError extends invariants.WorkflowError {
|
|
6198
|
+
reason;
|
|
6199
|
+
activity;
|
|
6200
|
+
action;
|
|
6201
|
+
constructor(args) {
|
|
6202
|
+
super("action-disabled", formatDisabledReason({
|
|
6203
|
+
activity: args.activity,
|
|
6204
|
+
action: args.action,
|
|
6205
|
+
reason: args.reason
|
|
6206
|
+
})), this.name = "ActionDisabledError", this.reason = args.reason, this.activity = args.activity,
|
|
6207
|
+
this.action = args.action;
|
|
6183
6208
|
}
|
|
6184
|
-
if (!user || typeof user.id != "string" || user.id.length === 0) return;
|
|
6185
|
-
const roleNames = user.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
6186
|
-
return {
|
|
6187
|
-
kind: "person",
|
|
6188
|
-
id: user.id,
|
|
6189
|
-
...roleNames.length > 0 ? {
|
|
6190
|
-
roles: roleNames
|
|
6191
|
-
} : {}
|
|
6192
|
-
};
|
|
6193
6209
|
}
|
|
6194
6210
|
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
resourcePath: resourcePath
|
|
6202
|
-
});
|
|
6203
|
-
} catch (err) {
|
|
6204
|
-
console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
|
|
6205
|
-
return;
|
|
6211
|
+
class StartNotAllowedError extends invariants.WorkflowError {
|
|
6212
|
+
definition;
|
|
6213
|
+
insight;
|
|
6214
|
+
constructor(args) {
|
|
6215
|
+
super("start-not-allowed", `startInstance refused: start.allowed on definition "${args.definition}" evaluated ` + (args.insight.outcome === "unevaluable" ? `GROQ null ("can't decide" — fail-closed)` : "false") + " for the supplied initialFields. Pre-flight the verdict with evaluateStart."),
|
|
6216
|
+
this.name = "StartNotAllowedError", this.definition = args.definition, this.insight = args.insight;
|
|
6206
6217
|
}
|
|
6207
6218
|
}
|
|
6208
6219
|
|
|
6209
|
-
|
|
6210
|
-
const
|
|
6211
|
-
|
|
6212
|
-
const involved = sites.filter(entry => readsField(entry.insight, field));
|
|
6213
|
-
insights.push({
|
|
6214
|
-
field: field,
|
|
6215
|
-
reads: groqConditionDescribe.dedupeReads(involved.flatMap(entry => fieldReads(entry.insight, field))),
|
|
6216
|
-
involvedIn: involved.map(entry => entry.site),
|
|
6217
|
-
proposals: await verifyProposals({
|
|
6218
|
-
field: field,
|
|
6219
|
-
involved: involved,
|
|
6220
|
-
snapshot: snapshot
|
|
6221
|
-
})
|
|
6222
|
-
});
|
|
6223
|
-
}
|
|
6224
|
-
return insights;
|
|
6220
|
+
function actionRendering(action) {
|
|
6221
|
+
const kind = action.disabledReason?.kind;
|
|
6222
|
+
return kind === "filter-failed" ? "absent" : action.triggered === !0 || kind === "cascade-fired" ? "automation" : "button";
|
|
6225
6223
|
}
|
|
6226
6224
|
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
}
|
|
6225
|
+
const disabledReasonDetail = {
|
|
6226
|
+
"filter-failed": r => `action filter returned false${r.detail ? ` (${r.detail})` : ""}`,
|
|
6227
|
+
"cascade-fired": r => `the action is cascade-fired (when: ${JSON.stringify(r.when)}) — the engine fires it on truth; it cannot be invoked via fireAction`,
|
|
6228
|
+
"activity-not-active": r => `activity status is "${r.status}"`,
|
|
6229
|
+
"stage-terminal": r => `stage "${r.stage}" is terminal`,
|
|
6230
|
+
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6231
|
+
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6232
|
+
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
|
|
6233
|
+
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
6234
|
+
};
|
|
6231
6235
|
|
|
6232
|
-
function
|
|
6233
|
-
return
|
|
6236
|
+
function actionDisabledDetail(reason) {
|
|
6237
|
+
return disabledReasonDetail[reason.kind](reason);
|
|
6234
6238
|
}
|
|
6235
6239
|
|
|
6236
|
-
function
|
|
6237
|
-
return
|
|
6240
|
+
function formatDisabledReason({activity: activity, action: action, reason: reason}) {
|
|
6241
|
+
return `Action "${activity}:${action}" is not allowed: ${actionDisabledDetail(reason)}`;
|
|
6238
6242
|
}
|
|
6239
6243
|
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
condition: entry.condition,
|
|
6247
|
-
dataset: snapshot.docs,
|
|
6248
|
-
params: entry.params,
|
|
6249
|
-
assign: assign
|
|
6250
|
-
});
|
|
6251
|
-
result.changed && consequences.push({
|
|
6252
|
-
site: entry.site,
|
|
6253
|
-
before: result.before,
|
|
6254
|
-
after: result.after
|
|
6255
|
-
});
|
|
6256
|
-
}
|
|
6257
|
-
consequences.length > 0 && proposals.push({
|
|
6258
|
-
assign: assign,
|
|
6259
|
-
consequences: consequences
|
|
6260
|
-
});
|
|
6244
|
+
class EditFieldDeniedError extends invariants.WorkflowError {
|
|
6245
|
+
reason;
|
|
6246
|
+
target;
|
|
6247
|
+
constructor(args) {
|
|
6248
|
+
super("edit-field-denied", formatEditDisabledReason(args.target, args.reason)),
|
|
6249
|
+
this.name = "EditFieldDeniedError", this.reason = args.reason, this.target = args.target;
|
|
6261
6250
|
}
|
|
6262
|
-
return proposals;
|
|
6263
6251
|
}
|
|
6264
6252
|
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
}
|
|
6253
|
+
const editDisabledReasonDetail = {
|
|
6254
|
+
"not-editable": () => "field is not declared editable",
|
|
6255
|
+
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6256
|
+
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6257
|
+
"edit-window-closed": r => `edit window closed (${r.detail})`,
|
|
6258
|
+
"editor-not-permitted": r => `editor not permitted (${r.predicate})`
|
|
6259
|
+
};
|
|
6269
6260
|
|
|
6270
|
-
function
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
target: requirement.target,
|
|
6275
|
-
value: requirement.value
|
|
6276
|
-
} ];
|
|
6261
|
+
function formatEditDisabledReason(target, reason) {
|
|
6262
|
+
const detail = editDisabledReasonDetail[reason.kind](reason), where = target.activity !== void 0 ? `${target.activity}.${target.field}` : target.field;
|
|
6263
|
+
return `Field "${target.scope}:${where}" is not editable: ${detail}`;
|
|
6264
|
+
}
|
|
6277
6265
|
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
return assignment.target.path.every(segment => typeof segment != "number" || segment <= groqConditionDescribe.MAX_COUNTERFACTUAL_INDEX);
|
|
6266
|
+
async function fireAction(args) {
|
|
6267
|
+
const {client: client, instanceId: instanceId, activity: activity, action: action, params: params, requestRecord: requestRecord, options: options} = args;
|
|
6268
|
+
return retryOnRevisionConflict({
|
|
6269
|
+
client: client,
|
|
6270
|
+
instanceId: instanceId,
|
|
6271
|
+
options: options,
|
|
6272
|
+
commit: ctx => commitAction({
|
|
6273
|
+
ctx: ctx,
|
|
6274
|
+
activityName: activity,
|
|
6275
|
+
actionName: action,
|
|
6276
|
+
callerParams: params,
|
|
6277
|
+
requestRecord: requestRecord,
|
|
6278
|
+
options: options
|
|
6279
|
+
}),
|
|
6280
|
+
onExhausted: () => new ConcurrentFireActionError({
|
|
6281
|
+
instanceId: instanceId,
|
|
6282
|
+
activity: activity,
|
|
6283
|
+
action: action,
|
|
6284
|
+
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
6285
|
+
})
|
|
6286
|
+
});
|
|
6300
6287
|
}
|
|
6301
6288
|
|
|
6302
|
-
async function
|
|
6303
|
-
const {
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6289
|
+
async function resolveActionCommit({ctx: ctx, activityName: activityName, actionName: actionName, callerParams: callerParams, options: options}) {
|
|
6290
|
+
const actor = options?.actor, {stage: stage, activity: activity} = findActivityInCurrentStage(ctx, activityName), action = (activity.actions ?? []).find(a => a.name === actionName);
|
|
6291
|
+
if (action === void 0) throw new invariants.ContractViolationError(`Action "${actionName}" not declared on activity "${activityName}"`);
|
|
6292
|
+
if (action.when !== void 0) throw new ActionDisabledError({
|
|
6293
|
+
activity: activityName,
|
|
6294
|
+
action: actionName,
|
|
6295
|
+
reason: {
|
|
6296
|
+
kind: "cascade-fired",
|
|
6297
|
+
when: action.when
|
|
6298
|
+
}
|
|
6299
|
+
});
|
|
6300
|
+
if (action.filter !== void 0) {
|
|
6301
|
+
const can = options?.grants !== void 0 && actor !== void 0 ? await advisoryCan({
|
|
6302
|
+
instance: ctx.instance,
|
|
6303
|
+
actor: actor,
|
|
6304
|
+
grants: options.grants
|
|
6305
|
+
}) : void 0;
|
|
6306
|
+
if (!await ctxEvaluateCondition({
|
|
6307
|
+
ctx: ctx,
|
|
6308
|
+
condition: action.filter,
|
|
6309
|
+
opts: {
|
|
6310
|
+
activityName: activityName,
|
|
6311
|
+
...actor !== void 0 ? {
|
|
6312
|
+
actor: actor
|
|
6313
|
+
} : {},
|
|
6314
|
+
...can !== void 0 ? {
|
|
6315
|
+
vars: {
|
|
6316
|
+
can: can
|
|
6317
|
+
}
|
|
6318
|
+
} : {}
|
|
6319
|
+
}
|
|
6320
|
+
})) throw new ActionDisabledError({
|
|
6321
|
+
activity: activityName,
|
|
6322
|
+
action: actionName,
|
|
6323
|
+
reason: {
|
|
6324
|
+
kind: "filter-failed",
|
|
6325
|
+
filter: action.filter,
|
|
6326
|
+
detail: "commit re-check"
|
|
6327
|
+
}
|
|
6309
6328
|
});
|
|
6310
6329
|
}
|
|
6311
|
-
const
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
}));
|
|
6317
|
-
return new Map(resolved.filter(entry => entry !== void 0));
|
|
6318
|
-
}
|
|
6319
|
-
|
|
6320
|
-
async function evaluateInstance(args) {
|
|
6321
|
-
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
6322
|
-
invariants.validateTag(tag);
|
|
6323
|
-
const {actor: actor, grants: grants} = await resolveAccess(client, {
|
|
6324
|
-
...args.grantsFromPath !== void 0 ? {
|
|
6325
|
-
grantsFromPath: args.grantsFromPath
|
|
6326
|
-
} : {}
|
|
6327
|
-
}), instance = await reload({
|
|
6328
|
-
client: client,
|
|
6329
|
-
instanceId: instanceId,
|
|
6330
|
-
tag: tag
|
|
6331
|
-
}), definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
6332
|
-
client: client,
|
|
6333
|
-
workflowResource: workflowResource,
|
|
6334
|
-
resourceClients: resourceClients
|
|
6335
|
-
}), snapshot = await hydrateSnapshot({
|
|
6336
|
-
client: client,
|
|
6337
|
-
clientForGdr: clientForGdr,
|
|
6338
|
-
instance: instance
|
|
6339
|
-
}), guards = await verdictGuardsForInstance(client, instance._id), resourceGrants = await subjectResourceGrants({
|
|
6340
|
-
clientForGdr: clientForGdr,
|
|
6341
|
-
instance: instance
|
|
6330
|
+
const entry = findCurrentActivities(ctx.instance).find(t => t.name === activityName);
|
|
6331
|
+
if (entry === void 0 || entry.status !== "active") throw notActiveAtCommit({
|
|
6332
|
+
activityName: activityName,
|
|
6333
|
+
actionName: actionName,
|
|
6334
|
+
status: entry?.status
|
|
6342
6335
|
});
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
snapshot: snapshot,
|
|
6348
|
-
guards: guards,
|
|
6349
|
-
now: now,
|
|
6350
|
-
resourceGrants: resourceGrants,
|
|
6351
|
-
...grants !== void 0 ? {
|
|
6352
|
-
grants: grants
|
|
6353
|
-
} : {}
|
|
6336
|
+
const params = validateActionParams({
|
|
6337
|
+
action: action,
|
|
6338
|
+
activityName: activityName,
|
|
6339
|
+
callerParams: callerParams
|
|
6354
6340
|
});
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
const hit = rendered.get(activityName);
|
|
6361
|
-
if (hit !== void 0) return hit;
|
|
6362
|
-
const scope = render(activityName);
|
|
6363
|
-
return rendered.set(activityName, scope), scope;
|
|
6341
|
+
return {
|
|
6342
|
+
stage: stage,
|
|
6343
|
+
activity: activity,
|
|
6344
|
+
action: action,
|
|
6345
|
+
params: params
|
|
6364
6346
|
};
|
|
6365
6347
|
}
|
|
6366
6348
|
|
|
6367
|
-
function
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6349
|
+
function notActiveAtCommit(args) {
|
|
6350
|
+
const {activityName: activityName, actionName: actionName, status: status} = args;
|
|
6351
|
+
return status !== void 0 && invariants.isTerminalActivityStatus(status) ? new ActionDisabledError({
|
|
6352
|
+
activity: activityName,
|
|
6353
|
+
action: actionName,
|
|
6354
|
+
reason: {
|
|
6355
|
+
kind: "activity-not-active",
|
|
6356
|
+
status: status
|
|
6357
|
+
}
|
|
6358
|
+
}) : new Error(`Activity "${activityName}" must be active to fire action "${actionName}"; status is ${status ?? "missing"}`);
|
|
6375
6359
|
}
|
|
6376
6360
|
|
|
6377
|
-
async function
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6361
|
+
async function applyActionFire({ctx: ctx, mutation: mutation, activity: activity, action: action, params: params, actor: actor, triggered: triggered}) {
|
|
6362
|
+
mutation.history.push({
|
|
6363
|
+
_key: randomKey(),
|
|
6364
|
+
_type: "actionFired",
|
|
6365
|
+
at: ctx.now,
|
|
6366
|
+
stage: mutation.currentStage,
|
|
6367
|
+
activity: activity.name,
|
|
6368
|
+
action: action.name,
|
|
6369
|
+
...actor !== void 0 ? {
|
|
6370
|
+
actor: actor,
|
|
6371
|
+
driverKind: invariants.driverKind(actor)
|
|
6372
|
+
} : {},
|
|
6373
|
+
...triggered ? {
|
|
6374
|
+
triggered: !0
|
|
6375
|
+
} : {}
|
|
6382
6376
|
});
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6377
|
+
const ranOps = await runOps({
|
|
6378
|
+
ops: action.ops,
|
|
6379
|
+
mutation: mutation,
|
|
6380
|
+
stage: mutation.currentStage,
|
|
6381
|
+
origin: {
|
|
6382
|
+
activity: activity.name,
|
|
6383
|
+
action: action.name
|
|
6384
|
+
},
|
|
6386
6385
|
params: params,
|
|
6387
|
-
insight: insight
|
|
6388
|
-
}), insight;
|
|
6389
|
-
}
|
|
6390
|
-
|
|
6391
|
-
async function evaluateFromSnapshot(args) {
|
|
6392
|
-
const {instance: instance, definition: definition, actor: actor, grants: grants, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), scopeSource = {
|
|
6393
|
-
instance: instance,
|
|
6394
|
-
definition: definition,
|
|
6395
|
-
snapshot: snapshot,
|
|
6396
|
-
now: now
|
|
6397
|
-
}, can = await advisoryCan({
|
|
6398
|
-
instance: instance,
|
|
6399
6386
|
actor: actor,
|
|
6400
|
-
|
|
6401
|
-
|
|
6387
|
+
self: invariants.selfGdr(ctx.instance),
|
|
6388
|
+
now: ctx.now,
|
|
6389
|
+
snapshot: ctx.snapshot,
|
|
6390
|
+
refSurface: ctx.refSurface
|
|
6391
|
+
});
|
|
6392
|
+
if (await queueEffects({
|
|
6393
|
+
ctx: ctx,
|
|
6394
|
+
mutation: mutation,
|
|
6395
|
+
effects: action.effects,
|
|
6396
|
+
origin: {
|
|
6397
|
+
kind: "action",
|
|
6398
|
+
name: action.name
|
|
6399
|
+
},
|
|
6402
6400
|
actor: actor,
|
|
6403
|
-
|
|
6404
|
-
|
|
6401
|
+
opts: {
|
|
6402
|
+
callerParams: params,
|
|
6403
|
+
activityName: activity.name
|
|
6405
6404
|
}
|
|
6406
|
-
}),
|
|
6405
|
+
}), action.spawn !== void 0) {
|
|
6406
|
+
if (!isEngineContext(ctx)) throw new invariants.ContractViolationError(`Action "${action.name}" declares spawn, which requires a lake-capable engine context`);
|
|
6407
|
+
await spawnSubworkflows({
|
|
6408
|
+
ctx: ctx,
|
|
6409
|
+
mutation: mutation,
|
|
6410
|
+
activity: activity,
|
|
6411
|
+
action: action,
|
|
6412
|
+
sub: action.spawn,
|
|
6413
|
+
actor: actor
|
|
6414
|
+
});
|
|
6415
|
+
}
|
|
6416
|
+
return {
|
|
6417
|
+
ranOps: ranOps
|
|
6418
|
+
};
|
|
6419
|
+
}
|
|
6420
|
+
|
|
6421
|
+
async function commitAction({ctx: ctx, activityName: activityName, actionName: actionName, callerParams: callerParams, requestRecord: requestRecord, options: options}) {
|
|
6422
|
+
assertRequestUnprocessed({
|
|
6423
|
+
instance: ctx.instance,
|
|
6424
|
+
record: requestRecord,
|
|
6425
|
+
now: ctx.now
|
|
6426
|
+
});
|
|
6427
|
+
const actor = options?.actor, {stage: stage, activity: activity, action: action, params: params} = await resolveActionCommit({
|
|
6428
|
+
ctx: ctx,
|
|
6407
6429
|
activityName: activityName,
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
actor: actor,
|
|
6417
|
-
guards: args.guards
|
|
6418
|
-
}), subjectDenials = await forecastSubjectDenials({
|
|
6419
|
-
instance: instance,
|
|
6420
|
-
actor: actor,
|
|
6421
|
-
snapshot: snapshot,
|
|
6422
|
-
resourceGrants: args.resourceGrants
|
|
6423
|
-
}), subjectPermissionReason = subjectDenials.length > 0 ? {
|
|
6424
|
-
kind: "subject-permission-denied",
|
|
6425
|
-
denied: subjectDenials
|
|
6426
|
-
} : void 0, sites = [], activityEvaluations = [];
|
|
6427
|
-
for (const activity of stage.activities ?? []) activityEvaluations.push(await evaluateActivity({
|
|
6428
|
-
activity: activity,
|
|
6429
|
-
statusEntry: currentActivityEntries.find(t => t.name === activity.name),
|
|
6430
|
-
instance: instance,
|
|
6431
|
-
snapshot: snapshot,
|
|
6432
|
-
activityScope: await scopeForActivity(activity.name),
|
|
6433
|
-
cascadeActivityScope: () => cascadeScopeForActivity(activity.name),
|
|
6434
|
-
stageHasExits: !isTerminalStage(stage),
|
|
6435
|
-
guardDenial: guardDenial,
|
|
6436
|
-
subjectPermissionReason: subjectPermissionReason,
|
|
6437
|
-
sites: sites,
|
|
6438
|
-
autonomy: activityAutonomyOf(stageAutonomy2, activity.name)
|
|
6439
|
-
}));
|
|
6440
|
-
const cascadeParams = await renderConditionScope(scopeSource), transitionEvaluations = [];
|
|
6441
|
-
for (const transition of stage.transitions ?? []) {
|
|
6442
|
-
const insight = await explainSite({
|
|
6443
|
-
site: {
|
|
6444
|
-
kind: "transition",
|
|
6445
|
-
transition: transition.name
|
|
6446
|
-
},
|
|
6447
|
-
condition: transition.when,
|
|
6448
|
-
params: cascadeParams,
|
|
6449
|
-
snapshot: snapshot,
|
|
6450
|
-
sites: sites
|
|
6451
|
-
});
|
|
6452
|
-
transitionEvaluations.push({
|
|
6453
|
-
transition: transition,
|
|
6454
|
-
whenSatisfied: insight.outcome === "satisfied",
|
|
6455
|
-
unevaluable: insight.outcome === "unevaluable",
|
|
6456
|
-
insight: insight
|
|
6457
|
-
});
|
|
6458
|
-
}
|
|
6459
|
-
const currentStage = {
|
|
6460
|
-
stage: stage,
|
|
6461
|
-
activities: activityEvaluations,
|
|
6462
|
-
transitions: transitionEvaluations,
|
|
6463
|
-
autonomy: stageAutonomy2
|
|
6464
|
-
}, pendingOnYou = activityEvaluations.filter(t => t.pendingOnActor), canInteract = activityEvaluations.some(t => t.actions.some(a => a.allowed)), editGuardDenial = guardDenial?.kind === "mutation-guard-denied" ? guardDenial : void 0, editableFields = await evaluateEditableFields({
|
|
6465
|
-
instance: instance,
|
|
6466
|
-
definition: definition,
|
|
6467
|
-
stage: stage,
|
|
6468
|
-
snapshot: snapshot,
|
|
6469
|
-
scope: scope,
|
|
6470
|
-
scopeForActivity: scopeForActivity,
|
|
6471
|
-
guardDenial: editGuardDenial,
|
|
6472
|
-
sites: sites
|
|
6430
|
+
actionName: actionName,
|
|
6431
|
+
callerParams: callerParams,
|
|
6432
|
+
options: options
|
|
6433
|
+
}), mutation = startMutation(ctx.instance);
|
|
6434
|
+
recordProcessedRequest({
|
|
6435
|
+
mutation: mutation,
|
|
6436
|
+
record: requestRecord,
|
|
6437
|
+
now: ctx.now
|
|
6473
6438
|
});
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6439
|
+
const mutEntry = requireMutationActivityEntry(mutation, activityName), statusBefore = mutEntry.status, {ranOps: ranOps} = await applyActionFire({
|
|
6440
|
+
ctx: ctx,
|
|
6441
|
+
mutation: mutation,
|
|
6442
|
+
activity: activity,
|
|
6443
|
+
action: action,
|
|
6444
|
+
params: params,
|
|
6477
6445
|
actor: actor,
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6446
|
+
triggered: !1
|
|
6447
|
+
}), newStatus = mutEntry.status !== statusBefore ? mutEntry.status : void 0;
|
|
6448
|
+
return await persistThenMaybeRefresh({
|
|
6449
|
+
ctx: ctx,
|
|
6450
|
+
mutation: mutation,
|
|
6451
|
+
stageName: stage.name,
|
|
6452
|
+
didChangeState: ranOps.some(isFieldOp)
|
|
6453
|
+
}), {
|
|
6454
|
+
fired: !0,
|
|
6455
|
+
activity: activityName,
|
|
6456
|
+
action: actionName,
|
|
6457
|
+
...newStatus !== void 0 ? {
|
|
6458
|
+
newStatus: newStatus
|
|
6459
|
+
} : {},
|
|
6460
|
+
...ranOps.length > 0 ? {
|
|
6461
|
+
ranOps: ranOps
|
|
6462
|
+
} : {}
|
|
6487
6463
|
};
|
|
6488
6464
|
}
|
|
6489
6465
|
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6466
|
+
async function runTriggeredActions({ctx: ctx, mutation: mutation, stage: stage}) {
|
|
6467
|
+
let fires = 0, ranFieldOps = !1;
|
|
6468
|
+
const liveCtx = liveViewContext(ctx, mutation);
|
|
6469
|
+
let firedThisPass = !0;
|
|
6470
|
+
for (;firedThisPass; ) {
|
|
6471
|
+
firedThisPass = !1;
|
|
6472
|
+
for (const activity of stage.activities ?? []) {
|
|
6473
|
+
const fired = await runActivityTriggers({
|
|
6474
|
+
ctx: liveCtx,
|
|
6475
|
+
mutation: mutation,
|
|
6476
|
+
activity: activity
|
|
6477
|
+
});
|
|
6478
|
+
fires += fired.fires, ranFieldOps = ranFieldOps || fired.ranFieldOps, fired.fires > 0 && (firedThisPass = !0);
|
|
6479
|
+
}
|
|
6480
|
+
}
|
|
6481
|
+
return {
|
|
6482
|
+
fires: fires,
|
|
6483
|
+
ranFieldOps: ranFieldOps
|
|
6484
|
+
};
|
|
6497
6485
|
}
|
|
6498
6486
|
|
|
6499
|
-
async function
|
|
6500
|
-
|
|
6501
|
-
for (const
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
scope: site.scope,
|
|
6517
|
-
...site.activity !== void 0 ? {
|
|
6518
|
-
activity: site.activity
|
|
6519
|
-
} : {},
|
|
6520
|
-
name: site.name,
|
|
6521
|
-
type: site.type,
|
|
6522
|
-
...site.title !== void 0 ? {
|
|
6523
|
-
title: site.title
|
|
6524
|
-
} : {},
|
|
6525
|
-
...site.validation !== void 0 ? {
|
|
6526
|
-
validation: site.validation
|
|
6527
|
-
} : {},
|
|
6528
|
-
value: value,
|
|
6529
|
-
editable: reason === void 0,
|
|
6530
|
-
...reason !== void 0 ? {
|
|
6531
|
-
disabledReason: reason
|
|
6532
|
-
} : {},
|
|
6533
|
-
...fieldProvenance(instance, site.ref),
|
|
6534
|
-
...insight !== void 0 ? {
|
|
6535
|
-
insight: insight
|
|
6536
|
-
} : {}
|
|
6487
|
+
async function runActivityTriggers({ctx: ctx, mutation: mutation, activity: activity}) {
|
|
6488
|
+
let fires = 0, ranFieldOps = !1;
|
|
6489
|
+
for (const action of activity.actions ?? []) {
|
|
6490
|
+
if (!invariants.isCascadeFired(action)) continue;
|
|
6491
|
+
const entry = currentActivities(mutation).find(e => e.name === activity.name);
|
|
6492
|
+
if (entry === void 0 || entry.status !== "active") break;
|
|
6493
|
+
if ((entry.firedActions ?? []).includes(action.name) || !await triggerIsLive({
|
|
6494
|
+
ctx: ctx,
|
|
6495
|
+
activity: activity,
|
|
6496
|
+
action: action
|
|
6497
|
+
})) continue;
|
|
6498
|
+
const result = await fireTriggeredAction({
|
|
6499
|
+
ctx: ctx,
|
|
6500
|
+
mutation: mutation,
|
|
6501
|
+
activity: activity,
|
|
6502
|
+
action: action,
|
|
6503
|
+
entry: entry
|
|
6537
6504
|
});
|
|
6505
|
+
if (fires++, ranFieldOps = ranFieldOps || result.ranFieldOps, invariants.isTerminalActivityStatus(entry.status)) break;
|
|
6538
6506
|
}
|
|
6539
|
-
return
|
|
6507
|
+
return {
|
|
6508
|
+
fires: fires,
|
|
6509
|
+
ranFieldOps: ranFieldOps
|
|
6510
|
+
};
|
|
6540
6511
|
}
|
|
6541
6512
|
|
|
6542
|
-
async function
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
});
|
|
6513
|
+
async function triggerIsLive({ctx: ctx, activity: activity, action: action}) {
|
|
6514
|
+
if (!tokenMayExecute({
|
|
6515
|
+
actor: ctx.actor,
|
|
6516
|
+
action: action,
|
|
6517
|
+
ctx: ctx
|
|
6518
|
+
})) return !1;
|
|
6519
|
+
const scope = {
|
|
6520
|
+
activityName: activity.name
|
|
6521
|
+
};
|
|
6522
|
+
return action.filter !== void 0 && await ctxEvaluateConditionOutcome({
|
|
6523
|
+
ctx: ctx,
|
|
6524
|
+
condition: action.filter,
|
|
6525
|
+
opts: scope
|
|
6526
|
+
}) !== "satisfied" ? !1 : await ctxEvaluateConditionOutcome({
|
|
6527
|
+
ctx: ctx,
|
|
6528
|
+
condition: action.when,
|
|
6529
|
+
opts: scope
|
|
6530
|
+
}) === "satisfied";
|
|
6560
6531
|
}
|
|
6561
6532
|
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6533
|
+
function tokenMayExecute({actor: actor, action: action, ctx: ctx}) {
|
|
6534
|
+
const roles = action.roles;
|
|
6535
|
+
return roles === void 0 || roles.length === 0 ? !0 : actor === void 0 ? !1 : roles.some(required => invariants.actorFulfillsRole({
|
|
6536
|
+
actorRoles: actor.roles,
|
|
6537
|
+
required: required,
|
|
6538
|
+
aliases: ctx.definition.roleAliases
|
|
6539
|
+
}));
|
|
6540
|
+
}
|
|
6541
|
+
|
|
6542
|
+
async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: activity, action: action, entry: entry}) {
|
|
6543
|
+
entry.firedActions = [ ...entry.firedActions ?? [], action.name ];
|
|
6544
|
+
const {ranOps: ranOps} = await applyActionFire({
|
|
6545
|
+
ctx: ctx,
|
|
6546
|
+
mutation: mutation,
|
|
6547
|
+
activity: activity,
|
|
6548
|
+
action: action,
|
|
6549
|
+
params: {},
|
|
6550
|
+
actor: ctx.actor,
|
|
6551
|
+
triggered: !0
|
|
6570
6552
|
});
|
|
6571
|
-
return
|
|
6553
|
+
return {
|
|
6554
|
+
ranFieldOps: ranOps.some(isFieldOp)
|
|
6555
|
+
};
|
|
6572
6556
|
}
|
|
6573
6557
|
|
|
6574
|
-
async function
|
|
6575
|
-
const
|
|
6576
|
-
if (
|
|
6577
|
-
const
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
const doc = snapshot.docs.find(d => d._id === ref.id);
|
|
6584
|
-
doc !== void 0 && await subjectUpdateAllowed({
|
|
6585
|
-
doc: doc,
|
|
6586
|
-
parsed: parsed,
|
|
6587
|
-
grants: grants,
|
|
6588
|
-
actorId: actor.id
|
|
6589
|
-
}) === !1 && denials.push({
|
|
6590
|
-
subject: ref.id,
|
|
6591
|
-
resource: invariants.resourceGdr(resource),
|
|
6592
|
-
permission: "update"
|
|
6593
|
-
});
|
|
6594
|
-
}
|
|
6595
|
-
return denials;
|
|
6596
|
-
}
|
|
6597
|
-
|
|
6598
|
-
async function subjectUpdateAllowed(args) {
|
|
6599
|
-
const {doc: doc, parsed: parsed, grants: grants, actorId: actorId} = args;
|
|
6600
|
-
try {
|
|
6601
|
-
return await grantsPermissionOn({
|
|
6602
|
-
document: {
|
|
6603
|
-
...doc,
|
|
6604
|
-
_id: parsed.documentId
|
|
6605
|
-
},
|
|
6606
|
-
grants: grants,
|
|
6607
|
-
permission: "update",
|
|
6608
|
-
userId: actorId
|
|
6609
|
-
});
|
|
6610
|
-
} catch (err) {
|
|
6611
|
-
console.warn(`workflow: subject-write forecast skipped for "${doc._id}" — evaluating that resource's grants failed (the lake still enforces the write). Original error: ${invariants.errorMessage(err)}`);
|
|
6612
|
-
return;
|
|
6613
|
-
}
|
|
6614
|
-
}
|
|
6615
|
-
|
|
6616
|
-
async function evaluateActivity(args) {
|
|
6617
|
-
const {activity: activity, statusEntry: statusEntry, instance: instance, snapshot: snapshot, activityScope: activityScope, cascadeActivityScope: cascadeActivityScope, stageHasExits: stageHasExits, guardDenial: guardDenial, subjectPermissionReason: subjectPermissionReason, sites: sites, autonomy: autonomy} = args, status = statusEntry?.status ?? "skipped", assigned = activityScope.assigned === !0, {unmetRequirements: unmetRequirements, ...conditionInsights} = await explainActivityConditions({
|
|
6618
|
-
activity: activity,
|
|
6619
|
-
activityScope: activityScope,
|
|
6620
|
-
cascadeActivityScope: cascadeActivityScope,
|
|
6621
|
-
snapshot: snapshot,
|
|
6622
|
-
sites: sites
|
|
6623
|
-
}), requirementsReason = unmetRequirements.length > 0 ? {
|
|
6624
|
-
kind: "requirements-unmet",
|
|
6625
|
-
unmetRequirements: unmetRequirements
|
|
6626
|
-
} : void 0, actions = [];
|
|
6627
|
-
for (const action of activity.actions ?? []) actions.push(await evaluateAction({
|
|
6628
|
-
action: action,
|
|
6629
|
-
activityName: activity.name,
|
|
6630
|
-
status: status,
|
|
6558
|
+
async function primeInitialStage({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry}) {
|
|
6559
|
+
const instance = await getInstanceDocument(client, instanceId);
|
|
6560
|
+
if (!instance || instance.stages.length > 0) return;
|
|
6561
|
+
const definition = invariants.parseDefinitionSnapshot(instance), stage = definition.stages.find(s => s.name === instance.currentStage);
|
|
6562
|
+
if (stage === void 0) return;
|
|
6563
|
+
const ctx = await buildEngineContext({
|
|
6564
|
+
client: client,
|
|
6565
|
+
clientForGdr: clientForGdr,
|
|
6566
|
+
refSurface: refSurface,
|
|
6631
6567
|
instance: instance,
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
stageHasExits: stageHasExits,
|
|
6636
|
-
guardDenial: guardDenial,
|
|
6637
|
-
subjectPermissionReason: subjectPermissionReason,
|
|
6638
|
-
requirementsReason: requirementsReason,
|
|
6639
|
-
sites: sites
|
|
6640
|
-
}));
|
|
6641
|
-
return {
|
|
6642
|
-
activity: activity,
|
|
6643
|
-
status: status,
|
|
6644
|
-
kind: invariants.deriveActivityKind(activity),
|
|
6645
|
-
classification: invariants.deriveExecutorClassification(activity),
|
|
6646
|
-
autonomy: autonomy,
|
|
6647
|
-
pendingOnActor: status === "active" && assigned,
|
|
6648
|
-
scopedOut: isFilterScopedOut({
|
|
6649
|
-
status: status,
|
|
6650
|
-
startedAt: statusEntry?.startedAt
|
|
6651
|
-
}),
|
|
6652
|
-
...unmetRequirements.length > 0 ? {
|
|
6653
|
-
unmetRequirements: unmetRequirements
|
|
6568
|
+
definition: definition,
|
|
6569
|
+
...clock ? {
|
|
6570
|
+
clock: clock
|
|
6654
6571
|
} : {},
|
|
6655
|
-
...
|
|
6656
|
-
|
|
6572
|
+
...actor ? {
|
|
6573
|
+
actor: actor
|
|
6574
|
+
} : {},
|
|
6575
|
+
...executionContext ? {
|
|
6576
|
+
executionContext: executionContext
|
|
6577
|
+
} : {},
|
|
6578
|
+
...telemetry ? {
|
|
6579
|
+
telemetry: telemetry
|
|
6580
|
+
} : {}
|
|
6581
|
+
}), now = ctx.now, discards = [], initialStageEntry = {
|
|
6582
|
+
_key: randomKey(),
|
|
6583
|
+
name: stage.name,
|
|
6584
|
+
enteredAt: now,
|
|
6585
|
+
fields: await resolveStageFieldEntries({
|
|
6586
|
+
client: client,
|
|
6587
|
+
instance: instance,
|
|
6588
|
+
stage: stage,
|
|
6589
|
+
now: now,
|
|
6590
|
+
refSurface: refSurface,
|
|
6591
|
+
recordDiscard: recordFieldDiscards({
|
|
6592
|
+
target: discards,
|
|
6593
|
+
scope: "stage",
|
|
6594
|
+
at: now
|
|
6595
|
+
})
|
|
6596
|
+
}),
|
|
6597
|
+
activities: []
|
|
6598
|
+
}, primedCtx = {
|
|
6599
|
+
...ctx,
|
|
6600
|
+
instance: {
|
|
6601
|
+
...instance,
|
|
6602
|
+
stages: [ initialStageEntry ]
|
|
6603
|
+
}
|
|
6657
6604
|
};
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
}, condition) ]);
|
|
6673
|
-
const requirementInsights = Object.fromEntries(requirementEntries), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([name]) => name), filterInsight = activity.filter !== void 0 ? await explainSite({
|
|
6674
|
-
site: {
|
|
6675
|
-
kind: "activity-filter",
|
|
6676
|
-
activity: activity.name
|
|
6677
|
-
},
|
|
6678
|
-
condition: activity.filter,
|
|
6679
|
-
params: await cascadeActivityScope(),
|
|
6680
|
-
snapshot: snapshot,
|
|
6681
|
-
sites: sites
|
|
6682
|
-
}) : void 0;
|
|
6683
|
-
return {
|
|
6684
|
-
unmetRequirements: unmetRequirements,
|
|
6685
|
-
...activity.requirements !== void 0 ? {
|
|
6686
|
-
requirementInsights: requirementInsights
|
|
6605
|
+
initialStageEntry.activities = await buildStageActivities({
|
|
6606
|
+
ctx: primedCtx,
|
|
6607
|
+
stage: stage,
|
|
6608
|
+
recordDiscard: recordFieldDiscards({
|
|
6609
|
+
target: discards,
|
|
6610
|
+
scope: "activity",
|
|
6611
|
+
at: now
|
|
6612
|
+
})
|
|
6613
|
+
});
|
|
6614
|
+
const terminal = isTerminalStage(stage), committed = await client.patch(instance._id).set({
|
|
6615
|
+
stages: [ initialStageEntry ],
|
|
6616
|
+
lastChangedAt: now,
|
|
6617
|
+
...terminal ? {
|
|
6618
|
+
completedAt: now
|
|
6687
6619
|
} : {},
|
|
6688
|
-
...
|
|
6689
|
-
|
|
6620
|
+
...discards.length > 0 ? {
|
|
6621
|
+
history: [ ...instance.history, ...stampHistoryEntries(discards, ctx.executionContext) ]
|
|
6690
6622
|
} : {}
|
|
6623
|
+
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
6624
|
+
await deployOrRollback({
|
|
6625
|
+
client: client,
|
|
6626
|
+
instanceId: instance._id,
|
|
6627
|
+
committedRev: committed._rev,
|
|
6628
|
+
restore: {
|
|
6629
|
+
stages: instance.stages,
|
|
6630
|
+
history: instance.history
|
|
6631
|
+
},
|
|
6632
|
+
...terminal ? {
|
|
6633
|
+
unset: [ "completedAt" ]
|
|
6634
|
+
} : {},
|
|
6635
|
+
reversible: !0,
|
|
6636
|
+
deploy: () => deployStageGuards({
|
|
6637
|
+
client: client,
|
|
6638
|
+
clientForGdr: clientForGdr,
|
|
6639
|
+
instance: instance,
|
|
6640
|
+
definition: definition,
|
|
6641
|
+
stageName: stage.name,
|
|
6642
|
+
now: now,
|
|
6643
|
+
snapshot: ctx.snapshot
|
|
6644
|
+
})
|
|
6645
|
+
});
|
|
6646
|
+
}
|
|
6647
|
+
|
|
6648
|
+
const CASCADE_LIMIT = 100;
|
|
6649
|
+
|
|
6650
|
+
async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
6651
|
+
const ctx = await loadContext({
|
|
6652
|
+
client: client,
|
|
6653
|
+
instanceId: instanceId,
|
|
6654
|
+
options: {
|
|
6655
|
+
clientForGdr: clientForGdr,
|
|
6656
|
+
refSurface: refSurface,
|
|
6657
|
+
...actor ? {
|
|
6658
|
+
actor: actor
|
|
6659
|
+
} : {},
|
|
6660
|
+
...clock ? {
|
|
6661
|
+
clock: clock
|
|
6662
|
+
} : {},
|
|
6663
|
+
...executionContext ? {
|
|
6664
|
+
executionContext: executionContext
|
|
6665
|
+
} : {},
|
|
6666
|
+
...telemetry ? {
|
|
6667
|
+
telemetry: telemetry
|
|
6668
|
+
} : {},
|
|
6669
|
+
...overlay ? {
|
|
6670
|
+
overlay: overlay
|
|
6671
|
+
} : {}
|
|
6672
|
+
}
|
|
6673
|
+
});
|
|
6674
|
+
if (isTerminal(ctx)) return {
|
|
6675
|
+
moved: !1
|
|
6691
6676
|
};
|
|
6677
|
+
const stage = findStage(ctx.definition, ctx.instance.currentStage), mutation = startMutation(ctx.instance), fired = await runTriggeredActions({
|
|
6678
|
+
ctx: ctx,
|
|
6679
|
+
mutation: mutation,
|
|
6680
|
+
stage: stage
|
|
6681
|
+
}), hopCtx = liveViewContext(ctx, mutation), transition = await pickTransition(hopCtx, stage);
|
|
6682
|
+
return transition === void 0 ? (fired.fires > 0 && await persistThenMaybeRefresh({
|
|
6683
|
+
ctx: ctx,
|
|
6684
|
+
mutation: mutation,
|
|
6685
|
+
stageName: stage.name,
|
|
6686
|
+
didChangeState: fired.ranFieldOps
|
|
6687
|
+
}), {
|
|
6688
|
+
moved: !1
|
|
6689
|
+
}) : (await commitStageMove({
|
|
6690
|
+
ctx: ctx,
|
|
6691
|
+
mutation: mutation,
|
|
6692
|
+
fromStage: stage,
|
|
6693
|
+
toStage: findStage(ctx.definition, transition.to),
|
|
6694
|
+
transition: transition.name,
|
|
6695
|
+
via: "transition",
|
|
6696
|
+
actor: actor
|
|
6697
|
+
}), {
|
|
6698
|
+
moved: !0
|
|
6699
|
+
});
|
|
6700
|
+
}
|
|
6701
|
+
|
|
6702
|
+
async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
|
|
6703
|
+
let count = 0;
|
|
6704
|
+
for (;;) {
|
|
6705
|
+
if (await drainCondemnedChildren({
|
|
6706
|
+
client: client,
|
|
6707
|
+
instanceId: instanceId,
|
|
6708
|
+
actor: actor,
|
|
6709
|
+
clientForGdr: clientForGdr,
|
|
6710
|
+
refSurface: refSurface,
|
|
6711
|
+
clock: clock,
|
|
6712
|
+
executionContext: executionContext,
|
|
6713
|
+
telemetry: telemetry
|
|
6714
|
+
}), !(await runCascadeHop({
|
|
6715
|
+
client: client,
|
|
6716
|
+
instanceId: instanceId,
|
|
6717
|
+
actor: actor,
|
|
6718
|
+
clientForGdr: clientForGdr,
|
|
6719
|
+
refSurface: refSurface,
|
|
6720
|
+
clock: clock,
|
|
6721
|
+
executionContext: executionContext,
|
|
6722
|
+
telemetry: telemetry,
|
|
6723
|
+
overlay: overlay
|
|
6724
|
+
})).moved) return count;
|
|
6725
|
+
if (count++, count >= CASCADE_LIMIT) throw new CascadeLimitError({
|
|
6726
|
+
instanceId: instanceId,
|
|
6727
|
+
limit: CASCADE_LIMIT
|
|
6728
|
+
});
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6732
|
+
async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set}) {
|
|
6733
|
+
if (draining.has(instanceId)) return;
|
|
6734
|
+
draining.add(instanceId);
|
|
6735
|
+
const instance = await getInstanceDocument(client, instanceId);
|
|
6736
|
+
if (!instance) return;
|
|
6737
|
+
const condemned = condemnedSubworkflows(instance);
|
|
6738
|
+
if (condemned.length !== 0) {
|
|
6739
|
+
for (const row of condemned) await settleCondemnedRow({
|
|
6740
|
+
client: client,
|
|
6741
|
+
ownerId: instanceId,
|
|
6742
|
+
row: row,
|
|
6743
|
+
actor: actor,
|
|
6744
|
+
clientForGdr: clientForGdr,
|
|
6745
|
+
refSurface: refSurface,
|
|
6746
|
+
clock: clock,
|
|
6747
|
+
executionContext: executionContext,
|
|
6748
|
+
telemetry: telemetry,
|
|
6749
|
+
draining: draining
|
|
6750
|
+
});
|
|
6751
|
+
await stampDrainedRows({
|
|
6752
|
+
client: client,
|
|
6753
|
+
instance: instance,
|
|
6754
|
+
condemned: condemned,
|
|
6755
|
+
clock: clock,
|
|
6756
|
+
executionContext: executionContext
|
|
6757
|
+
});
|
|
6758
|
+
}
|
|
6692
6759
|
}
|
|
6693
6760
|
|
|
6694
|
-
async function
|
|
6695
|
-
const
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6761
|
+
async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
|
|
6762
|
+
const childId = invariants.toBareId(row.ref.id);
|
|
6763
|
+
try {
|
|
6764
|
+
await abortInstance({
|
|
6765
|
+
client: client,
|
|
6766
|
+
instanceId: childId,
|
|
6767
|
+
reason: row.abortPending?.reason ?? "condemned by parent",
|
|
6768
|
+
options: {
|
|
6769
|
+
...actor ? {
|
|
6770
|
+
actor: actor
|
|
6771
|
+
} : {},
|
|
6772
|
+
clientForGdr: clientForGdr,
|
|
6773
|
+
refSurface: refSurface,
|
|
6774
|
+
...clock ? {
|
|
6775
|
+
clock: clock
|
|
6776
|
+
} : {},
|
|
6777
|
+
...executionContext ? {
|
|
6778
|
+
executionContext: executionContext
|
|
6779
|
+
} : {},
|
|
6780
|
+
...telemetry ? {
|
|
6781
|
+
telemetry: telemetry
|
|
6782
|
+
} : {}
|
|
6783
|
+
}
|
|
6784
|
+
}), await drainCondemnedChildren({
|
|
6785
|
+
client: client,
|
|
6786
|
+
instanceId: childId,
|
|
6787
|
+
actor: actor,
|
|
6788
|
+
clientForGdr: clientForGdr,
|
|
6789
|
+
refSurface: refSurface,
|
|
6790
|
+
clock: clock,
|
|
6791
|
+
executionContext: executionContext,
|
|
6792
|
+
telemetry: telemetry,
|
|
6793
|
+
draining: draining
|
|
6794
|
+
});
|
|
6795
|
+
} catch (cause) {
|
|
6796
|
+
if (cause instanceof invariants.InstanceNotFoundError) return;
|
|
6797
|
+
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
6798
|
+
instanceId: ownerId,
|
|
6799
|
+
guardError: cause,
|
|
6800
|
+
reason: `owed child abort of "${childId}" failed while draining condemned rows`
|
|
6801
|
+
});
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
|
|
6805
|
+
async function stampDrainedRows({client: client, instance: instance, condemned: condemned, clock: clock, executionContext: executionContext}) {
|
|
6806
|
+
const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)), children = await client.fetch("*[_id in $ids]{_id, currentStage, completedAt, abortedAt, modelVersion, minReaderModel}", {
|
|
6807
|
+
ids: ids
|
|
6808
|
+
}), byId = new Map(children.map(c => [ invariants.assertReadableModel(c)._id, c ])), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
|
|
6809
|
+
if (row.resolved !== void 0 || !condemnedKeys.has(row._key)) return row;
|
|
6810
|
+
const child = byId.get(invariants.toBareId(row.ref.id)), resolved = child !== void 0 ? terminalResolution(child) : {
|
|
6811
|
+
at: now,
|
|
6812
|
+
aborted: !0
|
|
6813
|
+
};
|
|
6814
|
+
return resolved === void 0 ? row : (history.push(...stampHistoryEntries([ subworkflowResolvedEntry({
|
|
6815
|
+
row: row,
|
|
6816
|
+
at: now,
|
|
6817
|
+
status: resolved.aborted === !0 ? "aborted" : "done"
|
|
6818
|
+
}) ], stamp)), {
|
|
6819
|
+
...row,
|
|
6820
|
+
resolved: resolved
|
|
6821
|
+
});
|
|
6709
6822
|
});
|
|
6823
|
+
await client.patch(instance._id).set({
|
|
6824
|
+
subworkflows: subworkflows,
|
|
6825
|
+
history: history,
|
|
6826
|
+
lastChangedAt: now
|
|
6827
|
+
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
6710
6828
|
}
|
|
6711
6829
|
|
|
6712
|
-
|
|
6713
|
-
const
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
condition: action.filter,
|
|
6720
|
-
params: conditionScope,
|
|
6721
|
-
snapshot: snapshot,
|
|
6722
|
-
sites: sites
|
|
6723
|
-
}) : void 0, whenInsight = action.when !== void 0 ? await explainSite({
|
|
6724
|
-
site: {
|
|
6725
|
-
kind: "action-when",
|
|
6726
|
-
activity: activityName,
|
|
6727
|
-
action: action.name
|
|
6728
|
-
},
|
|
6729
|
-
condition: action.when,
|
|
6730
|
-
params: conditionScope,
|
|
6731
|
-
snapshot: snapshot,
|
|
6732
|
-
sites: sites
|
|
6733
|
-
}) : void 0;
|
|
6734
|
-
return {
|
|
6735
|
-
...insight !== void 0 ? {
|
|
6736
|
-
insight: insight
|
|
6737
|
-
} : {},
|
|
6738
|
-
...whenInsight !== void 0 ? {
|
|
6739
|
-
whenInsight: whenInsight
|
|
6830
|
+
function terminalResolution(child) {
|
|
6831
|
+
const status = resolvedChildStatus(child);
|
|
6832
|
+
if (!(status === void 0 || child.completedAt === void 0 || child.completedAt === null)) return {
|
|
6833
|
+
at: child.completedAt,
|
|
6834
|
+
stage: child.currentStage,
|
|
6835
|
+
...status === "aborted" ? {
|
|
6836
|
+
aborted: !0
|
|
6740
6837
|
} : {}
|
|
6741
6838
|
};
|
|
6742
6839
|
}
|
|
6743
6840
|
|
|
6744
|
-
function
|
|
6745
|
-
return
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
}) : {
|
|
6753
|
-
...actionEvaluationIdentity(action),
|
|
6754
|
-
allowed: !1,
|
|
6755
|
-
triggered: !0,
|
|
6756
|
-
disabledReason: {
|
|
6757
|
-
kind: "cascade-fired",
|
|
6758
|
-
when: when
|
|
6759
|
-
},
|
|
6760
|
-
...insights
|
|
6841
|
+
function subworkflowResolvedEntry({row: row, at: at, status: status}) {
|
|
6842
|
+
return {
|
|
6843
|
+
_key: randomKey(),
|
|
6844
|
+
_type: "subworkflowResolved",
|
|
6845
|
+
at: at,
|
|
6846
|
+
activity: row.activity,
|
|
6847
|
+
instanceRef: row.ref,
|
|
6848
|
+
status: status
|
|
6761
6849
|
};
|
|
6762
6850
|
}
|
|
6763
6851
|
|
|
6764
|
-
function
|
|
6765
|
-
const
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
...
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6852
|
+
async function propagateToAncestors({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry}) {
|
|
6853
|
+
const loaded = await loadPropagationPair(client, instanceId);
|
|
6854
|
+
if (loaded === void 0) return;
|
|
6855
|
+
const {child: child, parent: parent} = loaded, definition = invariants.parseDefinitionSnapshot(parent), ctx = await buildEngineContext({
|
|
6856
|
+
client: client,
|
|
6857
|
+
clientForGdr: clientForGdr,
|
|
6858
|
+
refSurface: refSurface,
|
|
6859
|
+
instance: parent,
|
|
6860
|
+
definition: definition,
|
|
6861
|
+
...clock ? {
|
|
6862
|
+
clock: clock
|
|
6863
|
+
} : {},
|
|
6864
|
+
...actor ? {
|
|
6865
|
+
actor: actor
|
|
6866
|
+
} : {},
|
|
6867
|
+
...executionContext ? {
|
|
6868
|
+
executionContext: executionContext
|
|
6869
|
+
} : {},
|
|
6870
|
+
...telemetry ? {
|
|
6871
|
+
telemetry: telemetry
|
|
6872
|
+
} : {}
|
|
6873
|
+
}), mutation = startMutation(parent), row = mutation.subworkflows.find(r => invariants.toBareId(r.ref.id) === child._id);
|
|
6874
|
+
if (row === void 0) {
|
|
6875
|
+
await recordOrphanedPropagation({
|
|
6876
|
+
ctx: ctx,
|
|
6877
|
+
mutation: mutation,
|
|
6878
|
+
child: child
|
|
6879
|
+
});
|
|
6880
|
+
return;
|
|
6881
|
+
}
|
|
6882
|
+
const changed = stampResolvedChild({
|
|
6883
|
+
mutation: mutation,
|
|
6884
|
+
row: row,
|
|
6885
|
+
child: child,
|
|
6886
|
+
now: ctx.now
|
|
6887
|
+
}), parentTerminal = parent.completedAt !== void 0;
|
|
6888
|
+
changed && await persist(ctx, mutation), !parentTerminal && (await cascadeAutoTransitions({
|
|
6889
|
+
client: client,
|
|
6890
|
+
instanceId: parent._id,
|
|
6891
|
+
actor: actor,
|
|
6892
|
+
clientForGdr: clientForGdr,
|
|
6893
|
+
refSurface: refSurface,
|
|
6894
|
+
clock: clock,
|
|
6895
|
+
executionContext: executionContext,
|
|
6896
|
+
telemetry: telemetry
|
|
6897
|
+
}), await propagateToAncestors({
|
|
6898
|
+
client: client,
|
|
6899
|
+
instanceId: parent._id,
|
|
6900
|
+
actor: actor,
|
|
6901
|
+
clientForGdr: clientForGdr,
|
|
6902
|
+
refSurface: refSurface,
|
|
6903
|
+
clock: clock,
|
|
6904
|
+
executionContext: executionContext,
|
|
6905
|
+
telemetry: telemetry
|
|
6906
|
+
}));
|
|
6803
6907
|
}
|
|
6804
6908
|
|
|
6805
|
-
function
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6909
|
+
async function loadPropagationPair(client, instanceId) {
|
|
6910
|
+
const child = await getInstanceDocument(client, instanceId);
|
|
6911
|
+
if (!child) return;
|
|
6912
|
+
const parentGdr = invariants.parentRef(child);
|
|
6913
|
+
if (parentGdr === void 0) return;
|
|
6914
|
+
const parentDoc = await client.getDocument(invariants.toBareId(parentGdr.id));
|
|
6915
|
+
if (!(!parentDoc || parentDoc._type !== invariants.WORKFLOW_INSTANCE_TYPE)) return {
|
|
6916
|
+
child: child,
|
|
6917
|
+
parent: readInstanceDoc(parentDoc)
|
|
6811
6918
|
};
|
|
6812
6919
|
}
|
|
6813
6920
|
|
|
6814
|
-
|
|
6815
|
-
if (
|
|
6816
|
-
const
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
kind: "mutation-guard-denied",
|
|
6823
|
-
denied: deniedGuardRefs(denied)
|
|
6824
|
-
};
|
|
6921
|
+
function stampResolvedChild({mutation: mutation, row: row, child: child, now: now}) {
|
|
6922
|
+
if (row.resolved !== void 0) return !1;
|
|
6923
|
+
const resolved = terminalResolution(child);
|
|
6924
|
+
return resolved === void 0 ? !1 : (row.resolved = resolved, mutation.history.push(subworkflowResolvedEntry({
|
|
6925
|
+
row: row,
|
|
6926
|
+
at: now,
|
|
6927
|
+
status: resolved.aborted === !0 ? "aborted" : "done"
|
|
6928
|
+
})), !0);
|
|
6825
6929
|
}
|
|
6826
6930
|
|
|
6827
|
-
function
|
|
6828
|
-
const
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6931
|
+
async function recordOrphanedPropagation({ctx: ctx, mutation: mutation, child: child}) {
|
|
6932
|
+
const childUri = invariants.selfGdr(child);
|
|
6933
|
+
mutation.history.some(h => h._type === "subworkflowOrphaned" && h.instanceRef.id === childUri) || (mutation.history.push({
|
|
6934
|
+
_key: randomKey(),
|
|
6935
|
+
_type: "subworkflowOrphaned",
|
|
6936
|
+
at: ctx.now,
|
|
6937
|
+
instanceRef: {
|
|
6938
|
+
id: childUri,
|
|
6939
|
+
type: invariants.WORKFLOW_INSTANCE_TYPE
|
|
6940
|
+
},
|
|
6941
|
+
detail: `Instance "${child._id}" names this instance as its parent but no subworkflow-registry row matches it, so its state cannot drive any gate here.`
|
|
6942
|
+
}), await persist(ctx, mutation));
|
|
6838
6943
|
}
|
|
6839
6944
|
|
|
6840
|
-
function
|
|
6945
|
+
function startMutation(instance) {
|
|
6841
6946
|
return {
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6947
|
+
minReaderModel: invariants.minReaderModelOf(instance),
|
|
6948
|
+
currentStage: instance.currentStage,
|
|
6949
|
+
fields: (instance.fields ?? []).map(s => ({
|
|
6950
|
+
...s
|
|
6951
|
+
})),
|
|
6952
|
+
stages: instance.stages.map(s => ({
|
|
6953
|
+
...s,
|
|
6954
|
+
fields: (s.fields ?? []).map(entry => ({
|
|
6955
|
+
...entry
|
|
6956
|
+
})),
|
|
6957
|
+
activities: s.activities.map(t => ({
|
|
6958
|
+
...t,
|
|
6959
|
+
...t.fields !== void 0 ? {
|
|
6960
|
+
fields: t.fields.map(entry => ({
|
|
6961
|
+
...entry
|
|
6962
|
+
}))
|
|
6963
|
+
} : {}
|
|
6964
|
+
}))
|
|
6965
|
+
})),
|
|
6966
|
+
subworkflows: (instance.subworkflows ?? []).map(row => ({
|
|
6967
|
+
...row,
|
|
6968
|
+
...row.abortPending !== void 0 ? {
|
|
6969
|
+
abortPending: {
|
|
6970
|
+
...row.abortPending
|
|
6971
|
+
}
|
|
6972
|
+
} : {},
|
|
6973
|
+
...row.resolved !== void 0 ? {
|
|
6974
|
+
resolved: {
|
|
6975
|
+
...row.resolved
|
|
6976
|
+
}
|
|
6977
|
+
} : {}
|
|
6978
|
+
})),
|
|
6979
|
+
pendingEffects: [ ...instance.pendingEffects ],
|
|
6980
|
+
effectHistory: [ ...instance.effectHistory ],
|
|
6981
|
+
context: [ ...instance.context ],
|
|
6982
|
+
history: [ ...instance.history ],
|
|
6983
|
+
processedRequests: [ ...instance.processedRequests ?? [] ],
|
|
6984
|
+
lastChangedAt: instance.lastChangedAt,
|
|
6985
|
+
...instance.completedAt !== void 0 ? {
|
|
6986
|
+
completedAt: instance.completedAt
|
|
6847
6987
|
} : {},
|
|
6848
|
-
...
|
|
6849
|
-
|
|
6988
|
+
...instance.abortedAt !== void 0 ? {
|
|
6989
|
+
abortedAt: instance.abortedAt
|
|
6990
|
+
} : {},
|
|
6991
|
+
pendingCreates: []
|
|
6992
|
+
};
|
|
6993
|
+
}
|
|
6994
|
+
|
|
6995
|
+
function instanceStateFields(src) {
|
|
6996
|
+
const state = {
|
|
6997
|
+
currentStage: src.currentStage,
|
|
6998
|
+
fields: src.fields,
|
|
6999
|
+
stages: src.stages,
|
|
7000
|
+
subworkflows: src.subworkflows ?? [],
|
|
7001
|
+
pendingEffects: src.pendingEffects,
|
|
7002
|
+
effectHistory: src.effectHistory,
|
|
7003
|
+
context: src.context,
|
|
7004
|
+
history: src.history,
|
|
7005
|
+
processedRequests: src.processedRequests ?? [],
|
|
7006
|
+
...src.completedAt !== void 0 ? {
|
|
7007
|
+
completedAt: src.completedAt
|
|
7008
|
+
} : {},
|
|
7009
|
+
...src.abortedAt !== void 0 ? {
|
|
7010
|
+
abortedAt: src.abortedAt
|
|
6850
7011
|
} : {}
|
|
6851
7012
|
};
|
|
7013
|
+
return {
|
|
7014
|
+
...invariants.modelStampFor({
|
|
7015
|
+
documentType: "instance",
|
|
7016
|
+
document: state,
|
|
7017
|
+
storedMinReaderModel: src.minReaderModel
|
|
7018
|
+
}),
|
|
7019
|
+
...state
|
|
7020
|
+
};
|
|
6852
7021
|
}
|
|
6853
7022
|
|
|
6854
|
-
function
|
|
6855
|
-
|
|
7023
|
+
function liveViewContext(ctx, mutation) {
|
|
7024
|
+
const materialized = materializeInstance(ctx.instance, mutation);
|
|
7025
|
+
return {
|
|
7026
|
+
...ctx,
|
|
7027
|
+
instance: materialized,
|
|
7028
|
+
snapshot: overlayInstanceInSnapshot(ctx.snapshot, materialized)
|
|
7029
|
+
};
|
|
6856
7030
|
}
|
|
6857
7031
|
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
}
|
|
7032
|
+
function materializeInstance(base, mutation) {
|
|
7033
|
+
return {
|
|
7034
|
+
...base,
|
|
7035
|
+
currentStage: mutation.currentStage,
|
|
7036
|
+
fields: mutation.fields,
|
|
7037
|
+
stages: mutation.stages,
|
|
7038
|
+
subworkflows: mutation.subworkflows,
|
|
7039
|
+
context: mutation.context,
|
|
7040
|
+
pendingEffects: mutation.pendingEffects,
|
|
7041
|
+
effectHistory: mutation.effectHistory
|
|
7042
|
+
};
|
|
6870
7043
|
}
|
|
6871
7044
|
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
7045
|
+
async function persist(ctx, mutation) {
|
|
7046
|
+
stampExecutionContext(ctx, mutation);
|
|
7047
|
+
const set = {
|
|
7048
|
+
...instanceStateFields(mutation),
|
|
7049
|
+
lastChangedAt: ctx.now
|
|
7050
|
+
}, pendingCreates = mutation.pendingCreates;
|
|
7051
|
+
if (pendingCreates.length === 0) return ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev).commit(SYNC_COMMIT);
|
|
7052
|
+
const tx = ctx.client.transaction();
|
|
7053
|
+
for (const {body: body} of pendingCreates) tx.create(body);
|
|
7054
|
+
tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
|
|
7055
|
+
await tx.commit(), mutation.pendingCreates = [];
|
|
7056
|
+
const actorForPriming = ctx.actor;
|
|
7057
|
+
for (const {body: body, started: started} of pendingCreates) try {
|
|
7058
|
+
await primeInitialStage({
|
|
7059
|
+
client: ctx.client,
|
|
7060
|
+
instanceId: body._id,
|
|
7061
|
+
actor: actorForPriming,
|
|
7062
|
+
clientForGdr: ctx.clientForGdr,
|
|
7063
|
+
refSurface: ctx.refSurface,
|
|
7064
|
+
clock: ctx.clock,
|
|
7065
|
+
executionContext: ctx.executionContext,
|
|
7066
|
+
telemetry: ctx.telemetry
|
|
7067
|
+
}), await cascadeAutoTransitions({
|
|
7068
|
+
client: ctx.client,
|
|
7069
|
+
instanceId: body._id,
|
|
7070
|
+
actor: actorForPriming,
|
|
7071
|
+
clientForGdr: ctx.clientForGdr,
|
|
7072
|
+
refSurface: ctx.refSurface,
|
|
7073
|
+
clock: ctx.clock,
|
|
7074
|
+
executionContext: ctx.executionContext,
|
|
7075
|
+
telemetry: ctx.telemetry
|
|
7076
|
+
}), await propagateToAncestors({
|
|
7077
|
+
client: ctx.client,
|
|
7078
|
+
instanceId: body._id,
|
|
7079
|
+
actor: actorForPriming,
|
|
7080
|
+
clientForGdr: ctx.clientForGdr,
|
|
7081
|
+
refSurface: ctx.refSurface,
|
|
7082
|
+
clock: ctx.clock,
|
|
7083
|
+
executionContext: ctx.executionContext,
|
|
7084
|
+
telemetry: ctx.telemetry
|
|
7085
|
+
}), ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7086
|
+
} catch (cause) {
|
|
7087
|
+
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7088
|
+
instanceId: ctx.instance._id,
|
|
7089
|
+
guardError: cause,
|
|
7090
|
+
reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
|
|
7091
|
+
});
|
|
6878
7092
|
}
|
|
7093
|
+
const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
|
|
7094
|
+
if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
|
|
7095
|
+
return reloaded;
|
|
6879
7096
|
}
|
|
6880
7097
|
|
|
6881
|
-
function
|
|
6882
|
-
const
|
|
6883
|
-
|
|
7098
|
+
function stampExecutionContext(ctx, mutation) {
|
|
7099
|
+
const stamp = ctx.executionContext, appended = mutation.history.slice(ctx.instance.history.length);
|
|
7100
|
+
mutation.history = [ ...mutation.history.slice(0, ctx.instance.history.length), ...stampHistoryEntries(appended, stamp) ];
|
|
7101
|
+
for (const {body: body} of mutation.pendingCreates) body.history = stampHistoryEntries(body.history, stamp);
|
|
6884
7102
|
}
|
|
6885
7103
|
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
"instance-completed": r => `instance completed at ${r.completedAt}`,
|
|
6892
|
-
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6893
|
-
"requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
|
|
6894
|
-
"subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
|
|
6895
|
-
};
|
|
7104
|
+
function currentStageEntry(mutation) {
|
|
7105
|
+
const entry = findOpenStageEntry(mutation);
|
|
7106
|
+
if (entry === void 0) throw new Error(`Mutation invariant broken: no current (un-exited) StageEntry for currentStage "${mutation.currentStage}"`);
|
|
7107
|
+
return entry;
|
|
7108
|
+
}
|
|
6896
7109
|
|
|
6897
|
-
function
|
|
6898
|
-
return
|
|
7110
|
+
function currentActivities(mutation) {
|
|
7111
|
+
return currentStageEntry(mutation).activities;
|
|
6899
7112
|
}
|
|
6900
7113
|
|
|
6901
|
-
function
|
|
6902
|
-
|
|
7114
|
+
function findActivityInCurrentStage(ctx, activityName) {
|
|
7115
|
+
const stage = findStage(ctx.definition, ctx.instance.currentStage), activity = (stage.activities ?? []).find(t => t.name === activityName);
|
|
7116
|
+
if (activity === void 0) throw new invariants.ContractViolationError(`Activity "${activityName}" not found in current stage "${stage.name}" of ${ctx.definition.name}`);
|
|
7117
|
+
return {
|
|
7118
|
+
stage: stage,
|
|
7119
|
+
activity: activity
|
|
7120
|
+
};
|
|
6903
7121
|
}
|
|
6904
7122
|
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
super("edit-field-denied", formatEditDisabledReason(args.target, args.reason)),
|
|
6910
|
-
this.name = "EditFieldDeniedError", this.reason = args.reason, this.target = args.target;
|
|
6911
|
-
}
|
|
7123
|
+
function requireMutationActivityEntry(mutation, activity) {
|
|
7124
|
+
const mutEntry = currentActivities(mutation).find(t => t.name === activity);
|
|
7125
|
+
if (mutEntry === void 0) throw new Error(`Activity "${activity}" disappeared from mutation copy — invariant broken`);
|
|
7126
|
+
return mutEntry;
|
|
6912
7127
|
}
|
|
6913
7128
|
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
"instance-aborted": r => `instance aborted at ${r.abortedAt}`,
|
|
6918
|
-
"edit-window-closed": r => `edit window closed (${r.detail})`,
|
|
6919
|
-
"editor-not-permitted": r => `editor not permitted (${r.predicate})`
|
|
6920
|
-
};
|
|
7129
|
+
function findCurrentStageEntry(instance) {
|
|
7130
|
+
return findOpenStageEntry(instance);
|
|
7131
|
+
}
|
|
6921
7132
|
|
|
6922
|
-
function
|
|
6923
|
-
|
|
6924
|
-
return `Field "${target.scope}:${where}" is not editable: ${detail}`;
|
|
7133
|
+
function findCurrentActivities(instance) {
|
|
7134
|
+
return findCurrentStageEntry(instance)?.activities ?? [];
|
|
6925
7135
|
}
|
|
6926
7136
|
|
|
6927
|
-
async function
|
|
6928
|
-
const {client: client, instanceId: instanceId,
|
|
7137
|
+
async function completeEffect(args) {
|
|
7138
|
+
const {client: client, instanceId: instanceId, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, options: options} = args;
|
|
7139
|
+
if (status !== "done" && status !== "failed") throw new invariants.ContractViolationError(`completeEffect: status must be "done" or "failed", got ${JSON.stringify(status)} — "cancelled" is engine-stamped by abort, never reportable`);
|
|
6929
7140
|
return retryOnRevisionConflict({
|
|
6930
7141
|
client: client,
|
|
6931
7142
|
instanceId: instanceId,
|
|
6932
7143
|
options: options,
|
|
6933
|
-
commit: ctx =>
|
|
7144
|
+
commit: ctx => commitCompleteEffect({
|
|
6934
7145
|
ctx: ctx,
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
7146
|
+
effectKey: effectKey,
|
|
7147
|
+
status: status,
|
|
7148
|
+
outputs: outputs,
|
|
7149
|
+
ops: ops,
|
|
7150
|
+
detail: detail,
|
|
7151
|
+
error: error,
|
|
7152
|
+
durationMs: durationMs,
|
|
6938
7153
|
requestRecord: requestRecord,
|
|
6939
|
-
|
|
7154
|
+
actor: options.actor
|
|
6940
7155
|
}),
|
|
6941
|
-
onExhausted: () => new
|
|
7156
|
+
onExhausted: () => new ConcurrentCompleteEffectError({
|
|
6942
7157
|
instanceId: instanceId,
|
|
6943
|
-
|
|
6944
|
-
action: action,
|
|
7158
|
+
effectKey: effectKey,
|
|
6945
7159
|
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
6946
7160
|
})
|
|
6947
7161
|
});
|
|
6948
7162
|
}
|
|
6949
7163
|
|
|
6950
|
-
|
|
6951
|
-
const
|
|
6952
|
-
if (action === void 0) throw new invariants.ContractViolationError(`Action "${actionName}" not declared on activity "${activityName}"`);
|
|
6953
|
-
if (action.when !== void 0) throw new ActionDisabledError({
|
|
6954
|
-
activity: activityName,
|
|
6955
|
-
action: actionName,
|
|
6956
|
-
reason: {
|
|
6957
|
-
kind: "cascade-fired",
|
|
6958
|
-
when: action.when
|
|
6959
|
-
}
|
|
6960
|
-
});
|
|
6961
|
-
if (action.filter !== void 0) {
|
|
6962
|
-
const can = options?.grants !== void 0 && actor !== void 0 ? await advisoryCan({
|
|
6963
|
-
instance: ctx.instance,
|
|
6964
|
-
actor: actor,
|
|
6965
|
-
grants: options.grants
|
|
6966
|
-
}) : void 0;
|
|
6967
|
-
if (!await ctxEvaluateCondition({
|
|
6968
|
-
ctx: ctx,
|
|
6969
|
-
condition: action.filter,
|
|
6970
|
-
opts: {
|
|
6971
|
-
activityName: activityName,
|
|
6972
|
-
...actor !== void 0 ? {
|
|
6973
|
-
actor: actor
|
|
6974
|
-
} : {},
|
|
6975
|
-
...can !== void 0 ? {
|
|
6976
|
-
vars: {
|
|
6977
|
-
can: can
|
|
6978
|
-
}
|
|
6979
|
-
} : {}
|
|
6980
|
-
}
|
|
6981
|
-
})) throw new ActionDisabledError({
|
|
6982
|
-
activity: activityName,
|
|
6983
|
-
action: actionName,
|
|
6984
|
-
reason: {
|
|
6985
|
-
kind: "filter-failed",
|
|
6986
|
-
filter: action.filter,
|
|
6987
|
-
detail: "commit re-check"
|
|
6988
|
-
}
|
|
6989
|
-
});
|
|
6990
|
-
}
|
|
6991
|
-
const entry = findCurrentActivities(ctx.instance).find(t => t.name === activityName);
|
|
6992
|
-
if (entry === void 0 || entry.status !== "active") throw notActiveAtCommit({
|
|
6993
|
-
activityName: activityName,
|
|
6994
|
-
actionName: actionName,
|
|
6995
|
-
status: entry?.status
|
|
6996
|
-
});
|
|
6997
|
-
const params = validateActionParams({
|
|
6998
|
-
action: action,
|
|
6999
|
-
activityName: activityName,
|
|
7000
|
-
callerParams: callerParams
|
|
7001
|
-
});
|
|
7164
|
+
function buildEffectHistoryEntry(pending, outcome) {
|
|
7165
|
+
const {status: status, ranAt: ranAt, actor: actor, detail: detail, error: error, durationMs: durationMs, outputs: outputs} = outcome, resolvedActor = actor ?? pending.actor;
|
|
7002
7166
|
return {
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7167
|
+
_key: pending._key,
|
|
7168
|
+
name: pending.name,
|
|
7169
|
+
...pending.title !== void 0 ? {
|
|
7170
|
+
title: pending.title
|
|
7171
|
+
} : {},
|
|
7172
|
+
...pending.description !== void 0 ? {
|
|
7173
|
+
description: pending.description
|
|
7174
|
+
} : {},
|
|
7175
|
+
params: pending.params,
|
|
7176
|
+
origin: pending.origin,
|
|
7177
|
+
...resolvedActor !== void 0 ? {
|
|
7178
|
+
actor: resolvedActor
|
|
7179
|
+
} : {},
|
|
7180
|
+
...pending.stageEntryKey !== void 0 ? {
|
|
7181
|
+
stageEntryKey: pending.stageEntryKey
|
|
7182
|
+
} : {},
|
|
7183
|
+
ranAt: ranAt,
|
|
7184
|
+
...durationMs !== void 0 ? {
|
|
7185
|
+
durationMs: durationMs
|
|
7186
|
+
} : {},
|
|
7187
|
+
status: status,
|
|
7188
|
+
...detail !== void 0 ? {
|
|
7189
|
+
detail: detail
|
|
7190
|
+
} : {},
|
|
7191
|
+
...error !== void 0 ? {
|
|
7192
|
+
error: error
|
|
7193
|
+
} : {},
|
|
7194
|
+
...outputs !== void 0 ? {
|
|
7195
|
+
outputs: outputs
|
|
7196
|
+
} : {}
|
|
7007
7197
|
};
|
|
7008
7198
|
}
|
|
7009
7199
|
|
|
7010
|
-
function
|
|
7011
|
-
const {
|
|
7012
|
-
return
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7200
|
+
function buildEffectSettlement(pending, outcome) {
|
|
7201
|
+
const {status: status, ranAt: ranAt, actor: actor, detail: detail, outputs: outputs} = outcome;
|
|
7202
|
+
return {
|
|
7203
|
+
run: buildEffectHistoryEntry(pending, outcome),
|
|
7204
|
+
event: {
|
|
7205
|
+
_key: randomKey(),
|
|
7206
|
+
_type: "effectCompleted",
|
|
7207
|
+
at: ranAt,
|
|
7208
|
+
effectKey: pending._key,
|
|
7209
|
+
effect: pending.name,
|
|
7210
|
+
status: status,
|
|
7211
|
+
...outputs !== void 0 ? {
|
|
7212
|
+
outputs: outputs
|
|
7213
|
+
} : {},
|
|
7214
|
+
...detail !== void 0 ? {
|
|
7215
|
+
detail: detail
|
|
7216
|
+
} : {},
|
|
7217
|
+
...actor !== void 0 ? {
|
|
7218
|
+
actor: actor
|
|
7219
|
+
} : {}
|
|
7018
7220
|
}
|
|
7019
|
-
}
|
|
7221
|
+
};
|
|
7020
7222
|
}
|
|
7021
7223
|
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7224
|
+
function validateEffectOutputs(args) {
|
|
7225
|
+
const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [];
|
|
7226
|
+
for (const [key, value] of Object.entries(outputs)) {
|
|
7227
|
+
const shape = byName.get(key);
|
|
7228
|
+
if (shape === void 0) {
|
|
7229
|
+
issues.push(`"${key}" is not a declared output`);
|
|
7230
|
+
continue;
|
|
7231
|
+
}
|
|
7232
|
+
const shapeIssues = effectOutputIssues(shape, value);
|
|
7233
|
+
shapeIssues !== void 0 && issues.push(...shapeIssues.map(i => `"${key}": ${i}`));
|
|
7234
|
+
}
|
|
7235
|
+
if (issues.length > 0) throw new EffectOutputsInvalidError({
|
|
7236
|
+
effect: effectName,
|
|
7237
|
+
issues: issues
|
|
7238
|
+
});
|
|
7239
|
+
}
|
|
7240
|
+
|
|
7241
|
+
function effectOutputIssues(shape, value) {
|
|
7242
|
+
return invariants.checkFieldValue({
|
|
7243
|
+
entryType: shape.type,
|
|
7244
|
+
value: value,
|
|
7245
|
+
...shape.fields !== void 0 ? {
|
|
7246
|
+
fields: shape.fields
|
|
7033
7247
|
} : {},
|
|
7034
|
-
...
|
|
7035
|
-
|
|
7248
|
+
...shape.of !== void 0 ? {
|
|
7249
|
+
of: shape.of
|
|
7250
|
+
} : {},
|
|
7251
|
+
...shape.options !== void 0 ? {
|
|
7252
|
+
options: shape.options
|
|
7253
|
+
} : {},
|
|
7254
|
+
...shape.validation !== void 0 ? {
|
|
7255
|
+
validation: shape.validation
|
|
7036
7256
|
} : {}
|
|
7037
7257
|
});
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7258
|
+
}
|
|
7259
|
+
|
|
7260
|
+
function requirePendingEffect(instance, effectKey) {
|
|
7261
|
+
const pending = instance.pendingEffects.find(e => e._key === effectKey);
|
|
7262
|
+
if (pending !== void 0) return pending;
|
|
7263
|
+
const run = instance.effectHistory.find(e => e._key === effectKey), settled = run !== void 0 ? {
|
|
7264
|
+
status: run.status,
|
|
7265
|
+
ranAt: run.ranAt,
|
|
7266
|
+
...run.detail !== void 0 ? {
|
|
7267
|
+
detail: run.detail
|
|
7268
|
+
} : {}
|
|
7269
|
+
} : void 0;
|
|
7270
|
+
throw new invariants.EffectNotFoundError({
|
|
7271
|
+
instanceId: instance._id,
|
|
7272
|
+
effectKey: effectKey,
|
|
7273
|
+
...settled !== void 0 ? {
|
|
7274
|
+
settled: settled
|
|
7275
|
+
} : {}
|
|
7276
|
+
});
|
|
7277
|
+
}
|
|
7278
|
+
|
|
7279
|
+
function validateCompletionInput({pending: pending, definition: definition, status: status, ops: ops, outputs: outputs}) {
|
|
7280
|
+
if (status === "failed" && ops !== void 0 && ops.length > 0) throw new EffectOpsInvalidError({
|
|
7281
|
+
effect: pending.name,
|
|
7282
|
+
issues: [ "ops cannot accompany a failed completion — field.set the outcome on a done completion instead" ]
|
|
7052
7283
|
});
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
}), action.spawn !== void 0 && await spawnSubworkflows({
|
|
7067
|
-
ctx: ctx,
|
|
7068
|
-
mutation: mutation,
|
|
7069
|
-
activity: activity,
|
|
7070
|
-
action: action,
|
|
7071
|
-
sub: action.spawn,
|
|
7072
|
-
actor: actor
|
|
7073
|
-
}), {
|
|
7074
|
-
ranOps: ranOps
|
|
7075
|
-
};
|
|
7284
|
+
if (status === "failed" && outputs !== void 0) throw new EffectOutputsInvalidError({
|
|
7285
|
+
effect: pending.name,
|
|
7286
|
+
issues: [ "outputs cannot accompany a failed completion — report outputs on a done completion instead" ]
|
|
7287
|
+
});
|
|
7288
|
+
if (outputs !== void 0) {
|
|
7289
|
+
const declared = findEffect(definition, pending.name)?.outputs ?? [];
|
|
7290
|
+
validateEffectOutputs({
|
|
7291
|
+
outputs: outputs,
|
|
7292
|
+
declared: declared,
|
|
7293
|
+
effectName: pending.name
|
|
7294
|
+
});
|
|
7295
|
+
}
|
|
7296
|
+
return ops !== void 0 ? validateEffectOps(ops, pending.name) : [];
|
|
7076
7297
|
}
|
|
7077
7298
|
|
|
7078
|
-
async function
|
|
7299
|
+
async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, actor: actor}) {
|
|
7079
7300
|
assertRequestUnprocessed({
|
|
7080
7301
|
instance: ctx.instance,
|
|
7081
7302
|
record: requestRecord,
|
|
7082
7303
|
now: ctx.now
|
|
7083
7304
|
});
|
|
7084
|
-
const
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7305
|
+
const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
|
|
7306
|
+
pending: pending,
|
|
7307
|
+
definition: ctx.definition,
|
|
7308
|
+
status: status,
|
|
7309
|
+
ops: ops,
|
|
7310
|
+
outputs: outputs
|
|
7090
7311
|
}), mutation = startMutation(ctx.instance);
|
|
7091
7312
|
recordProcessedRequest({
|
|
7092
7313
|
mutation: mutation,
|
|
7093
7314
|
record: requestRecord,
|
|
7094
7315
|
now: ctx.now
|
|
7316
|
+
}), mutation.pendingEffects = mutation.pendingEffects.filter(e => e._key !== effectKey);
|
|
7317
|
+
const ranAt = ctx.now, settlement = buildEffectSettlement(pending, {
|
|
7318
|
+
status: status,
|
|
7319
|
+
ranAt: ranAt,
|
|
7320
|
+
actor: actor,
|
|
7321
|
+
detail: detail,
|
|
7322
|
+
error: error,
|
|
7323
|
+
durationMs: durationMs,
|
|
7324
|
+
outputs: outputs
|
|
7095
7325
|
});
|
|
7096
|
-
|
|
7097
|
-
|
|
7326
|
+
mutation.effectHistory.push(settlement.run);
|
|
7327
|
+
const wroteEffectOutputs = status === "done" && outputs !== void 0;
|
|
7328
|
+
mutation.history.push(settlement.event);
|
|
7329
|
+
const ranOps = await runOps({
|
|
7330
|
+
ops: validatedOps,
|
|
7098
7331
|
mutation: mutation,
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7332
|
+
stage: ctx.instance.currentStage,
|
|
7333
|
+
origin: {
|
|
7334
|
+
effect: pending.name
|
|
7335
|
+
},
|
|
7336
|
+
params: pending.params,
|
|
7102
7337
|
actor: actor,
|
|
7103
|
-
|
|
7104
|
-
|
|
7338
|
+
self: invariants.selfGdr(ctx.instance),
|
|
7339
|
+
now: ranAt,
|
|
7340
|
+
snapshot: ctx.snapshot,
|
|
7341
|
+
refSurface: ctx.refSurface
|
|
7342
|
+
}), needsGuardRefresh = wroteEffectOutputs || ranOps.some(isFieldOp);
|
|
7105
7343
|
return await persistThenMaybeRefresh({
|
|
7106
7344
|
ctx: ctx,
|
|
7107
7345
|
mutation: mutation,
|
|
7108
|
-
stageName:
|
|
7109
|
-
didChangeState:
|
|
7346
|
+
stageName: ctx.instance.currentStage,
|
|
7347
|
+
didChangeState: needsGuardRefresh
|
|
7110
7348
|
}), {
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
newStatus: newStatus
|
|
7116
|
-
} : {},
|
|
7117
|
-
...ranOps.length > 0 ? {
|
|
7118
|
-
ranOps: ranOps
|
|
7119
|
-
} : {}
|
|
7120
|
-
};
|
|
7121
|
-
}
|
|
7122
|
-
|
|
7123
|
-
async function runTriggeredActions({ctx: ctx, mutation: mutation, stage: stage}) {
|
|
7124
|
-
let fires = 0, ranFieldOps = !1;
|
|
7125
|
-
const liveCtx = liveViewContext(ctx, mutation);
|
|
7126
|
-
let firedThisPass = !0;
|
|
7127
|
-
for (;firedThisPass; ) {
|
|
7128
|
-
firedThisPass = !1;
|
|
7129
|
-
for (const activity of stage.activities ?? []) {
|
|
7130
|
-
const fired = await runActivityTriggers({
|
|
7131
|
-
ctx: liveCtx,
|
|
7132
|
-
mutation: mutation,
|
|
7133
|
-
activity: activity
|
|
7134
|
-
});
|
|
7135
|
-
fires += fired.fires, ranFieldOps = ranFieldOps || fired.ranFieldOps, fired.fires > 0 && (firedThisPass = !0);
|
|
7136
|
-
}
|
|
7137
|
-
}
|
|
7138
|
-
return {
|
|
7139
|
-
fires: fires,
|
|
7140
|
-
ranFieldOps: ranFieldOps
|
|
7141
|
-
};
|
|
7142
|
-
}
|
|
7143
|
-
|
|
7144
|
-
async function runActivityTriggers({ctx: ctx, mutation: mutation, activity: activity}) {
|
|
7145
|
-
let fires = 0, ranFieldOps = !1;
|
|
7146
|
-
for (const action of activity.actions ?? []) {
|
|
7147
|
-
if (!invariants.isCascadeFired(action)) continue;
|
|
7148
|
-
const entry = currentActivities(mutation).find(e => e.name === activity.name);
|
|
7149
|
-
if (entry === void 0 || entry.status !== "active") break;
|
|
7150
|
-
if ((entry.firedActions ?? []).includes(action.name) || !await triggerIsLive({
|
|
7151
|
-
ctx: ctx,
|
|
7152
|
-
activity: activity,
|
|
7153
|
-
action: action
|
|
7154
|
-
})) continue;
|
|
7155
|
-
const result = await fireTriggeredAction({
|
|
7156
|
-
ctx: ctx,
|
|
7157
|
-
mutation: mutation,
|
|
7158
|
-
activity: activity,
|
|
7159
|
-
action: action,
|
|
7160
|
-
entry: entry
|
|
7161
|
-
});
|
|
7162
|
-
if (fires++, ranFieldOps = ranFieldOps || result.ranFieldOps, invariants.isTerminalActivityStatus(entry.status)) break;
|
|
7163
|
-
}
|
|
7164
|
-
return {
|
|
7165
|
-
fires: fires,
|
|
7166
|
-
ranFieldOps: ranFieldOps
|
|
7167
|
-
};
|
|
7168
|
-
}
|
|
7169
|
-
|
|
7170
|
-
async function triggerIsLive({ctx: ctx, activity: activity, action: action}) {
|
|
7171
|
-
if (!tokenMayExecute({
|
|
7172
|
-
actor: ctx.actor,
|
|
7173
|
-
action: action,
|
|
7174
|
-
ctx: ctx
|
|
7175
|
-
})) return !1;
|
|
7176
|
-
const scope = {
|
|
7177
|
-
activityName: activity.name
|
|
7178
|
-
};
|
|
7179
|
-
return action.filter !== void 0 && await ctxEvaluateConditionOutcome({
|
|
7180
|
-
ctx: ctx,
|
|
7181
|
-
condition: action.filter,
|
|
7182
|
-
opts: scope
|
|
7183
|
-
}) !== "satisfied" ? !1 : await ctxEvaluateConditionOutcome({
|
|
7184
|
-
ctx: ctx,
|
|
7185
|
-
condition: action.when,
|
|
7186
|
-
opts: scope
|
|
7187
|
-
}) === "satisfied";
|
|
7188
|
-
}
|
|
7189
|
-
|
|
7190
|
-
function tokenMayExecute({actor: actor, action: action, ctx: ctx}) {
|
|
7191
|
-
const roles = action.roles;
|
|
7192
|
-
return roles === void 0 || roles.length === 0 ? !0 : actor === void 0 ? !1 : roles.some(required => invariants.actorFulfillsRole({
|
|
7193
|
-
actorRoles: actor.roles,
|
|
7194
|
-
required: required,
|
|
7195
|
-
aliases: ctx.definition.roleAliases
|
|
7196
|
-
}));
|
|
7197
|
-
}
|
|
7198
|
-
|
|
7199
|
-
async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: activity, action: action, entry: entry}) {
|
|
7200
|
-
entry.firedActions = [ ...entry.firedActions ?? [], action.name ];
|
|
7201
|
-
const {ranOps: ranOps} = await applyActionFire({
|
|
7202
|
-
ctx: ctx,
|
|
7203
|
-
mutation: mutation,
|
|
7204
|
-
activity: activity,
|
|
7205
|
-
action: action,
|
|
7206
|
-
params: {},
|
|
7207
|
-
actor: ctx.actor,
|
|
7208
|
-
triggered: !0
|
|
7209
|
-
});
|
|
7210
|
-
return {
|
|
7211
|
-
ranFieldOps: ranOps.some(isFieldOp)
|
|
7349
|
+
effectKey: effectKey,
|
|
7350
|
+
effect: pending.name,
|
|
7351
|
+
status: status,
|
|
7352
|
+
origin: pending.origin.kind
|
|
7212
7353
|
};
|
|
7213
7354
|
}
|
|
7214
7355
|
|
|
7215
|
-
|
|
7216
|
-
const
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
clientForGdr: clientForGdr,
|
|
7223
|
-
refSurface: refSurface,
|
|
7224
|
-
instance: instance,
|
|
7225
|
-
definition: definition,
|
|
7226
|
-
...clock ? {
|
|
7227
|
-
clock: clock
|
|
7228
|
-
} : {},
|
|
7229
|
-
...actor ? {
|
|
7230
|
-
actor: actor
|
|
7231
|
-
} : {},
|
|
7232
|
-
...executionContext ? {
|
|
7233
|
-
executionContext: executionContext
|
|
7234
|
-
} : {},
|
|
7235
|
-
...telemetry ? {
|
|
7236
|
-
telemetry: telemetry
|
|
7237
|
-
} : {}
|
|
7238
|
-
}), now = ctx.now, discards = [], initialStageEntry = {
|
|
7239
|
-
_key: randomKey(),
|
|
7240
|
-
name: stage.name,
|
|
7241
|
-
enteredAt: now,
|
|
7242
|
-
fields: await resolveStageFieldEntries({
|
|
7243
|
-
client: client,
|
|
7244
|
-
instance: instance,
|
|
7245
|
-
stage: stage,
|
|
7246
|
-
now: now,
|
|
7247
|
-
refSurface: refSurface,
|
|
7248
|
-
recordDiscard: recordFieldDiscards({
|
|
7249
|
-
target: discards,
|
|
7250
|
-
scope: "stage",
|
|
7251
|
-
at: now
|
|
7252
|
-
})
|
|
7253
|
-
}),
|
|
7254
|
-
activities: []
|
|
7255
|
-
}, primedCtx = {
|
|
7256
|
-
...ctx,
|
|
7257
|
-
instance: {
|
|
7258
|
-
...instance,
|
|
7259
|
-
stages: [ initialStageEntry ]
|
|
7260
|
-
}
|
|
7261
|
-
};
|
|
7262
|
-
initialStageEntry.activities = await buildStageActivities({
|
|
7263
|
-
ctx: primedCtx,
|
|
7264
|
-
stage: stage,
|
|
7265
|
-
recordDiscard: recordFieldDiscards({
|
|
7266
|
-
target: discards,
|
|
7267
|
-
scope: "activity",
|
|
7268
|
-
at: now
|
|
7269
|
-
})
|
|
7270
|
-
});
|
|
7271
|
-
const terminal = isTerminalStage(stage), committed = await client.patch(instance._id).set({
|
|
7272
|
-
stages: [ initialStageEntry ],
|
|
7273
|
-
lastChangedAt: now,
|
|
7274
|
-
...terminal ? {
|
|
7275
|
-
completedAt: now
|
|
7356
|
+
function buildQueuedEffect({effect: effect, origin: origin, params: params, actor: actor, now: now, stageEntryKey: stageEntryKey}) {
|
|
7357
|
+
const key = randomKey(), pending = {
|
|
7358
|
+
_key: key,
|
|
7359
|
+
_type: "pendingEffect",
|
|
7360
|
+
name: effect.name,
|
|
7361
|
+
...effect.title !== void 0 ? {
|
|
7362
|
+
title: effect.title
|
|
7276
7363
|
} : {},
|
|
7277
|
-
...
|
|
7278
|
-
|
|
7364
|
+
...effect.description !== void 0 ? {
|
|
7365
|
+
description: effect.description
|
|
7366
|
+
} : {},
|
|
7367
|
+
...effect.bindings !== void 0 ? {
|
|
7368
|
+
bindings: effect.bindings
|
|
7369
|
+
} : {},
|
|
7370
|
+
params: params,
|
|
7371
|
+
origin: origin,
|
|
7372
|
+
...actor !== void 0 ? {
|
|
7373
|
+
actor: actor
|
|
7374
|
+
} : {},
|
|
7375
|
+
queuedAt: now,
|
|
7376
|
+
...stageEntryKey !== void 0 ? {
|
|
7377
|
+
stageEntryKey: stageEntryKey
|
|
7279
7378
|
} : {}
|
|
7280
|
-
}
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7379
|
+
}, history = {
|
|
7380
|
+
_key: randomKey(),
|
|
7381
|
+
_type: "effectQueued",
|
|
7382
|
+
at: now,
|
|
7383
|
+
effectKey: key,
|
|
7384
|
+
effect: effect.name,
|
|
7385
|
+
origin: origin
|
|
7386
|
+
};
|
|
7387
|
+
return {
|
|
7388
|
+
pending: pending,
|
|
7389
|
+
history: history
|
|
7390
|
+
};
|
|
7391
|
+
}
|
|
7392
|
+
|
|
7393
|
+
async function queueEffects({ctx: ctx, mutation: mutation, effects: effects, origin: origin, actor: actor, opts: opts}) {
|
|
7394
|
+
if (!effects || effects.length === 0) return;
|
|
7395
|
+
const now = ctx.now, liveCtx = {
|
|
7396
|
+
...ctx,
|
|
7397
|
+
instance: materializeInstance(ctx.instance, mutation)
|
|
7398
|
+
}, stageEntryKey = opts?.stageEntryKey ?? findOpenStageEntry(liveCtx.instance)?._key, params = await ctxConditionParams(liveCtx, {
|
|
7399
|
+
...opts?.activityName !== void 0 ? {
|
|
7400
|
+
activityName: opts.activityName
|
|
7291
7401
|
} : {},
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7402
|
+
...actor !== void 0 ? {
|
|
7403
|
+
actor: actor
|
|
7404
|
+
} : {},
|
|
7405
|
+
vars: {
|
|
7406
|
+
params: opts?.callerParams ?? {}
|
|
7407
|
+
}
|
|
7408
|
+
});
|
|
7409
|
+
for (const effect of effects) {
|
|
7410
|
+
const resolved = await resolveBindings({
|
|
7411
|
+
bindings: effect.bindings,
|
|
7412
|
+
staticInput: effect.input,
|
|
7413
|
+
snapshot: ctx.snapshot,
|
|
7414
|
+
params: params
|
|
7415
|
+
}), {pending: pending, history: history} = buildQueuedEffect({
|
|
7416
|
+
effect: effect,
|
|
7417
|
+
origin: origin,
|
|
7418
|
+
params: resolved,
|
|
7419
|
+
actor: actor,
|
|
7299
7420
|
now: now,
|
|
7300
|
-
|
|
7421
|
+
stageEntryKey: stageEntryKey
|
|
7422
|
+
});
|
|
7423
|
+
mutation.pendingEffects.push(pending), mutation.history.push(history);
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
7426
|
+
|
|
7427
|
+
async function commitEffectOps(args) {
|
|
7428
|
+
const {client: client, instanceId: instanceId, effectKey: effectKey, claimToken: claimToken, ops: ops, requestRecord: requestRecord, leaseMs: leaseMs, options: options} = args;
|
|
7429
|
+
return retryOnRevisionConflict({
|
|
7430
|
+
client: client,
|
|
7431
|
+
instanceId: instanceId,
|
|
7432
|
+
options: options,
|
|
7433
|
+
commit: ctx => commitReport({
|
|
7434
|
+
ctx: ctx,
|
|
7435
|
+
effectKey: effectKey,
|
|
7436
|
+
claimToken: claimToken,
|
|
7437
|
+
ops: ops,
|
|
7438
|
+
requestRecord: requestRecord,
|
|
7439
|
+
leaseMs: leaseMs
|
|
7440
|
+
}),
|
|
7441
|
+
onExhausted: () => new ConcurrentCommitEffectOpsError({
|
|
7442
|
+
instanceId: instanceId,
|
|
7443
|
+
effectKey: effectKey,
|
|
7444
|
+
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
7301
7445
|
})
|
|
7302
7446
|
});
|
|
7303
7447
|
}
|
|
7304
7448
|
|
|
7305
|
-
|
|
7449
|
+
function staleClaimReason(args) {
|
|
7450
|
+
const claim = args.pending.claim;
|
|
7451
|
+
if (claim === void 0) return "unclaimed";
|
|
7452
|
+
if (claim.claimToken !== args.claimToken) return "claim-superseded";
|
|
7453
|
+
if (isClaimExpired(claim, args.now)) return "lease-expired";
|
|
7454
|
+
}
|
|
7306
7455
|
|
|
7307
|
-
|
|
7308
|
-
const
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
...actor ? {
|
|
7315
|
-
actor: actor
|
|
7316
|
-
} : {},
|
|
7317
|
-
...clock ? {
|
|
7318
|
-
clock: clock
|
|
7319
|
-
} : {},
|
|
7320
|
-
...executionContext ? {
|
|
7321
|
-
executionContext: executionContext
|
|
7322
|
-
} : {},
|
|
7323
|
-
...telemetry ? {
|
|
7324
|
-
telemetry: telemetry
|
|
7325
|
-
} : {},
|
|
7326
|
-
...overlay ? {
|
|
7327
|
-
overlay: overlay
|
|
7328
|
-
} : {}
|
|
7456
|
+
function renewClaimLease(args) {
|
|
7457
|
+
const {mutation: mutation, effectKey: effectKey, now: now, leaseMs: leaseMs} = args;
|
|
7458
|
+
mutation.pendingEffects = mutation.pendingEffects.map(entry => entry._key === effectKey && entry.claim !== void 0 ? {
|
|
7459
|
+
...entry,
|
|
7460
|
+
claim: {
|
|
7461
|
+
...entry.claim,
|
|
7462
|
+
leaseExpiresAt: addMs(now, leaseMs)
|
|
7329
7463
|
}
|
|
7464
|
+
} : entry);
|
|
7465
|
+
}
|
|
7466
|
+
|
|
7467
|
+
async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimToken, ops: ops, requestRecord: requestRecord, leaseMs: leaseMs}) {
|
|
7468
|
+
assertRequestUnprocessed({
|
|
7469
|
+
instance: ctx.instance,
|
|
7470
|
+
record: requestRecord,
|
|
7471
|
+
now: ctx.now
|
|
7330
7472
|
});
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7473
|
+
const pending = requirePendingEffect(ctx.instance, effectKey), reason = staleClaimReason({
|
|
7474
|
+
pending: pending,
|
|
7475
|
+
claimToken: claimToken,
|
|
7476
|
+
now: ctx.now
|
|
7477
|
+
});
|
|
7478
|
+
if (reason !== void 0) throw new StaleEffectClaimError({
|
|
7479
|
+
instanceId: ctx.instance._id,
|
|
7480
|
+
effectKey: effectKey,
|
|
7481
|
+
reason: reason
|
|
7482
|
+
});
|
|
7483
|
+
const validatedOps = validateEffectOps(ops, pending.name);
|
|
7484
|
+
if (validatedOps.length === 0) throw new EffectOpsInvalidError({
|
|
7485
|
+
effect: pending.name,
|
|
7486
|
+
issues: [ "a mid-dispatch report must carry at least one field op — there is nothing to commit" ]
|
|
7487
|
+
});
|
|
7488
|
+
const mutation = startMutation(ctx.instance);
|
|
7489
|
+
return recordProcessedRequest({
|
|
7336
7490
|
mutation: mutation,
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
ctx: ctx,
|
|
7491
|
+
record: requestRecord,
|
|
7492
|
+
now: ctx.now
|
|
7493
|
+
}), renewClaimLease({
|
|
7341
7494
|
mutation: mutation,
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7495
|
+
effectKey: effectKey,
|
|
7496
|
+
now: ctx.now,
|
|
7497
|
+
leaseMs: leaseMs
|
|
7498
|
+
}), await runOps({
|
|
7499
|
+
ops: validatedOps,
|
|
7500
|
+
mutation: mutation,
|
|
7501
|
+
stage: ctx.instance.currentStage,
|
|
7502
|
+
origin: {
|
|
7503
|
+
effect: pending.name
|
|
7504
|
+
},
|
|
7505
|
+
params: pending.params,
|
|
7506
|
+
actor: ctx.actor,
|
|
7507
|
+
self: invariants.selfGdr(ctx.instance),
|
|
7508
|
+
now: ctx.now,
|
|
7509
|
+
snapshot: ctx.snapshot,
|
|
7510
|
+
refSurface: ctx.refSurface
|
|
7511
|
+
}), await persistThenMaybeRefresh({
|
|
7347
7512
|
ctx: ctx,
|
|
7348
7513
|
mutation: mutation,
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
transition: transition.name,
|
|
7352
|
-
via: "transition",
|
|
7353
|
-
actor: actor
|
|
7514
|
+
stageName: ctx.instance.currentStage,
|
|
7515
|
+
didChangeState: !0
|
|
7354
7516
|
}), {
|
|
7355
|
-
|
|
7517
|
+
effectKey: effectKey,
|
|
7518
|
+
effect: pending.name
|
|
7519
|
+
};
|
|
7520
|
+
}
|
|
7521
|
+
|
|
7522
|
+
const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
|
|
7523
|
+
|
|
7524
|
+
async function resolveAccess(taggedClient, args = {}) {
|
|
7525
|
+
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
7526
|
+
if (requestFn === void 0) throw new invariants.ContractViolationError("workflow: no actor available. The engine resolves the actor from the client's token via `client.request({ uri: '/users/me' })`. Supply a real `@sanity/client` configured with a token (the test bench serves these endpoints per registered token).");
|
|
7527
|
+
const grantsPromise = args.grantsFromPath !== void 0 ? cachedGrants({
|
|
7528
|
+
client: client,
|
|
7529
|
+
requestFn: requestFn,
|
|
7530
|
+
resourcePath: args.grantsFromPath
|
|
7531
|
+
}) : Promise.resolve(void 0), [actor, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
|
|
7532
|
+
if (actor === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
|
|
7533
|
+
return {
|
|
7534
|
+
actor: actor,
|
|
7535
|
+
...grants !== void 0 ? {
|
|
7536
|
+
grants: grants
|
|
7537
|
+
} : {}
|
|
7538
|
+
};
|
|
7539
|
+
}
|
|
7540
|
+
|
|
7541
|
+
function cachedActor(client, requestFn) {
|
|
7542
|
+
const cached = actorCache.get(client);
|
|
7543
|
+
if (cached !== void 0) return cached;
|
|
7544
|
+
const pending = fetchActor(requestFn).catch(err => {
|
|
7545
|
+
throw actorCache.get(client) === pending && actorCache.delete(client), err;
|
|
7356
7546
|
});
|
|
7547
|
+
return actorCache.set(client, pending), pending;
|
|
7357
7548
|
}
|
|
7358
7549
|
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7550
|
+
function grantsForClientPath(taggedClient, resourcePath) {
|
|
7551
|
+
const client = unwrapRequestTag(taggedClient), requestFn = lazyRequest(client);
|
|
7552
|
+
return requestFn === void 0 ? Promise.resolve(void 0) : cachedGrants({
|
|
7553
|
+
client: client,
|
|
7554
|
+
requestFn: requestFn,
|
|
7555
|
+
resourcePath: resourcePath
|
|
7556
|
+
});
|
|
7557
|
+
}
|
|
7558
|
+
|
|
7559
|
+
function lazyRequest(client) {
|
|
7560
|
+
return client.request === void 0 ? void 0 : opts => client.request(opts);
|
|
7561
|
+
}
|
|
7562
|
+
|
|
7563
|
+
function cachedGrants({client: client, requestFn: requestFn, resourcePath: resourcePath}) {
|
|
7564
|
+
let byPath = grantsCache.get(client);
|
|
7565
|
+
byPath === void 0 && (byPath = /* @__PURE__ */ new Map, grantsCache.set(client, byPath));
|
|
7566
|
+
let cached = byPath.get(resourcePath);
|
|
7567
|
+
return cached === void 0 && (cached = fetchGrantsCached(requestFn, resourcePath),
|
|
7568
|
+
byPath.set(resourcePath, cached)), cached;
|
|
7569
|
+
}
|
|
7570
|
+
|
|
7571
|
+
async function fetchActor(requestFn) {
|
|
7572
|
+
let user;
|
|
7573
|
+
try {
|
|
7574
|
+
user = await requestFn({
|
|
7575
|
+
uri: "/users/me",
|
|
7576
|
+
tag: REQUEST_TAG.accessResolveActor
|
|
7577
|
+
});
|
|
7578
|
+
} catch (err) {
|
|
7579
|
+
throw new Error('workflow: /users/me request failed. The engine resolves the actor from the client\'s token via `client.request({ uri: "/users/me" })`. Check the token/connectivity.', {
|
|
7580
|
+
cause: err
|
|
7385
7581
|
});
|
|
7386
7582
|
}
|
|
7583
|
+
if (!user || typeof user.id != "string" || user.id.length === 0) return;
|
|
7584
|
+
const roleNames = user.roles?.map(r => r.name).filter(n => !!n) ?? [];
|
|
7585
|
+
return {
|
|
7586
|
+
kind: "person",
|
|
7587
|
+
id: user.id,
|
|
7588
|
+
...roleNames.length > 0 ? {
|
|
7589
|
+
roles: roleNames
|
|
7590
|
+
} : {}
|
|
7591
|
+
};
|
|
7387
7592
|
}
|
|
7388
7593
|
|
|
7389
|
-
async function
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
for (const row of condemned) await settleCondemnedRow({
|
|
7397
|
-
client: client,
|
|
7398
|
-
ownerId: instanceId,
|
|
7399
|
-
row: row,
|
|
7400
|
-
actor: actor,
|
|
7401
|
-
clientForGdr: clientForGdr,
|
|
7402
|
-
refSurface: refSurface,
|
|
7403
|
-
clock: clock,
|
|
7404
|
-
executionContext: executionContext,
|
|
7405
|
-
telemetry: telemetry,
|
|
7406
|
-
draining: draining
|
|
7407
|
-
});
|
|
7408
|
-
await stampDrainedRows({
|
|
7409
|
-
client: client,
|
|
7410
|
-
instance: instance,
|
|
7411
|
-
condemned: condemned,
|
|
7412
|
-
clock: clock,
|
|
7413
|
-
executionContext: executionContext
|
|
7594
|
+
async function fetchGrantsCached(requestFn, resourcePath) {
|
|
7595
|
+
try {
|
|
7596
|
+
return await fetchGrants({
|
|
7597
|
+
client: {
|
|
7598
|
+
request: requestFn
|
|
7599
|
+
},
|
|
7600
|
+
resourcePath: resourcePath
|
|
7414
7601
|
});
|
|
7602
|
+
} catch (err) {
|
|
7603
|
+
console.warn(`workflow: failed to fetch grants from "${resourcePath}"; advisory permission reads that depend on them are skipped — a rendered $can stays undefined (conditions referencing it fail closed) and the subject-write forecast omits this resource. The lake still enforces writes. Original error: ${invariants.errorMessage(err)}`);
|
|
7604
|
+
return;
|
|
7415
7605
|
}
|
|
7416
7606
|
}
|
|
7417
7607
|
|
|
7418
|
-
|
|
7419
|
-
|
|
7608
|
+
const REPLAY_SURFACE = {
|
|
7609
|
+
allows: () => !0,
|
|
7610
|
+
description: "any resource (in-memory replay; the committing surface enforces)"
|
|
7611
|
+
};
|
|
7612
|
+
|
|
7613
|
+
async function whatIfFireAction(args) {
|
|
7614
|
+
const {instance: instance, definition: definition, snapshot: snapshot, now: now, actor: actor, stage: stage, activity: activity, action: action} = args;
|
|
7615
|
+
if (!replayable({
|
|
7616
|
+
instance: instance,
|
|
7617
|
+
stage: stage,
|
|
7618
|
+
action: action
|
|
7619
|
+
})) return;
|
|
7620
|
+
const ctx = {
|
|
7621
|
+
now: now,
|
|
7622
|
+
instance: instance,
|
|
7623
|
+
definition: definition,
|
|
7624
|
+
snapshot: snapshot,
|
|
7625
|
+
refSurface: REPLAY_SURFACE,
|
|
7626
|
+
actor: actor
|
|
7627
|
+
}, mutation = startMutation(instance);
|
|
7420
7628
|
try {
|
|
7421
|
-
await
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
actor: actor
|
|
7428
|
-
} : {},
|
|
7429
|
-
clientForGdr: clientForGdr,
|
|
7430
|
-
refSurface: refSurface,
|
|
7431
|
-
...clock ? {
|
|
7432
|
-
clock: clock
|
|
7433
|
-
} : {},
|
|
7434
|
-
...executionContext ? {
|
|
7435
|
-
executionContext: executionContext
|
|
7436
|
-
} : {},
|
|
7437
|
-
...telemetry ? {
|
|
7438
|
-
telemetry: telemetry
|
|
7439
|
-
} : {}
|
|
7440
|
-
}
|
|
7441
|
-
}), await drainCondemnedChildren({
|
|
7442
|
-
client: client,
|
|
7443
|
-
instanceId: childId,
|
|
7629
|
+
await applyActionFire({
|
|
7630
|
+
ctx: ctx,
|
|
7631
|
+
mutation: mutation,
|
|
7632
|
+
activity: activity,
|
|
7633
|
+
action: action,
|
|
7634
|
+
params: {},
|
|
7444
7635
|
actor: actor,
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
draining: draining
|
|
7451
|
-
});
|
|
7452
|
-
} catch (cause) {
|
|
7453
|
-
if (cause instanceof invariants.InstanceNotFoundError) return;
|
|
7454
|
-
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7455
|
-
instanceId: ownerId,
|
|
7456
|
-
guardError: cause,
|
|
7457
|
-
reason: `owed child abort of "${childId}" failed while draining condemned rows`
|
|
7636
|
+
triggered: !1
|
|
7637
|
+
}), await runTriggeredActions({
|
|
7638
|
+
ctx: ctx,
|
|
7639
|
+
mutation: mutation,
|
|
7640
|
+
stage: stage
|
|
7458
7641
|
});
|
|
7642
|
+
} catch (err) {
|
|
7643
|
+
if (err instanceof invariants.FieldValueShapeError) return;
|
|
7644
|
+
throw err;
|
|
7459
7645
|
}
|
|
7646
|
+
const transition = await pickTransition(liveViewContext(ctx, mutation), stage);
|
|
7647
|
+
return transition === void 0 ? {
|
|
7648
|
+
exitsStage: !1
|
|
7649
|
+
} : {
|
|
7650
|
+
exitsStage: !0,
|
|
7651
|
+
transition: transition.name
|
|
7652
|
+
};
|
|
7460
7653
|
}
|
|
7461
7654
|
|
|
7462
|
-
|
|
7463
|
-
const
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7655
|
+
function replayable(args) {
|
|
7656
|
+
const {instance: instance, stage: stage, action: action} = args;
|
|
7657
|
+
if (invariants.terminalState(instance) !== "in-flight" || (action.params ?? []).length > 0 || action.spawn !== void 0) return !1;
|
|
7658
|
+
const primed = new Set((findOpenStageEntry(instance)?.activities ?? []).map(e => e.name));
|
|
7659
|
+
return (stage.activities ?? []).every(declared => primed.has(declared.name)) ? !(stage.activities ?? []).flatMap(declared => declared.actions ?? []).some(sibling => invariants.isCascadeFired(sibling) && sibling.spawn !== void 0) : !1;
|
|
7660
|
+
}
|
|
7661
|
+
|
|
7662
|
+
async function buildFieldInsights({sites: sites, snapshot: snapshot}) {
|
|
7663
|
+
const insights = [];
|
|
7664
|
+
for (const field of fieldsReadAcross(sites)) {
|
|
7665
|
+
const involved = sites.filter(entry => readsField(entry.insight, field));
|
|
7666
|
+
insights.push({
|
|
7667
|
+
field: field,
|
|
7668
|
+
reads: groqConditionDescribe.dedupeReads(involved.flatMap(entry => fieldReads(entry.insight, field))),
|
|
7669
|
+
involvedIn: involved.map(entry => entry.site),
|
|
7670
|
+
proposals: await verifyProposals({
|
|
7671
|
+
field: field,
|
|
7672
|
+
involved: involved,
|
|
7673
|
+
snapshot: snapshot
|
|
7674
|
+
})
|
|
7478
7675
|
});
|
|
7479
|
-
}
|
|
7480
|
-
|
|
7481
|
-
subworkflows: subworkflows,
|
|
7482
|
-
history: history,
|
|
7483
|
-
lastChangedAt: now
|
|
7484
|
-
}).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
|
|
7676
|
+
}
|
|
7677
|
+
return insights;
|
|
7485
7678
|
}
|
|
7486
7679
|
|
|
7487
|
-
function
|
|
7488
|
-
const
|
|
7489
|
-
|
|
7490
|
-
at: child.completedAt,
|
|
7491
|
-
stage: child.currentStage,
|
|
7492
|
-
...status === "aborted" ? {
|
|
7493
|
-
aborted: !0
|
|
7494
|
-
} : {}
|
|
7495
|
-
};
|
|
7680
|
+
function fieldsReadAcross(sites) {
|
|
7681
|
+
const names = sites.flatMap(entry => entry.insight.analysis.reads).filter(read => read.variable === "fields").map(read => read.path[0]).filter(head => typeof head == "string");
|
|
7682
|
+
return [ ...new Set(names) ];
|
|
7496
7683
|
}
|
|
7497
7684
|
|
|
7498
|
-
function
|
|
7499
|
-
return
|
|
7500
|
-
_key: randomKey(),
|
|
7501
|
-
_type: "subworkflowResolved",
|
|
7502
|
-
at: at,
|
|
7503
|
-
activity: row.activity,
|
|
7504
|
-
instanceRef: row.ref,
|
|
7505
|
-
status: status
|
|
7506
|
-
};
|
|
7685
|
+
function fieldReads(insight, field) {
|
|
7686
|
+
return insight.analysis.reads.filter(read => read.variable === "fields" && read.path[0] === field);
|
|
7507
7687
|
}
|
|
7508
7688
|
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
if (loaded === void 0) return;
|
|
7512
|
-
const {child: child, parent: parent} = loaded, definition = invariants.parseDefinitionSnapshot(parent), ctx = await buildEngineContext({
|
|
7513
|
-
client: client,
|
|
7514
|
-
clientForGdr: clientForGdr,
|
|
7515
|
-
refSurface: refSurface,
|
|
7516
|
-
instance: parent,
|
|
7517
|
-
definition: definition,
|
|
7518
|
-
...clock ? {
|
|
7519
|
-
clock: clock
|
|
7520
|
-
} : {},
|
|
7521
|
-
...actor ? {
|
|
7522
|
-
actor: actor
|
|
7523
|
-
} : {},
|
|
7524
|
-
...executionContext ? {
|
|
7525
|
-
executionContext: executionContext
|
|
7526
|
-
} : {},
|
|
7527
|
-
...telemetry ? {
|
|
7528
|
-
telemetry: telemetry
|
|
7529
|
-
} : {}
|
|
7530
|
-
}), mutation = startMutation(parent), row = mutation.subworkflows.find(r => invariants.toBareId(r.ref.id) === child._id);
|
|
7531
|
-
if (row === void 0) {
|
|
7532
|
-
await recordOrphanedPropagation({
|
|
7533
|
-
ctx: ctx,
|
|
7534
|
-
mutation: mutation,
|
|
7535
|
-
child: child
|
|
7536
|
-
});
|
|
7537
|
-
return;
|
|
7538
|
-
}
|
|
7539
|
-
const changed = stampResolvedChild({
|
|
7540
|
-
mutation: mutation,
|
|
7541
|
-
row: row,
|
|
7542
|
-
child: child,
|
|
7543
|
-
now: ctx.now
|
|
7544
|
-
}), parentTerminal = parent.completedAt !== void 0;
|
|
7545
|
-
changed && await persist(ctx, mutation), !parentTerminal && (await cascadeAutoTransitions({
|
|
7546
|
-
client: client,
|
|
7547
|
-
instanceId: parent._id,
|
|
7548
|
-
actor: actor,
|
|
7549
|
-
clientForGdr: clientForGdr,
|
|
7550
|
-
refSurface: refSurface,
|
|
7551
|
-
clock: clock,
|
|
7552
|
-
executionContext: executionContext,
|
|
7553
|
-
telemetry: telemetry
|
|
7554
|
-
}), await propagateToAncestors({
|
|
7555
|
-
client: client,
|
|
7556
|
-
instanceId: parent._id,
|
|
7557
|
-
actor: actor,
|
|
7558
|
-
clientForGdr: clientForGdr,
|
|
7559
|
-
refSurface: refSurface,
|
|
7560
|
-
clock: clock,
|
|
7561
|
-
executionContext: executionContext,
|
|
7562
|
-
telemetry: telemetry
|
|
7563
|
-
}));
|
|
7689
|
+
function readsField(insight, field) {
|
|
7690
|
+
return fieldReads(insight, field).length > 0;
|
|
7564
7691
|
}
|
|
7565
7692
|
|
|
7566
|
-
async function
|
|
7567
|
-
const
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7693
|
+
async function verifyProposals({field: field, involved: involved, snapshot: snapshot}) {
|
|
7694
|
+
const proposals = [];
|
|
7695
|
+
for (const assign of candidateAssignments(involved, field)) {
|
|
7696
|
+
const consequences = [];
|
|
7697
|
+
for (const entry of involved) {
|
|
7698
|
+
const result = await groqConditionDescribe.whatIfCondition({
|
|
7699
|
+
condition: entry.condition,
|
|
7700
|
+
dataset: snapshot.docs,
|
|
7701
|
+
params: entry.params,
|
|
7702
|
+
assign: assign
|
|
7703
|
+
});
|
|
7704
|
+
result.changed && consequences.push({
|
|
7705
|
+
site: entry.site,
|
|
7706
|
+
before: result.before,
|
|
7707
|
+
after: result.after
|
|
7708
|
+
});
|
|
7709
|
+
}
|
|
7710
|
+
consequences.length > 0 && proposals.push({
|
|
7711
|
+
assign: assign,
|
|
7712
|
+
consequences: consequences
|
|
7713
|
+
});
|
|
7714
|
+
}
|
|
7715
|
+
return proposals;
|
|
7576
7716
|
}
|
|
7577
7717
|
|
|
7578
|
-
function
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
return resolved === void 0 ? !1 : (row.resolved = resolved, mutation.history.push(subworkflowResolvedEntry({
|
|
7582
|
-
row: row,
|
|
7583
|
-
at: now,
|
|
7584
|
-
status: resolved.aborted === !0 ? "aborted" : "done"
|
|
7585
|
-
})), !0);
|
|
7718
|
+
function candidateAssignments(involved, field) {
|
|
7719
|
+
const candidates = involved.flatMap(entry => entry.insight.blockedBy).flatMap(atom => atom.requirement !== void 0 ? [ atom.requirement ] : []).filter(requirement => requirement.target.variable === "fields").filter(requirement => requirement.target.path[0] === field).flatMap(assignmentFor).filter(fabricatable);
|
|
7720
|
+
return groqConditionDescribe.dedupeBy(candidates, assignment => JSON.stringify([ assignment.target.path, assignment.value ]));
|
|
7586
7721
|
}
|
|
7587
7722
|
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7723
|
+
function assignmentFor(requirement) {
|
|
7724
|
+
switch (requirement.kind) {
|
|
7725
|
+
case "equals":
|
|
7726
|
+
return [ {
|
|
7727
|
+
target: requirement.target,
|
|
7728
|
+
value: requirement.value
|
|
7729
|
+
} ];
|
|
7730
|
+
|
|
7731
|
+
case "truthy":
|
|
7732
|
+
return [ {
|
|
7733
|
+
target: requirement.target,
|
|
7734
|
+
value: !0
|
|
7735
|
+
} ];
|
|
7736
|
+
|
|
7737
|
+
case "falsy":
|
|
7738
|
+
return [ {
|
|
7739
|
+
target: requirement.target,
|
|
7740
|
+
value: !1
|
|
7741
|
+
} ];
|
|
7742
|
+
|
|
7743
|
+
case "differs":
|
|
7744
|
+
case "defined":
|
|
7745
|
+
case "undefined":
|
|
7746
|
+
case "compares":
|
|
7747
|
+
return [];
|
|
7748
|
+
}
|
|
7600
7749
|
}
|
|
7601
7750
|
|
|
7602
|
-
function
|
|
7603
|
-
return
|
|
7604
|
-
minReaderModel: invariants.minReaderModelOf(instance),
|
|
7605
|
-
currentStage: instance.currentStage,
|
|
7606
|
-
fields: (instance.fields ?? []).map(s => ({
|
|
7607
|
-
...s
|
|
7608
|
-
})),
|
|
7609
|
-
stages: instance.stages.map(s => ({
|
|
7610
|
-
...s,
|
|
7611
|
-
fields: (s.fields ?? []).map(entry => ({
|
|
7612
|
-
...entry
|
|
7613
|
-
})),
|
|
7614
|
-
activities: s.activities.map(t => ({
|
|
7615
|
-
...t,
|
|
7616
|
-
...t.fields !== void 0 ? {
|
|
7617
|
-
fields: t.fields.map(entry => ({
|
|
7618
|
-
...entry
|
|
7619
|
-
}))
|
|
7620
|
-
} : {}
|
|
7621
|
-
}))
|
|
7622
|
-
})),
|
|
7623
|
-
subworkflows: (instance.subworkflows ?? []).map(row => ({
|
|
7624
|
-
...row,
|
|
7625
|
-
...row.abortPending !== void 0 ? {
|
|
7626
|
-
abortPending: {
|
|
7627
|
-
...row.abortPending
|
|
7628
|
-
}
|
|
7629
|
-
} : {},
|
|
7630
|
-
...row.resolved !== void 0 ? {
|
|
7631
|
-
resolved: {
|
|
7632
|
-
...row.resolved
|
|
7633
|
-
}
|
|
7634
|
-
} : {}
|
|
7635
|
-
})),
|
|
7636
|
-
pendingEffects: [ ...instance.pendingEffects ],
|
|
7637
|
-
effectHistory: [ ...instance.effectHistory ],
|
|
7638
|
-
context: [ ...instance.context ],
|
|
7639
|
-
history: [ ...instance.history ],
|
|
7640
|
-
processedRequests: [ ...instance.processedRequests ?? [] ],
|
|
7641
|
-
lastChangedAt: instance.lastChangedAt,
|
|
7642
|
-
...instance.completedAt !== void 0 ? {
|
|
7643
|
-
completedAt: instance.completedAt
|
|
7644
|
-
} : {},
|
|
7645
|
-
...instance.abortedAt !== void 0 ? {
|
|
7646
|
-
abortedAt: instance.abortedAt
|
|
7647
|
-
} : {},
|
|
7648
|
-
pendingCreates: []
|
|
7649
|
-
};
|
|
7751
|
+
function fabricatable(assignment) {
|
|
7752
|
+
return assignment.target.path.every(segment => typeof segment != "number" || segment <= groqConditionDescribe.MAX_COUNTERFACTUAL_INDEX);
|
|
7650
7753
|
}
|
|
7651
7754
|
|
|
7652
|
-
function
|
|
7653
|
-
const
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
} : {}
|
|
7669
|
-
};
|
|
7670
|
-
return {
|
|
7671
|
-
...invariants.modelStampFor({
|
|
7672
|
-
documentType: "instance",
|
|
7673
|
-
document: state,
|
|
7674
|
-
storedMinReaderModel: src.minReaderModel
|
|
7675
|
-
}),
|
|
7676
|
-
...state
|
|
7677
|
-
};
|
|
7755
|
+
async function subjectResourceGrants(args) {
|
|
7756
|
+
const {clientForGdr: clientForGdr, instance: instance} = args, clients = /* @__PURE__ */ new Map;
|
|
7757
|
+
for (const {parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
|
|
7758
|
+
const key = invariants.resourceGdr(resource);
|
|
7759
|
+
clients.has(key) || clients.set(key, {
|
|
7760
|
+
resource: resource,
|
|
7761
|
+
client: clientForGdr(parsed)
|
|
7762
|
+
});
|
|
7763
|
+
}
|
|
7764
|
+
const resolved = await Promise.all([ ...clients.entries() ].map(async ([key, entry]) => {
|
|
7765
|
+
const path = aclPathForResource(entry.resource);
|
|
7766
|
+
if (path === void 0) return;
|
|
7767
|
+
const grants = await grantsForClientPath(entry.client, path);
|
|
7768
|
+
return grants === void 0 ? void 0 : [ key, grants ];
|
|
7769
|
+
}));
|
|
7770
|
+
return new Map(resolved.filter(entry => entry !== void 0));
|
|
7678
7771
|
}
|
|
7679
7772
|
|
|
7680
|
-
function
|
|
7681
|
-
const
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7773
|
+
async function evaluateInstance(args) {
|
|
7774
|
+
const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
|
|
7775
|
+
invariants.validateTag(tag);
|
|
7776
|
+
const {actor: actor, grants: grants} = await resolveAccess(client, {
|
|
7777
|
+
...args.grantsFromPath !== void 0 ? {
|
|
7778
|
+
grantsFromPath: args.grantsFromPath
|
|
7779
|
+
} : {}
|
|
7780
|
+
}), instance = await reload({
|
|
7781
|
+
client: client,
|
|
7782
|
+
instanceId: instanceId,
|
|
7783
|
+
tag: tag
|
|
7784
|
+
}), definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
|
|
7785
|
+
client: client,
|
|
7786
|
+
workflowResource: workflowResource,
|
|
7787
|
+
resourceClients: resourceClients
|
|
7788
|
+
}), snapshot = await hydrateSnapshot({
|
|
7789
|
+
client: client,
|
|
7790
|
+
clientForGdr: clientForGdr,
|
|
7791
|
+
instance: instance
|
|
7792
|
+
}), guards = await verdictGuardsForInstance(client, instance._id), resourceGrants = await subjectResourceGrants({
|
|
7793
|
+
clientForGdr: clientForGdr,
|
|
7794
|
+
instance: instance
|
|
7795
|
+
});
|
|
7796
|
+
return evaluateFromSnapshot({
|
|
7797
|
+
instance: instance,
|
|
7798
|
+
definition: definition,
|
|
7799
|
+
actor: actor,
|
|
7800
|
+
snapshot: snapshot,
|
|
7801
|
+
guards: guards,
|
|
7802
|
+
now: now,
|
|
7803
|
+
resourceGrants: resourceGrants,
|
|
7804
|
+
...grants !== void 0 ? {
|
|
7805
|
+
grants: grants
|
|
7806
|
+
} : {}
|
|
7807
|
+
});
|
|
7687
7808
|
}
|
|
7688
7809
|
|
|
7689
|
-
function
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
context: mutation.context,
|
|
7697
|
-
pendingEffects: mutation.pendingEffects,
|
|
7698
|
-
effectHistory: mutation.effectHistory
|
|
7810
|
+
function memoizedByName(render) {
|
|
7811
|
+
const rendered = /* @__PURE__ */ new Map;
|
|
7812
|
+
return activityName => {
|
|
7813
|
+
const hit = rendered.get(activityName);
|
|
7814
|
+
if (hit !== void 0) return hit;
|
|
7815
|
+
const scope = render(activityName);
|
|
7816
|
+
return rendered.set(activityName, scope), scope;
|
|
7699
7817
|
};
|
|
7700
7818
|
}
|
|
7701
7819
|
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
if (pendingCreates.length === 0) return ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev).commit(SYNC_COMMIT);
|
|
7709
|
-
const tx = ctx.client.transaction();
|
|
7710
|
-
for (const {body: body} of pendingCreates) tx.create(body);
|
|
7711
|
-
tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
|
|
7712
|
-
await tx.commit(), mutation.pendingCreates = [];
|
|
7713
|
-
const actorForPriming = ctx.actor;
|
|
7714
|
-
for (const {body: body, started: started} of pendingCreates) try {
|
|
7715
|
-
await primeInitialStage({
|
|
7716
|
-
client: ctx.client,
|
|
7717
|
-
instanceId: body._id,
|
|
7718
|
-
actor: actorForPriming,
|
|
7719
|
-
clientForGdr: ctx.clientForGdr,
|
|
7720
|
-
refSurface: ctx.refSurface,
|
|
7721
|
-
clock: ctx.clock,
|
|
7722
|
-
executionContext: ctx.executionContext,
|
|
7723
|
-
telemetry: ctx.telemetry
|
|
7724
|
-
}), await cascadeAutoTransitions({
|
|
7725
|
-
client: ctx.client,
|
|
7726
|
-
instanceId: body._id,
|
|
7727
|
-
actor: actorForPriming,
|
|
7728
|
-
clientForGdr: ctx.clientForGdr,
|
|
7729
|
-
refSurface: ctx.refSurface,
|
|
7730
|
-
clock: ctx.clock,
|
|
7731
|
-
executionContext: ctx.executionContext,
|
|
7732
|
-
telemetry: ctx.telemetry
|
|
7733
|
-
}), await propagateToAncestors({
|
|
7734
|
-
client: ctx.client,
|
|
7735
|
-
instanceId: body._id,
|
|
7736
|
-
actor: actorForPriming,
|
|
7737
|
-
clientForGdr: ctx.clientForGdr,
|
|
7738
|
-
refSurface: ctx.refSurface,
|
|
7739
|
-
clock: ctx.clock,
|
|
7740
|
-
executionContext: ctx.executionContext,
|
|
7741
|
-
telemetry: ctx.telemetry
|
|
7742
|
-
}), ctx.telemetry.log(WorkflowInstanceStarted, started);
|
|
7743
|
-
} catch (cause) {
|
|
7744
|
-
throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
|
|
7745
|
-
instanceId: ctx.instance._id,
|
|
7746
|
-
guardError: cause,
|
|
7747
|
-
reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
|
|
7820
|
+
function currentStageOf(instance, definition) {
|
|
7821
|
+
try {
|
|
7822
|
+
return findStage(definition, instance.currentStage);
|
|
7823
|
+
} catch (err) {
|
|
7824
|
+
throw new Error(`Instance "${instance._id}" currentStage "${instance.currentStage}" not in definition`, {
|
|
7825
|
+
cause: err
|
|
7748
7826
|
});
|
|
7749
7827
|
}
|
|
7750
|
-
const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
|
|
7751
|
-
if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
|
|
7752
|
-
return reloaded;
|
|
7753
7828
|
}
|
|
7754
7829
|
|
|
7755
|
-
function
|
|
7756
|
-
const
|
|
7757
|
-
|
|
7758
|
-
|
|
7830
|
+
async function explainSite(args) {
|
|
7831
|
+
const {site: site, condition: condition, params: params, snapshot: snapshot, sites: sites} = args, insight = await groqConditionDescribe.explainCondition({
|
|
7832
|
+
condition: condition,
|
|
7833
|
+
dataset: snapshot.docs,
|
|
7834
|
+
params: params
|
|
7835
|
+
});
|
|
7836
|
+
return sites.push({
|
|
7837
|
+
site: site,
|
|
7838
|
+
condition: condition,
|
|
7839
|
+
params: params,
|
|
7840
|
+
insight: insight
|
|
7841
|
+
}), insight;
|
|
7759
7842
|
}
|
|
7760
7843
|
|
|
7761
|
-
function
|
|
7762
|
-
const
|
|
7763
|
-
|
|
7764
|
-
|
|
7844
|
+
async function evaluateFromSnapshot(args) {
|
|
7845
|
+
const {instance: instance, definition: definition, actor: actor, grants: grants, snapshot: snapshot} = args, now = args.now ?? wallClock(), stage = currentStageOf(instance, definition), autonomy = autonomyOf(definition), stageAutonomy2 = stageAutonomyOf(autonomy, stage.name), fireConsequence = (activity, action) => whatIfFireAction({
|
|
7846
|
+
instance: instance,
|
|
7847
|
+
definition: definition,
|
|
7848
|
+
snapshot: snapshot,
|
|
7849
|
+
now: now,
|
|
7850
|
+
actor: actor,
|
|
7851
|
+
stage: stage,
|
|
7852
|
+
activity: activity,
|
|
7853
|
+
action: action
|
|
7854
|
+
}), scopeSource = {
|
|
7855
|
+
instance: instance,
|
|
7856
|
+
definition: definition,
|
|
7857
|
+
snapshot: snapshot,
|
|
7858
|
+
now: now
|
|
7859
|
+
}, can = await advisoryCan({
|
|
7860
|
+
instance: instance,
|
|
7861
|
+
actor: actor,
|
|
7862
|
+
grants: grants
|
|
7863
|
+
}), scope = await renderConditionScope(scopeSource, {
|
|
7864
|
+
actor: actor,
|
|
7865
|
+
vars: {
|
|
7866
|
+
can: can
|
|
7867
|
+
}
|
|
7868
|
+
}), scopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
|
|
7869
|
+
activityName: activityName,
|
|
7870
|
+
actor: actor,
|
|
7871
|
+
vars: {
|
|
7872
|
+
can: can
|
|
7873
|
+
}
|
|
7874
|
+
})), cascadeScopeForActivity = memoizedByName(activityName => renderConditionScope(scopeSource, {
|
|
7875
|
+
activityName: activityName
|
|
7876
|
+
})), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
|
|
7877
|
+
instance: instance,
|
|
7878
|
+
actor: actor,
|
|
7879
|
+
guards: args.guards
|
|
7880
|
+
}), subjectDenials = await forecastSubjectDenials({
|
|
7881
|
+
instance: instance,
|
|
7882
|
+
actor: actor,
|
|
7883
|
+
snapshot: snapshot,
|
|
7884
|
+
resourceGrants: args.resourceGrants
|
|
7885
|
+
}), subjectPermissionReason = subjectDenials.length > 0 ? {
|
|
7886
|
+
kind: "subject-permission-denied",
|
|
7887
|
+
denied: subjectDenials
|
|
7888
|
+
} : void 0, sites = [], activityEvaluations = [];
|
|
7889
|
+
for (const activity of stage.activities ?? []) activityEvaluations.push(await evaluateActivity({
|
|
7890
|
+
activity: activity,
|
|
7891
|
+
statusEntry: currentActivityEntries.find(t => t.name === activity.name),
|
|
7892
|
+
instance: instance,
|
|
7893
|
+
snapshot: snapshot,
|
|
7894
|
+
activityScope: await scopeForActivity(activity.name),
|
|
7895
|
+
cascadeActivityScope: () => cascadeScopeForActivity(activity.name),
|
|
7896
|
+
stageHasExits: !isTerminalStage(stage),
|
|
7897
|
+
guardDenial: guardDenial,
|
|
7898
|
+
subjectPermissionReason: subjectPermissionReason,
|
|
7899
|
+
sites: sites,
|
|
7900
|
+
autonomy: activityAutonomyOf(stageAutonomy2, activity.name),
|
|
7901
|
+
fireConsequence: fireConsequence
|
|
7902
|
+
}));
|
|
7903
|
+
const cascadeParams = await renderConditionScope(scopeSource), transitionEvaluations = [];
|
|
7904
|
+
for (const transition of stage.transitions ?? []) {
|
|
7905
|
+
const insight = await explainSite({
|
|
7906
|
+
site: {
|
|
7907
|
+
kind: "transition",
|
|
7908
|
+
transition: transition.name
|
|
7909
|
+
},
|
|
7910
|
+
condition: transition.when,
|
|
7911
|
+
params: cascadeParams,
|
|
7912
|
+
snapshot: snapshot,
|
|
7913
|
+
sites: sites
|
|
7914
|
+
});
|
|
7915
|
+
transitionEvaluations.push({
|
|
7916
|
+
transition: transition,
|
|
7917
|
+
whenSatisfied: insight.outcome === "satisfied",
|
|
7918
|
+
unevaluable: insight.outcome === "unevaluable",
|
|
7919
|
+
insight: insight
|
|
7920
|
+
});
|
|
7921
|
+
}
|
|
7922
|
+
const currentStage = {
|
|
7923
|
+
stage: stage,
|
|
7924
|
+
activities: activityEvaluations,
|
|
7925
|
+
transitions: transitionEvaluations,
|
|
7926
|
+
autonomy: stageAutonomy2
|
|
7927
|
+
}, pendingOnYou = activityEvaluations.filter(t => t.pendingOnActor), canInteract = activityEvaluations.some(t => t.actions.some(a => a.allowed)), editGuardDenial = guardDenial?.kind === "mutation-guard-denied" ? guardDenial : void 0, editableFields = await evaluateEditableFields({
|
|
7928
|
+
instance: instance,
|
|
7929
|
+
definition: definition,
|
|
7930
|
+
stage: stage,
|
|
7931
|
+
snapshot: snapshot,
|
|
7932
|
+
scope: scope,
|
|
7933
|
+
scopeForActivity: scopeForActivity,
|
|
7934
|
+
guardDenial: editGuardDenial,
|
|
7935
|
+
sites: sites
|
|
7936
|
+
});
|
|
7937
|
+
return {
|
|
7938
|
+
instance: instance,
|
|
7939
|
+
definition: definition,
|
|
7940
|
+
actor: actor,
|
|
7941
|
+
currentStage: currentStage,
|
|
7942
|
+
pendingOnYou: pendingOnYou,
|
|
7943
|
+
canInteract: canInteract,
|
|
7944
|
+
editableFields: editableFields,
|
|
7945
|
+
fieldInsights: await buildFieldInsights({
|
|
7946
|
+
sites: sites,
|
|
7947
|
+
snapshot: snapshot
|
|
7948
|
+
}),
|
|
7949
|
+
autonomy: autonomy
|
|
7950
|
+
};
|
|
7765
7951
|
}
|
|
7766
7952
|
|
|
7767
|
-
|
|
7768
|
-
return currentStageEntry(mutation).activities;
|
|
7769
|
-
}
|
|
7953
|
+
const AUTONOMY_CACHE = /* @__PURE__ */ new WeakMap;
|
|
7770
7954
|
|
|
7771
|
-
function
|
|
7772
|
-
const
|
|
7773
|
-
if (
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
activity: activity
|
|
7777
|
-
};
|
|
7955
|
+
function autonomyOf(definition) {
|
|
7956
|
+
const hit = AUTONOMY_CACHE.get(definition);
|
|
7957
|
+
if (hit !== void 0) return hit;
|
|
7958
|
+
const derived = deriveWorkflowAutonomy(definition);
|
|
7959
|
+
return AUTONOMY_CACHE.set(definition, derived), derived;
|
|
7778
7960
|
}
|
|
7779
7961
|
|
|
7780
|
-
function
|
|
7781
|
-
const
|
|
7782
|
-
|
|
7783
|
-
|
|
7962
|
+
async function evaluateEditableFields(args) {
|
|
7963
|
+
const {instance: instance, definition: definition, stage: stage, snapshot: snapshot, scope: scope, scopeForActivity: scopeForActivity, guardDenial: guardDenial, sites: sites} = args, fields = [];
|
|
7964
|
+
for (const site of editableFieldsInStage(definition, stage)) {
|
|
7965
|
+
const window = fieldWindowOpen(instance, site), insight = await editPredicateInsight({
|
|
7966
|
+
site: site,
|
|
7967
|
+
snapshot: snapshot,
|
|
7968
|
+
scope: scope,
|
|
7969
|
+
scopeForActivity: scopeForActivity,
|
|
7970
|
+
sites: sites
|
|
7971
|
+
}), predicateSatisfied = insight === void 0 || insight.outcome === "satisfied", reason = editDisabledReason({
|
|
7972
|
+
effective: site.effective,
|
|
7973
|
+
instance: instance,
|
|
7974
|
+
window: window,
|
|
7975
|
+
guardDenial: guardDenial,
|
|
7976
|
+
predicateSatisfied: predicateSatisfied
|
|
7977
|
+
}), value = readFieldValue(instance, site);
|
|
7978
|
+
fields.push({
|
|
7979
|
+
scope: site.scope,
|
|
7980
|
+
...site.activity !== void 0 ? {
|
|
7981
|
+
activity: site.activity
|
|
7982
|
+
} : {},
|
|
7983
|
+
name: site.name,
|
|
7984
|
+
type: site.type,
|
|
7985
|
+
...site.title !== void 0 ? {
|
|
7986
|
+
title: site.title
|
|
7987
|
+
} : {},
|
|
7988
|
+
...site.validation !== void 0 ? {
|
|
7989
|
+
validation: site.validation
|
|
7990
|
+
} : {},
|
|
7991
|
+
value: value,
|
|
7992
|
+
editable: reason === void 0,
|
|
7993
|
+
...reason !== void 0 ? {
|
|
7994
|
+
disabledReason: reason
|
|
7995
|
+
} : {},
|
|
7996
|
+
...fieldProvenance(instance, site.ref),
|
|
7997
|
+
...insight !== void 0 ? {
|
|
7998
|
+
insight: insight
|
|
7999
|
+
} : {}
|
|
8000
|
+
});
|
|
8001
|
+
}
|
|
8002
|
+
return fields;
|
|
7784
8003
|
}
|
|
7785
8004
|
|
|
7786
|
-
function
|
|
7787
|
-
|
|
8005
|
+
async function editPredicateInsight(args) {
|
|
8006
|
+
const {site: site, snapshot: snapshot, scope: scope, scopeForActivity: scopeForActivity, sites: sites} = args;
|
|
8007
|
+
if (typeof site.effective != "string") return;
|
|
8008
|
+
const params = site.scope === "activity" && site.activity !== void 0 ? await scopeForActivity(site.activity) : scope;
|
|
8009
|
+
return explainSite({
|
|
8010
|
+
site: {
|
|
8011
|
+
kind: "editable-field",
|
|
8012
|
+
scope: site.scope,
|
|
8013
|
+
name: site.name,
|
|
8014
|
+
...site.activity !== void 0 ? {
|
|
8015
|
+
activity: site.activity
|
|
8016
|
+
} : {}
|
|
8017
|
+
},
|
|
8018
|
+
condition: site.effective,
|
|
8019
|
+
params: params,
|
|
8020
|
+
snapshot: snapshot,
|
|
8021
|
+
sites: sites
|
|
8022
|
+
});
|
|
7788
8023
|
}
|
|
7789
8024
|
|
|
7790
|
-
function
|
|
7791
|
-
|
|
8025
|
+
async function forecastSubjectDenials(args) {
|
|
8026
|
+
const {instance: instance, actor: actor, snapshot: snapshot, resourceGrants: resourceGrants} = args;
|
|
8027
|
+
if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
|
|
8028
|
+
const denials = [], seen = /* @__PURE__ */ new Set;
|
|
8029
|
+
for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
|
|
8030
|
+
if (seen.has(ref.id)) continue;
|
|
8031
|
+
seen.add(ref.id);
|
|
8032
|
+
const grants = resourceGrants.get(invariants.resourceGdr(resource));
|
|
8033
|
+
if (grants === void 0) continue;
|
|
8034
|
+
const doc = snapshot.docs.find(d => d._id === ref.id);
|
|
8035
|
+
doc !== void 0 && await subjectUpdateAllowed({
|
|
8036
|
+
doc: doc,
|
|
8037
|
+
parsed: parsed,
|
|
8038
|
+
grants: grants,
|
|
8039
|
+
actorId: actor.id
|
|
8040
|
+
}) === !1 && denials.push({
|
|
8041
|
+
subject: ref.id,
|
|
8042
|
+
resource: invariants.resourceGdr(resource),
|
|
8043
|
+
permission: "update"
|
|
8044
|
+
});
|
|
8045
|
+
}
|
|
8046
|
+
return denials;
|
|
7792
8047
|
}
|
|
7793
8048
|
|
|
7794
|
-
async function
|
|
7795
|
-
const {
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
requestRecord: requestRecord,
|
|
7811
|
-
actor: options.actor
|
|
7812
|
-
}),
|
|
7813
|
-
onExhausted: () => new ConcurrentCompleteEffectError({
|
|
7814
|
-
instanceId: instanceId,
|
|
7815
|
-
effectKey: effectKey,
|
|
7816
|
-
attempts: CONCURRENT_COMMIT_MAX_ATTEMPTS
|
|
7817
|
-
})
|
|
7818
|
-
});
|
|
8049
|
+
async function subjectUpdateAllowed(args) {
|
|
8050
|
+
const {doc: doc, parsed: parsed, grants: grants, actorId: actorId} = args;
|
|
8051
|
+
try {
|
|
8052
|
+
return await grantsPermissionOn({
|
|
8053
|
+
document: {
|
|
8054
|
+
...doc,
|
|
8055
|
+
_id: parsed.documentId
|
|
8056
|
+
},
|
|
8057
|
+
grants: grants,
|
|
8058
|
+
permission: "update",
|
|
8059
|
+
userId: actorId
|
|
8060
|
+
});
|
|
8061
|
+
} catch (err) {
|
|
8062
|
+
console.warn(`workflow: subject-write forecast skipped for "${doc._id}" — evaluating that resource's grants failed (the lake still enforces the write). Original error: ${invariants.errorMessage(err)}`);
|
|
8063
|
+
return;
|
|
8064
|
+
}
|
|
7819
8065
|
}
|
|
7820
8066
|
|
|
7821
|
-
function
|
|
7822
|
-
const {
|
|
8067
|
+
async function evaluateActivity(args) {
|
|
8068
|
+
const {activity: activity, statusEntry: statusEntry, instance: instance, snapshot: snapshot, activityScope: activityScope, cascadeActivityScope: cascadeActivityScope, stageHasExits: stageHasExits, guardDenial: guardDenial, subjectPermissionReason: subjectPermissionReason, sites: sites, autonomy: autonomy, fireConsequence: fireConsequence} = args, status = statusEntry?.status ?? "skipped", assigned = activityScope.assigned === !0, {unmetRequirements: unmetRequirements, ...conditionInsights} = await explainActivityConditions({
|
|
8069
|
+
activity: activity,
|
|
8070
|
+
activityScope: activityScope,
|
|
8071
|
+
cascadeActivityScope: cascadeActivityScope,
|
|
8072
|
+
snapshot: snapshot,
|
|
8073
|
+
sites: sites
|
|
8074
|
+
}), requirementsReason = unmetRequirements.length > 0 ? {
|
|
8075
|
+
kind: "requirements-unmet",
|
|
8076
|
+
unmetRequirements: unmetRequirements
|
|
8077
|
+
} : void 0, actions = [];
|
|
8078
|
+
for (const action of activity.actions ?? []) actions.push(await evaluateAction({
|
|
8079
|
+
action: action,
|
|
8080
|
+
activityName: activity.name,
|
|
8081
|
+
status: status,
|
|
8082
|
+
instance: instance,
|
|
8083
|
+
snapshot: snapshot,
|
|
8084
|
+
activityScope: activityScope,
|
|
8085
|
+
cascadeActivityScope: cascadeActivityScope,
|
|
8086
|
+
stageHasExits: stageHasExits,
|
|
8087
|
+
guardDenial: guardDenial,
|
|
8088
|
+
subjectPermissionReason: subjectPermissionReason,
|
|
8089
|
+
requirementsReason: requirementsReason,
|
|
8090
|
+
sites: sites,
|
|
8091
|
+
fireConsequence: a => fireConsequence(activity, a)
|
|
8092
|
+
}));
|
|
7823
8093
|
return {
|
|
7824
|
-
|
|
7825
|
-
name: pending.name,
|
|
7826
|
-
...pending.title !== void 0 ? {
|
|
7827
|
-
title: pending.title
|
|
7828
|
-
} : {},
|
|
7829
|
-
...pending.description !== void 0 ? {
|
|
7830
|
-
description: pending.description
|
|
7831
|
-
} : {},
|
|
7832
|
-
params: pending.params,
|
|
7833
|
-
origin: pending.origin,
|
|
7834
|
-
...resolvedActor !== void 0 ? {
|
|
7835
|
-
actor: resolvedActor
|
|
7836
|
-
} : {},
|
|
7837
|
-
...pending.stageEntryKey !== void 0 ? {
|
|
7838
|
-
stageEntryKey: pending.stageEntryKey
|
|
7839
|
-
} : {},
|
|
7840
|
-
ranAt: ranAt,
|
|
7841
|
-
...durationMs !== void 0 ? {
|
|
7842
|
-
durationMs: durationMs
|
|
7843
|
-
} : {},
|
|
8094
|
+
activity: activity,
|
|
7844
8095
|
status: status,
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
8096
|
+
kind: invariants.deriveActivityKind(activity),
|
|
8097
|
+
classification: invariants.deriveExecutorClassification(activity),
|
|
8098
|
+
autonomy: autonomy,
|
|
8099
|
+
pendingOnActor: status === "active" && assigned,
|
|
8100
|
+
scopedOut: isFilterScopedOut({
|
|
8101
|
+
status: status,
|
|
8102
|
+
startedAt: statusEntry?.startedAt
|
|
8103
|
+
}),
|
|
8104
|
+
...unmetRequirements.length > 0 ? {
|
|
8105
|
+
unmetRequirements: unmetRequirements
|
|
7850
8106
|
} : {},
|
|
7851
|
-
...
|
|
7852
|
-
|
|
7853
|
-
} : {}
|
|
8107
|
+
...conditionInsights,
|
|
8108
|
+
actions: actions
|
|
7854
8109
|
};
|
|
7855
8110
|
}
|
|
7856
8111
|
|
|
7857
|
-
function
|
|
7858
|
-
const
|
|
8112
|
+
async function explainActivityConditions({activity: activity, activityScope: activityScope, cascadeActivityScope: cascadeActivityScope, snapshot: snapshot, sites: sites}) {
|
|
8113
|
+
const explainAt = (site, condition) => explainSite({
|
|
8114
|
+
site: site,
|
|
8115
|
+
condition: condition,
|
|
8116
|
+
params: activityScope,
|
|
8117
|
+
snapshot: snapshot,
|
|
8118
|
+
sites: sites
|
|
8119
|
+
}), requirementEntries = [];
|
|
8120
|
+
for (const [name, condition] of Object.entries(activity.requirements ?? {})) requirementEntries.push([ name, await explainAt({
|
|
8121
|
+
kind: "requirement",
|
|
8122
|
+
activity: activity.name,
|
|
8123
|
+
requirement: name
|
|
8124
|
+
}, condition) ]);
|
|
8125
|
+
const requirementInsights = Object.fromEntries(requirementEntries), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([name]) => name), filterInsight = activity.filter !== void 0 ? await explainSite({
|
|
8126
|
+
site: {
|
|
8127
|
+
kind: "activity-filter",
|
|
8128
|
+
activity: activity.name
|
|
8129
|
+
},
|
|
8130
|
+
condition: activity.filter,
|
|
8131
|
+
params: await cascadeActivityScope(),
|
|
8132
|
+
snapshot: snapshot,
|
|
8133
|
+
sites: sites
|
|
8134
|
+
}) : void 0;
|
|
7859
8135
|
return {
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
status: status,
|
|
7868
|
-
...outputs !== void 0 ? {
|
|
7869
|
-
outputs: outputs
|
|
7870
|
-
} : {},
|
|
7871
|
-
...detail !== void 0 ? {
|
|
7872
|
-
detail: detail
|
|
7873
|
-
} : {},
|
|
7874
|
-
...actor !== void 0 ? {
|
|
7875
|
-
actor: actor
|
|
7876
|
-
} : {}
|
|
7877
|
-
}
|
|
8136
|
+
unmetRequirements: unmetRequirements,
|
|
8137
|
+
...activity.requirements !== void 0 ? {
|
|
8138
|
+
requirementInsights: requirementInsights
|
|
8139
|
+
} : {},
|
|
8140
|
+
...filterInsight !== void 0 ? {
|
|
8141
|
+
filterInsight: filterInsight
|
|
8142
|
+
} : {}
|
|
7878
8143
|
};
|
|
7879
8144
|
}
|
|
7880
8145
|
|
|
7881
|
-
function
|
|
7882
|
-
const {
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
}
|
|
7889
|
-
const shapeIssues = effectOutputIssues(shape, value);
|
|
7890
|
-
shapeIssues !== void 0 && issues.push(...shapeIssues.map(i => `"${key}": ${i}`));
|
|
7891
|
-
}
|
|
7892
|
-
if (issues.length > 0) throw new EffectOutputsInvalidError({
|
|
7893
|
-
effect: effectName,
|
|
7894
|
-
issues: issues
|
|
8146
|
+
async function evaluateAction(args) {
|
|
8147
|
+
const {action: action, activityName: activityName, snapshot: snapshot, activityScope: activityScope, sites: sites} = args, conditionScope = invariants.isCascadeFired(action) ? await args.cascadeActivityScope() : activityScope, insights = await explainActionGates({
|
|
8148
|
+
action: action,
|
|
8149
|
+
activityName: activityName,
|
|
8150
|
+
conditionScope: conditionScope,
|
|
8151
|
+
snapshot: snapshot,
|
|
8152
|
+
sites: sites
|
|
7895
8153
|
});
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
entryType: shape.type,
|
|
7901
|
-
value: value,
|
|
7902
|
-
...shape.fields !== void 0 ? {
|
|
7903
|
-
fields: shape.fields
|
|
7904
|
-
} : {},
|
|
7905
|
-
...shape.of !== void 0 ? {
|
|
7906
|
-
of: shape.of
|
|
7907
|
-
} : {},
|
|
7908
|
-
...shape.options !== void 0 ? {
|
|
7909
|
-
options: shape.options
|
|
7910
|
-
} : {},
|
|
7911
|
-
...shape.validation !== void 0 ? {
|
|
7912
|
-
validation: shape.validation
|
|
7913
|
-
} : {}
|
|
8154
|
+
if (action.when !== void 0) return triggeredActionVerdict({
|
|
8155
|
+
action: action,
|
|
8156
|
+
when: action.when,
|
|
8157
|
+
insights: insights
|
|
7914
8158
|
});
|
|
8159
|
+
const verdict = fireableActionVerdict({
|
|
8160
|
+
args: args,
|
|
8161
|
+
insights: insights
|
|
8162
|
+
}), firing = await args.fireConsequence(action);
|
|
8163
|
+
return firing !== void 0 ? {
|
|
8164
|
+
...verdict,
|
|
8165
|
+
firing: firing
|
|
8166
|
+
} : verdict;
|
|
7915
8167
|
}
|
|
7916
8168
|
|
|
7917
|
-
function
|
|
7918
|
-
const
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
8169
|
+
async function explainActionGates({action: action, activityName: activityName, conditionScope: conditionScope, snapshot: snapshot, sites: sites}) {
|
|
8170
|
+
const insight = action.filter !== void 0 ? await explainSite({
|
|
8171
|
+
site: {
|
|
8172
|
+
kind: "action",
|
|
8173
|
+
activity: activityName,
|
|
8174
|
+
action: action.name
|
|
8175
|
+
},
|
|
8176
|
+
condition: action.filter,
|
|
8177
|
+
params: conditionScope,
|
|
8178
|
+
snapshot: snapshot,
|
|
8179
|
+
sites: sites
|
|
8180
|
+
}) : void 0, whenInsight = action.when !== void 0 ? await explainSite({
|
|
8181
|
+
site: {
|
|
8182
|
+
kind: "action-when",
|
|
8183
|
+
activity: activityName,
|
|
8184
|
+
action: action.name
|
|
8185
|
+
},
|
|
8186
|
+
condition: action.when,
|
|
8187
|
+
params: conditionScope,
|
|
8188
|
+
snapshot: snapshot,
|
|
8189
|
+
sites: sites
|
|
8190
|
+
}) : void 0;
|
|
8191
|
+
return {
|
|
8192
|
+
...insight !== void 0 ? {
|
|
8193
|
+
insight: insight
|
|
8194
|
+
} : {},
|
|
8195
|
+
...whenInsight !== void 0 ? {
|
|
8196
|
+
whenInsight: whenInsight
|
|
7932
8197
|
} : {}
|
|
7933
|
-
}
|
|
8198
|
+
};
|
|
7934
8199
|
}
|
|
7935
8200
|
|
|
7936
|
-
function
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
})
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
}
|
|
7952
|
-
|
|
7953
|
-
|
|
8201
|
+
function triggeredActionVerdict({action: action, when: when, insights: insights}) {
|
|
8202
|
+
return insights.insight !== void 0 && insights.insight.outcome === "unsatisfied" ? disabled({
|
|
8203
|
+
action: action,
|
|
8204
|
+
reason: {
|
|
8205
|
+
kind: "filter-failed",
|
|
8206
|
+
filter: action.filter ?? ""
|
|
8207
|
+
},
|
|
8208
|
+
...insights
|
|
8209
|
+
}) : {
|
|
8210
|
+
...actionEvaluationIdentity(action),
|
|
8211
|
+
allowed: !1,
|
|
8212
|
+
triggered: !0,
|
|
8213
|
+
disabledReason: {
|
|
8214
|
+
kind: "cascade-fired",
|
|
8215
|
+
when: when
|
|
8216
|
+
},
|
|
8217
|
+
...insights
|
|
8218
|
+
};
|
|
7954
8219
|
}
|
|
7955
8220
|
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
instance:
|
|
7959
|
-
record: requestRecord,
|
|
7960
|
-
now: ctx.now
|
|
7961
|
-
});
|
|
7962
|
-
const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
|
|
7963
|
-
pending: pending,
|
|
7964
|
-
definition: ctx.definition,
|
|
7965
|
-
status: status,
|
|
7966
|
-
ops: ops,
|
|
7967
|
-
outputs: outputs
|
|
7968
|
-
}), mutation = startMutation(ctx.instance);
|
|
7969
|
-
recordProcessedRequest({
|
|
7970
|
-
mutation: mutation,
|
|
7971
|
-
record: requestRecord,
|
|
7972
|
-
now: ctx.now
|
|
7973
|
-
}), mutation.pendingEffects = mutation.pendingEffects.filter(e => e._key !== effectKey);
|
|
7974
|
-
const ranAt = ctx.now, settlement = buildEffectSettlement(pending, {
|
|
8221
|
+
function fireableActionVerdict({args: args, insights: insights}) {
|
|
8222
|
+
const {action: action, status: status, instance: instance, stageHasExits: stageHasExits, guardDenial: guardDenial} = args, lifecycle = lifecycleReason({
|
|
8223
|
+
instance: instance,
|
|
7975
8224
|
status: status,
|
|
7976
|
-
|
|
7977
|
-
actor: actor,
|
|
7978
|
-
detail: detail,
|
|
7979
|
-
error: error,
|
|
7980
|
-
durationMs: durationMs,
|
|
7981
|
-
outputs: outputs
|
|
8225
|
+
stageHasExits: stageHasExits
|
|
7982
8226
|
});
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
8227
|
+
if (lifecycle !== void 0) return disabled({
|
|
8228
|
+
action: action,
|
|
8229
|
+
reason: lifecycle,
|
|
8230
|
+
...insights
|
|
8231
|
+
});
|
|
8232
|
+
if (guardDenial !== void 0) return disabled({
|
|
8233
|
+
action: action,
|
|
8234
|
+
reason: guardDenial,
|
|
8235
|
+
...insights
|
|
8236
|
+
});
|
|
8237
|
+
if (args.subjectPermissionReason !== void 0 && (action.effects?.length ?? 0) > 0) return disabled({
|
|
8238
|
+
action: action,
|
|
8239
|
+
reason: args.subjectPermissionReason,
|
|
8240
|
+
...insights
|
|
8241
|
+
});
|
|
8242
|
+
if (args.requirementsReason !== void 0) return disabled({
|
|
8243
|
+
action: action,
|
|
8244
|
+
reason: args.requirementsReason,
|
|
8245
|
+
...insights
|
|
8246
|
+
});
|
|
8247
|
+
const {insight: insight} = insights;
|
|
8248
|
+
return action.filter !== void 0 && insight !== void 0 && insight.outcome !== "satisfied" ? disabled({
|
|
8249
|
+
action: action,
|
|
8250
|
+
reason: {
|
|
8251
|
+
kind: "filter-failed",
|
|
8252
|
+
filter: action.filter
|
|
7992
8253
|
},
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
refSurface: ctx.refSurface
|
|
7999
|
-
}), needsGuardRefresh = wroteEffectOutputs || ranOps.some(isFieldOp);
|
|
8000
|
-
return await persistThenMaybeRefresh({
|
|
8001
|
-
ctx: ctx,
|
|
8002
|
-
mutation: mutation,
|
|
8003
|
-
stageName: ctx.instance.currentStage,
|
|
8004
|
-
didChangeState: needsGuardRefresh
|
|
8005
|
-
}), {
|
|
8006
|
-
effectKey: effectKey,
|
|
8007
|
-
effect: pending.name,
|
|
8008
|
-
status: status,
|
|
8009
|
-
origin: pending.origin.kind
|
|
8254
|
+
...insights
|
|
8255
|
+
}) : {
|
|
8256
|
+
...actionEvaluationIdentity(action),
|
|
8257
|
+
allowed: !0,
|
|
8258
|
+
...insights
|
|
8010
8259
|
};
|
|
8011
8260
|
}
|
|
8012
8261
|
|
|
8013
|
-
function
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
...effect.title !== void 0 ? {
|
|
8019
|
-
title: effect.title
|
|
8020
|
-
} : {},
|
|
8021
|
-
...effect.description !== void 0 ? {
|
|
8022
|
-
description: effect.description
|
|
8023
|
-
} : {},
|
|
8024
|
-
...effect.bindings !== void 0 ? {
|
|
8025
|
-
bindings: effect.bindings
|
|
8026
|
-
} : {},
|
|
8027
|
-
params: params,
|
|
8028
|
-
origin: origin,
|
|
8029
|
-
...actor !== void 0 ? {
|
|
8030
|
-
actor: actor
|
|
8031
|
-
} : {},
|
|
8032
|
-
queuedAt: now,
|
|
8033
|
-
...stageEntryKey !== void 0 ? {
|
|
8034
|
-
stageEntryKey: stageEntryKey
|
|
8262
|
+
function actionEvaluationIdentity(action) {
|
|
8263
|
+
return {
|
|
8264
|
+
action: action,
|
|
8265
|
+
...action.semantics !== void 0 ? {
|
|
8266
|
+
semantics: action.semantics
|
|
8035
8267
|
} : {}
|
|
8036
|
-
}, history = {
|
|
8037
|
-
_key: randomKey(),
|
|
8038
|
-
_type: "effectQueued",
|
|
8039
|
-
at: now,
|
|
8040
|
-
effectKey: key,
|
|
8041
|
-
effect: effect.name,
|
|
8042
|
-
origin: origin
|
|
8043
8268
|
};
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8269
|
+
}
|
|
8270
|
+
|
|
8271
|
+
async function instanceGuardReason({instance: instance, actor: actor, guards: guards}) {
|
|
8272
|
+
if (guards === void 0 || guards.length === 0) return;
|
|
8273
|
+
const denied = await instanceWriteDenials({
|
|
8274
|
+
instance: instance,
|
|
8275
|
+
guards: guards,
|
|
8276
|
+
identity: actor.id
|
|
8277
|
+
});
|
|
8278
|
+
if (denied.length !== 0) return {
|
|
8279
|
+
kind: "mutation-guard-denied",
|
|
8280
|
+
denied: deniedGuardRefs(denied)
|
|
8047
8281
|
};
|
|
8048
8282
|
}
|
|
8049
8283
|
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8284
|
+
function lifecycleReason({instance: instance, status: status, stageHasExits: stageHasExits}) {
|
|
8285
|
+
const terminalReason = instanceTerminalReason(instance);
|
|
8286
|
+
if (terminalReason !== void 0) return terminalReason;
|
|
8287
|
+
if (!stageHasExits) return {
|
|
8288
|
+
kind: "stage-terminal",
|
|
8289
|
+
stage: instance.currentStage
|
|
8290
|
+
};
|
|
8291
|
+
if (invariants.isTerminalActivityStatus(status)) return {
|
|
8292
|
+
kind: "activity-not-active",
|
|
8293
|
+
status: status
|
|
8294
|
+
};
|
|
8295
|
+
}
|
|
8296
|
+
|
|
8297
|
+
function disabled(args) {
|
|
8298
|
+
return {
|
|
8299
|
+
...actionEvaluationIdentity(args.action),
|
|
8300
|
+
allowed: !1,
|
|
8301
|
+
disabledReason: args.reason,
|
|
8302
|
+
...args.insight !== void 0 ? {
|
|
8303
|
+
insight: args.insight
|
|
8061
8304
|
} : {},
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
}
|
|
8065
|
-
}
|
|
8066
|
-
for (const effect of effects) {
|
|
8067
|
-
const resolved = await resolveBindings({
|
|
8068
|
-
bindings: effect.bindings,
|
|
8069
|
-
staticInput: effect.input,
|
|
8070
|
-
snapshot: ctx.snapshot,
|
|
8071
|
-
params: params
|
|
8072
|
-
}), {pending: pending, history: history} = buildQueuedEffect({
|
|
8073
|
-
effect: effect,
|
|
8074
|
-
origin: origin,
|
|
8075
|
-
params: resolved,
|
|
8076
|
-
actor: actor,
|
|
8077
|
-
now: now,
|
|
8078
|
-
stageEntryKey: stageEntryKey
|
|
8079
|
-
});
|
|
8080
|
-
mutation.pendingEffects.push(pending), mutation.history.push(history);
|
|
8081
|
-
}
|
|
8305
|
+
...args.whenInsight !== void 0 ? {
|
|
8306
|
+
whenInsight: args.whenInsight
|
|
8307
|
+
} : {}
|
|
8308
|
+
};
|
|
8082
8309
|
}
|
|
8083
8310
|
|
|
8084
8311
|
function inFlightFilter() {
|
|
@@ -8106,25 +8333,81 @@ function idsArm(filter, params) {
|
|
|
8106
8333
|
}
|
|
8107
8334
|
}
|
|
8108
8335
|
|
|
8109
|
-
function instancesQuery(args) {
|
|
8110
|
-
const {tag: tag, filter: filter = {}} = args;
|
|
8111
|
-
if (invariants.validateTag(tag), filter.limit !== void 0 && (!Number.isInteger(filter.limit) || filter.limit <= 0)) throw new invariants.ContractViolationError(`instancesQuery: limit must be a positive integer; got ${JSON.stringify(filter.limit)}`);
|
|
8112
|
-
const conditions = [ `_type == "${invariants.WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ], params = {
|
|
8113
|
-
tag: tag
|
|
8114
|
-
};
|
|
8115
|
-
filter.includeCompleted !== !0 && conditions.push(inFlightFilter()), filter.definition !== void 0 && (conditions.push("definition == $definition"),
|
|
8116
|
-
params.definition = filter.definition), filter.stage !== void 0 && (conditions.push("currentStage == $stage"),
|
|
8117
|
-
params.stage = filter.stage);
|
|
8118
|
-
const arms = [ documentArm(filter, params), idsArm(filter, params) ].filter(arm => arm !== void 0);
|
|
8119
|
-
arms.length > 0 && conditions.push(`(${arms.join(" || ")})`);
|
|
8120
|
-
const body = `*[${conditions.join(" && ")}]`;
|
|
8121
|
-
return filter.limit !== void 0 ? {
|
|
8122
|
-
query: `${body} | order(startedAt desc) [0...${filter.limit}]`,
|
|
8123
|
-
params: params
|
|
8124
|
-
} : {
|
|
8125
|
-
query: `${body} | order(startedAt asc)`,
|
|
8126
|
-
params: params
|
|
8127
|
-
};
|
|
8336
|
+
function instancesQuery(args) {
|
|
8337
|
+
const {tag: tag, filter: filter = {}} = args;
|
|
8338
|
+
if (invariants.validateTag(tag), filter.limit !== void 0 && (!Number.isInteger(filter.limit) || filter.limit <= 0)) throw new invariants.ContractViolationError(`instancesQuery: limit must be a positive integer; got ${JSON.stringify(filter.limit)}`);
|
|
8339
|
+
const conditions = [ `_type == "${invariants.WORKFLOW_INSTANCE_TYPE}"`, invariants.tagScopeFilter() ], params = {
|
|
8340
|
+
tag: tag
|
|
8341
|
+
};
|
|
8342
|
+
filter.includeCompleted !== !0 && conditions.push(inFlightFilter()), filter.definition !== void 0 && (conditions.push("definition == $definition"),
|
|
8343
|
+
params.definition = filter.definition), filter.stage !== void 0 && (conditions.push("currentStage == $stage"),
|
|
8344
|
+
params.stage = filter.stage);
|
|
8345
|
+
const arms = [ documentArm(filter, params), idsArm(filter, params) ].filter(arm => arm !== void 0);
|
|
8346
|
+
arms.length > 0 && conditions.push(`(${arms.join(" || ")})`);
|
|
8347
|
+
const body = `*[${conditions.join(" && ")}]`;
|
|
8348
|
+
return filter.limit !== void 0 ? {
|
|
8349
|
+
query: `${body} | order(startedAt desc) [0...${filter.limit}]`,
|
|
8350
|
+
params: params
|
|
8351
|
+
} : {
|
|
8352
|
+
query: `${body} | order(startedAt asc)`,
|
|
8353
|
+
params: params
|
|
8354
|
+
};
|
|
8355
|
+
}
|
|
8356
|
+
|
|
8357
|
+
const DEFAULT_EFFECT_LEASE_MS = 300 * 1e3;
|
|
8358
|
+
|
|
8359
|
+
function claimReleasedEntry(args) {
|
|
8360
|
+
return {
|
|
8361
|
+
_key: randomKey(),
|
|
8362
|
+
_type: "effectClaimReleased",
|
|
8363
|
+
at: args.at,
|
|
8364
|
+
effectKey: args.pending._key,
|
|
8365
|
+
effect: args.pending.name,
|
|
8366
|
+
claim: args.claim,
|
|
8367
|
+
via: args.via,
|
|
8368
|
+
actor: args.actor
|
|
8369
|
+
};
|
|
8370
|
+
}
|
|
8371
|
+
|
|
8372
|
+
const SWEEP_MAX_ATTEMPTS = 5;
|
|
8373
|
+
|
|
8374
|
+
async function sweepStaleClaims(args) {
|
|
8375
|
+
const {tag: tag, instanceId: instanceId} = args, client = pinApiVersion(args.client);
|
|
8376
|
+
invariants.validateTag(tag);
|
|
8377
|
+
const clock = args.clock ?? wallClock, {actor: actor} = await resolveAccess(client), stamp = resolveExecutionContext(args.executionContext);
|
|
8378
|
+
for (let attempt = 1; attempt <= SWEEP_MAX_ATTEMPTS; attempt++) {
|
|
8379
|
+
const now = clock(), instance = await reload({
|
|
8380
|
+
client: client,
|
|
8381
|
+
instanceId: instanceId,
|
|
8382
|
+
tag: tag
|
|
8383
|
+
}), expired = instance.pendingEffects.filter(e => e.claim !== void 0 && isClaimExpired(e.claim, now));
|
|
8384
|
+
if (expired.length === 0) return {
|
|
8385
|
+
released: []
|
|
8386
|
+
};
|
|
8387
|
+
const expiredKeys = new Set(expired.map(e => e._key)), releasedQueue = instance.pendingEffects.map(e => expiredKeys.has(e._key) ? stripClaim(e) : e), auditRows = stampHistoryEntries(expired.map(pending => claimReleasedEntry({
|
|
8388
|
+
pending: pending,
|
|
8389
|
+
claim: pending.claim,
|
|
8390
|
+
at: now,
|
|
8391
|
+
via: "sweep",
|
|
8392
|
+
actor: actor
|
|
8393
|
+
})), stamp);
|
|
8394
|
+
try {
|
|
8395
|
+
return await client.patch(instance._id).ifRevisionId(instance._rev).set({
|
|
8396
|
+
pendingEffects: releasedQueue,
|
|
8397
|
+
history: [ ...instance.history, ...auditRows ]
|
|
8398
|
+
}).commit(SYNC_COMMIT), {
|
|
8399
|
+
released: expired
|
|
8400
|
+
};
|
|
8401
|
+
} catch (error) {
|
|
8402
|
+
if (!isRevisionConflict(error)) throw error;
|
|
8403
|
+
}
|
|
8404
|
+
}
|
|
8405
|
+
throw new Error(`sweepStaleClaims lost the optimistic-locking race ${SWEEP_MAX_ATTEMPTS} attempts running on ${instanceId} — a concurrent writer kept committing first. Retry later, or investigate a write storm on this instance.`);
|
|
8406
|
+
}
|
|
8407
|
+
|
|
8408
|
+
function stripClaim(entry) {
|
|
8409
|
+
const {claim: _claim, ...rest} = entry;
|
|
8410
|
+
return rest;
|
|
8128
8411
|
}
|
|
8129
8412
|
|
|
8130
8413
|
async function sortByDependencies({client: client, definitions: definitions, tag: tag}) {
|
|
@@ -9418,6 +9701,66 @@ const workflow = {
|
|
|
9418
9701
|
}
|
|
9419
9702
|
});
|
|
9420
9703
|
},
|
|
9704
|
+
commitEffectOps: async rawArgs => {
|
|
9705
|
+
const args = taggedScope(rawArgs, REQUEST_TAG.commitEffectOps), {client: client, tag: tag, instanceId: instanceId, effectKey: effectKey, claimToken: claimToken, ops: ops, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, record = requestRecordFor({
|
|
9706
|
+
idempotencyKey: args.idempotencyKey,
|
|
9707
|
+
op: "commitEffectOps",
|
|
9708
|
+
idempotencyTtlMs: args.idempotencyTtlMs
|
|
9709
|
+
});
|
|
9710
|
+
if (record === void 0) throw new invariants.ContractViolationError("commitEffectOps: idempotencyKey is required — the engine cannot assume a supplied field op is idempotent, so every mid-dispatch report must be retry-safe");
|
|
9711
|
+
return runDeduped({
|
|
9712
|
+
client: client,
|
|
9713
|
+
tag: tag,
|
|
9714
|
+
instanceId: instanceId,
|
|
9715
|
+
record: record,
|
|
9716
|
+
now: clock(),
|
|
9717
|
+
actor: actor,
|
|
9718
|
+
clientForGdr: clientForGdr,
|
|
9719
|
+
refSurface: refSurface,
|
|
9720
|
+
clock: clock,
|
|
9721
|
+
executionContext: executionContext,
|
|
9722
|
+
telemetry: args.telemetry,
|
|
9723
|
+
run: async () => {
|
|
9724
|
+
const report = await commitEffectOps({
|
|
9725
|
+
client: client,
|
|
9726
|
+
instanceId: instanceId,
|
|
9727
|
+
effectKey: effectKey,
|
|
9728
|
+
claimToken: claimToken,
|
|
9729
|
+
ops: ops,
|
|
9730
|
+
requestRecord: record,
|
|
9731
|
+
leaseMs: args.leaseMs ?? DEFAULT_EFFECT_LEASE_MS,
|
|
9732
|
+
options: engineOptionsForActor({
|
|
9733
|
+
actor: actor,
|
|
9734
|
+
clock: clock,
|
|
9735
|
+
clientForGdr: clientForGdr,
|
|
9736
|
+
refSurface: refSurface,
|
|
9737
|
+
executionContext: executionContext,
|
|
9738
|
+
telemetry: args.telemetry
|
|
9739
|
+
})
|
|
9740
|
+
}), {cascaded: cascaded, instance: instance} = await cascadeAndReload({
|
|
9741
|
+
client: client,
|
|
9742
|
+
tag: tag,
|
|
9743
|
+
instanceId: instanceId,
|
|
9744
|
+
actor: actor,
|
|
9745
|
+
clientForGdr: clientForGdr,
|
|
9746
|
+
refSurface: refSurface,
|
|
9747
|
+
clock: clock,
|
|
9748
|
+
executionContext: executionContext,
|
|
9749
|
+
telemetry: args.telemetry
|
|
9750
|
+
});
|
|
9751
|
+
return resolveTelemetry(args.telemetry).log(WorkflowEffectStateReported, {
|
|
9752
|
+
...definitionHashFragment(instance.pinnedContentHash),
|
|
9753
|
+
instanceId: instanceId,
|
|
9754
|
+
effect: report.effect,
|
|
9755
|
+
cascaded: cascaded
|
|
9756
|
+
}), {
|
|
9757
|
+
instance: instance,
|
|
9758
|
+
cascaded: cascaded,
|
|
9759
|
+
changed: !0
|
|
9760
|
+
};
|
|
9761
|
+
}
|
|
9762
|
+
});
|
|
9763
|
+
},
|
|
9421
9764
|
tick: async rawArgs => {
|
|
9422
9765
|
const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, current = await reload({
|
|
9423
9766
|
client: client,
|
|
@@ -10019,64 +10362,100 @@ async function resolveActor(directory, actor) {
|
|
|
10019
10362
|
};
|
|
10020
10363
|
}
|
|
10021
10364
|
|
|
10022
|
-
const
|
|
10365
|
+
const EFFECT_COMMIT_QUEUE_DEPTH = 32, EFFECT_COMMIT_DISPATCH_CAP = 200;
|
|
10023
10366
|
|
|
10024
|
-
|
|
10025
|
-
|
|
10367
|
+
class EffectCommitQueueOverflowError extends invariants.WorkflowError {
|
|
10368
|
+
effectKey;
|
|
10369
|
+
bound;
|
|
10370
|
+
limit;
|
|
10371
|
+
constructor(args) {
|
|
10372
|
+
super("effect-commit-queue-overflow", args.bound === "queue-depth" ? `Effect dispatch "${args.effectKey}" has ${args.limit} mid-dispatch commits queued — await your ctx.commitOps/ctx.setProgress calls (or report less often); the queue serializes real engine commits and cannot grow without bound` : `Effect dispatch "${args.effectKey}" already made ${args.limit} mid-dispatch commits — the per-dispatch cap bounds instance history growth; report more coarsely`),
|
|
10373
|
+
this.name = "EffectCommitQueueOverflowError", this.effectKey = args.effectKey, this.bound = args.bound,
|
|
10374
|
+
this.limit = args.limit;
|
|
10375
|
+
}
|
|
10026
10376
|
}
|
|
10027
10377
|
|
|
10028
|
-
function
|
|
10029
|
-
return
|
|
10030
|
-
_key: randomKey(),
|
|
10031
|
-
_type: "effectClaimReleased",
|
|
10032
|
-
at: args.at,
|
|
10033
|
-
effectKey: args.pending._key,
|
|
10034
|
-
effect: args.pending.name,
|
|
10035
|
-
claim: args.claim,
|
|
10036
|
-
via: args.via,
|
|
10037
|
-
actor: args.actor
|
|
10038
|
-
};
|
|
10378
|
+
function isClaimLoss(err) {
|
|
10379
|
+
return err instanceof StaleEffectClaimError || err instanceof invariants.EffectNotFoundError;
|
|
10039
10380
|
}
|
|
10040
10381
|
|
|
10041
|
-
|
|
10382
|
+
function pendingEntry(args) {
|
|
10383
|
+
let resolve, reject;
|
|
10384
|
+
const promise = new Promise((res, rej) => {
|
|
10385
|
+
resolve = res, reject = rej;
|
|
10386
|
+
});
|
|
10387
|
+
return promise.catch(() => {}), {
|
|
10388
|
+
...args,
|
|
10389
|
+
resolve: resolve,
|
|
10390
|
+
reject: reject,
|
|
10391
|
+
promise: promise
|
|
10392
|
+
};
|
|
10393
|
+
}
|
|
10042
10394
|
|
|
10043
|
-
|
|
10044
|
-
const {
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
};
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10395
|
+
function createEffectCommitQueue(args) {
|
|
10396
|
+
const {effectKey: effectKey, claimToken: claimToken, commit: commit} = args, pending = [];
|
|
10397
|
+
let admitted = 0, dead, closed = !1, tail = Promise.resolve();
|
|
10398
|
+
function assertOpen() {
|
|
10399
|
+
if (dead !== void 0) throw dead;
|
|
10400
|
+
if (closed) throw new Error(`Effect dispatch "${effectKey}" already settled — a mid-dispatch report after the handler returned cannot commit; await your reports inside the handler`);
|
|
10401
|
+
}
|
|
10402
|
+
function admit(entry) {
|
|
10403
|
+
if (assertOpen(), pending.length >= EFFECT_COMMIT_QUEUE_DEPTH) throw new EffectCommitQueueOverflowError({
|
|
10404
|
+
effectKey: effectKey,
|
|
10405
|
+
bound: "queue-depth",
|
|
10406
|
+
limit: EFFECT_COMMIT_QUEUE_DEPTH
|
|
10407
|
+
});
|
|
10408
|
+
if (admitted >= EFFECT_COMMIT_DISPATCH_CAP) throw new EffectCommitQueueOverflowError({
|
|
10409
|
+
effectKey: effectKey,
|
|
10410
|
+
bound: "dispatch-cap",
|
|
10411
|
+
limit: EFFECT_COMMIT_DISPATCH_CAP
|
|
10412
|
+
});
|
|
10413
|
+
return admitted += 1, pending.push(entry), tail = tail.then(runNext), entry.promise;
|
|
10414
|
+
}
|
|
10415
|
+
function die(err) {
|
|
10416
|
+
dead = err;
|
|
10417
|
+
for (const entry of pending.splice(0)) entry.reject(err);
|
|
10418
|
+
}
|
|
10419
|
+
async function runNext() {
|
|
10420
|
+
const entry = pending.shift();
|
|
10421
|
+
if (entry !== void 0) try {
|
|
10422
|
+
await commit({
|
|
10423
|
+
ops: entry.buildOps(),
|
|
10424
|
+
idempotencyKey: entry.idempotencyKey
|
|
10425
|
+
}), entry.resolve();
|
|
10426
|
+
} catch (err) {
|
|
10427
|
+
entry.reject(err), die(err);
|
|
10072
10428
|
}
|
|
10073
10429
|
}
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10430
|
+
return {
|
|
10431
|
+
commitOps: req => admit(pendingEntry({
|
|
10432
|
+
buildOps: () => req.ops,
|
|
10433
|
+
idempotencyKey: req.idempotencyKey
|
|
10434
|
+
})),
|
|
10435
|
+
setProgress: (target, value) => {
|
|
10436
|
+
assertOpen();
|
|
10437
|
+
const ref = typeof target == "string" ? {
|
|
10438
|
+
scope: "workflow",
|
|
10439
|
+
field: target
|
|
10440
|
+
} : target, coalesceKey = `${ref.scope}:${ref.field}`, queued = pending.find(entry2 => entry2.coalesceKey === coalesceKey);
|
|
10441
|
+
if (queued !== void 0) return queued.latestValue = value, queued.promise;
|
|
10442
|
+
const entry = pendingEntry({
|
|
10443
|
+
buildOps: () => [ {
|
|
10444
|
+
type: "field.set",
|
|
10445
|
+
target: ref,
|
|
10446
|
+
value: {
|
|
10447
|
+
type: "literal",
|
|
10448
|
+
value: entry.latestValue
|
|
10449
|
+
}
|
|
10450
|
+
} ],
|
|
10451
|
+
idempotencyKey: `effect:${effectKey}:${claimToken}:progress:${coalesceKey}:${admitted}`,
|
|
10452
|
+
coalesceKey: coalesceKey,
|
|
10453
|
+
latestValue: value
|
|
10454
|
+
});
|
|
10455
|
+
return admit(entry);
|
|
10456
|
+
},
|
|
10457
|
+
settle: async () => (closed = !0, await tail, dead !== void 0 && !isClaimLoss(dead) ? dead : void 0)
|
|
10458
|
+
};
|
|
10080
10459
|
}
|
|
10081
10460
|
|
|
10082
10461
|
class MissingHandlerError extends invariants.WorkflowError {
|
|
@@ -10172,74 +10551,126 @@ async function drainEffectsInternal(args) {
|
|
|
10172
10551
|
failed: [],
|
|
10173
10552
|
skipped: [],
|
|
10174
10553
|
lost: []
|
|
10175
|
-
},
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
client: client,
|
|
10201
|
-
instance: before,
|
|
10202
|
-
candidate: candidate,
|
|
10203
|
-
drainerActor: drainerActor,
|
|
10204
|
-
now: now,
|
|
10205
|
-
leaseMs: leaseMs,
|
|
10206
|
-
...executionContext !== void 0 ? {
|
|
10207
|
-
executionContext: executionContext
|
|
10208
|
-
} : {}
|
|
10209
|
-
})) continue;
|
|
10210
|
-
const outcome = await dispatchAndReport({
|
|
10211
|
-
handler: handler,
|
|
10212
|
-
candidate: candidate,
|
|
10213
|
-
client: client,
|
|
10214
|
-
handlerClient: handlerClient,
|
|
10215
|
-
tag: tag,
|
|
10216
|
-
workflowResource: workflowResource,
|
|
10217
|
-
...resourceClients !== void 0 ? {
|
|
10218
|
-
resourceClients: resourceClients
|
|
10219
|
-
} : {},
|
|
10220
|
-
instanceId: instanceId,
|
|
10221
|
-
clientFor: clientFor,
|
|
10222
|
-
logger: logger,
|
|
10223
|
-
log: log,
|
|
10224
|
-
...executionContext !== void 0 ? {
|
|
10225
|
-
executionContext: executionContext
|
|
10226
|
-
} : {},
|
|
10227
|
-
telemetry: cascadeTelemetry,
|
|
10228
|
-
clock: clock
|
|
10229
|
-
});
|
|
10230
|
-
buckets[outcome].push(candidate);
|
|
10231
|
-
}
|
|
10554
|
+
}, pass = {
|
|
10555
|
+
client: client,
|
|
10556
|
+
handlerClient: handlerClient,
|
|
10557
|
+
tag: tag,
|
|
10558
|
+
workflowResource: workflowResource,
|
|
10559
|
+
...resourceClients !== void 0 ? {
|
|
10560
|
+
resourceClients: resourceClients
|
|
10561
|
+
} : {},
|
|
10562
|
+
instanceId: instanceId,
|
|
10563
|
+
effectHandlers: effectHandlers,
|
|
10564
|
+
missingHandler: missingHandler,
|
|
10565
|
+
logger: logger,
|
|
10566
|
+
log: log,
|
|
10567
|
+
leaseMs: leaseMs,
|
|
10568
|
+
clock: clock,
|
|
10569
|
+
...executionContext !== void 0 ? {
|
|
10570
|
+
executionContext: executionContext
|
|
10571
|
+
} : {},
|
|
10572
|
+
telemetry: cascadeTelemetry,
|
|
10573
|
+
drainerActor: drainerActor,
|
|
10574
|
+
clientFor: clientFor,
|
|
10575
|
+
buckets: buckets,
|
|
10576
|
+
skippedKeys: /* @__PURE__ */ new Set
|
|
10577
|
+
};
|
|
10578
|
+
for (;await drainOneCandidate(pass); ) ;
|
|
10232
10579
|
return buckets;
|
|
10233
10580
|
}
|
|
10234
10581
|
|
|
10582
|
+
async function drainOneCandidate(pass) {
|
|
10583
|
+
const {client: client, tag: tag, instanceId: instanceId, buckets: buckets, skippedKeys: skippedKeys} = pass, now = pass.clock(), before = await reload({
|
|
10584
|
+
client: client,
|
|
10585
|
+
instanceId: instanceId,
|
|
10586
|
+
tag: tag
|
|
10587
|
+
});
|
|
10588
|
+
noteDrainedInstanceHash(buckets, before);
|
|
10589
|
+
const candidate = findClaimableCandidate({
|
|
10590
|
+
instance: before,
|
|
10591
|
+
now: now,
|
|
10592
|
+
skippedKeys: skippedKeys
|
|
10593
|
+
});
|
|
10594
|
+
if (candidate === void 0) return !1;
|
|
10595
|
+
const handler = pass.effectHandlers[candidate.name];
|
|
10596
|
+
if (handler === void 0) return await assertSkippableOrThrow({
|
|
10597
|
+
missingHandler: pass.missingHandler,
|
|
10598
|
+
candidate: candidate,
|
|
10599
|
+
instanceId: instanceId,
|
|
10600
|
+
log: pass.log
|
|
10601
|
+
}), buckets.skipped.push(candidate), skippedKeys.add(candidate._key), !0;
|
|
10602
|
+
const claimed = await claimPendingEffect({
|
|
10603
|
+
client: client,
|
|
10604
|
+
instance: before,
|
|
10605
|
+
candidate: candidate,
|
|
10606
|
+
drainerActor: pass.drainerActor,
|
|
10607
|
+
now: now,
|
|
10608
|
+
leaseMs: pass.leaseMs,
|
|
10609
|
+
...pass.executionContext !== void 0 ? {
|
|
10610
|
+
executionContext: pass.executionContext
|
|
10611
|
+
} : {}
|
|
10612
|
+
});
|
|
10613
|
+
if (claimed === void 0) return !0;
|
|
10614
|
+
const outcome = await dispatchAndReport({
|
|
10615
|
+
handler: handler,
|
|
10616
|
+
candidate: candidate,
|
|
10617
|
+
claimToken: claimed.claimToken,
|
|
10618
|
+
leaseMs: pass.leaseMs,
|
|
10619
|
+
client: client,
|
|
10620
|
+
handlerClient: pass.handlerClient,
|
|
10621
|
+
tag: tag,
|
|
10622
|
+
workflowResource: pass.workflowResource,
|
|
10623
|
+
...pass.resourceClients !== void 0 ? {
|
|
10624
|
+
resourceClients: pass.resourceClients
|
|
10625
|
+
} : {},
|
|
10626
|
+
instanceId: instanceId,
|
|
10627
|
+
clientFor: pass.clientFor,
|
|
10628
|
+
logger: pass.logger,
|
|
10629
|
+
log: pass.log,
|
|
10630
|
+
...pass.executionContext !== void 0 ? {
|
|
10631
|
+
executionContext: pass.executionContext
|
|
10632
|
+
} : {},
|
|
10633
|
+
telemetry: pass.telemetry,
|
|
10634
|
+
clock: pass.clock
|
|
10635
|
+
});
|
|
10636
|
+
return buckets[outcome].push(candidate), !0;
|
|
10637
|
+
}
|
|
10638
|
+
|
|
10235
10639
|
function findClaimableCandidate({instance: instance, now: now, skippedKeys: skippedKeys}) {
|
|
10236
10640
|
return instance.pendingEffects.find(e => (e.claim === void 0 || isClaimExpired(e.claim, now)) && !skippedKeys.has(e._key));
|
|
10237
10641
|
}
|
|
10238
10642
|
|
|
10239
10643
|
async function dispatchAndReport(args) {
|
|
10240
|
-
const {handler: handler, candidate: candidate, client: client, handlerClient: handlerClient, tag: tag, workflowResource: workflowResource, resourceClients: resourceClients, instanceId: instanceId, clientFor: clientFor, logger: logger, log: log, executionContext: executionContext, telemetry: telemetry, clock: clock} = args,
|
|
10644
|
+
const {handler: handler, candidate: candidate, claimToken: claimToken, leaseMs: leaseMs, client: client, handlerClient: handlerClient, tag: tag, workflowResource: workflowResource, resourceClients: resourceClients, instanceId: instanceId, clientFor: clientFor, logger: logger, log: log, executionContext: executionContext, telemetry: telemetry, clock: clock} = args, commitQueue = createEffectCommitQueue({
|
|
10645
|
+
effectKey: candidate._key,
|
|
10646
|
+
claimToken: claimToken,
|
|
10647
|
+
commit: async req => {
|
|
10648
|
+
await workflow.commitEffectOps({
|
|
10649
|
+
client: client,
|
|
10650
|
+
tag: tag,
|
|
10651
|
+
workflowResource: workflowResource,
|
|
10652
|
+
...resourceClients !== void 0 ? {
|
|
10653
|
+
resourceClients: resourceClients
|
|
10654
|
+
} : {},
|
|
10655
|
+
...executionContext !== void 0 ? {
|
|
10656
|
+
executionContext: executionContext
|
|
10657
|
+
} : {},
|
|
10658
|
+
...telemetry !== void 0 ? {
|
|
10659
|
+
telemetry: telemetry
|
|
10660
|
+
} : {},
|
|
10661
|
+
instanceId: instanceId,
|
|
10662
|
+
effectKey: candidate._key,
|
|
10663
|
+
claimToken: claimToken,
|
|
10664
|
+
ops: req.ops,
|
|
10665
|
+
idempotencyKey: req.idempotencyKey,
|
|
10666
|
+
leaseMs: leaseMs,
|
|
10667
|
+
clock: clock
|
|
10668
|
+
});
|
|
10669
|
+
}
|
|
10670
|
+
}), {outputs: outputs, ops: ops, dispatchError: dispatchError} = await dispatchEffect({
|
|
10241
10671
|
handler: handler,
|
|
10242
10672
|
candidate: candidate,
|
|
10673
|
+
queue: commitQueue,
|
|
10243
10674
|
ctx: {
|
|
10244
10675
|
client: handlerClient,
|
|
10245
10676
|
clientFor: clientFor,
|
|
@@ -10319,11 +10750,12 @@ async function assertSkippableOrThrow({missingHandler: missingHandler, candidate
|
|
|
10319
10750
|
}
|
|
10320
10751
|
|
|
10321
10752
|
async function claimPendingEffect({client: client, instance: instance, candidate: candidate, drainerActor: drainerActor, now: now, leaseMs: leaseMs, executionContext: executionContext}) {
|
|
10322
|
-
const priorClaim = candidate.claim, claim = {
|
|
10753
|
+
const priorClaim = candidate.claim, claimToken = randomKey(), claim = {
|
|
10323
10754
|
_type: "pendingEffect.claim",
|
|
10324
10755
|
claimedAt: now,
|
|
10325
10756
|
claimedBy: drainerActor,
|
|
10326
|
-
leaseExpiresAt: addMs(now, leaseMs)
|
|
10757
|
+
leaseExpiresAt: addMs(now, leaseMs),
|
|
10758
|
+
claimToken: claimToken
|
|
10327
10759
|
}, takeoverAudit = priorClaim !== void 0 ? stampHistoryEntries([ claimReleasedEntry({
|
|
10328
10760
|
pending: candidate,
|
|
10329
10761
|
claim: priorClaim,
|
|
@@ -10337,43 +10769,64 @@ async function claimPendingEffect({client: client, instance: instance, candidate
|
|
|
10337
10769
|
...takeoverAudit !== void 0 ? {
|
|
10338
10770
|
history: [ ...instance.history, takeoverAudit ]
|
|
10339
10771
|
} : {}
|
|
10340
|
-
}).commit(SYNC_COMMIT),
|
|
10772
|
+
}).commit(SYNC_COMMIT), {
|
|
10773
|
+
claimToken: claimToken
|
|
10774
|
+
};
|
|
10341
10775
|
} catch (error) {
|
|
10342
10776
|
if (!isRevisionConflict(error)) throw error;
|
|
10343
|
-
return
|
|
10777
|
+
return;
|
|
10344
10778
|
}
|
|
10345
10779
|
}
|
|
10346
10780
|
|
|
10347
|
-
async function
|
|
10781
|
+
async function invokeHandler({handler: handler, candidate: candidate, queue: queue, ctx: ctx}) {
|
|
10348
10782
|
try {
|
|
10349
10783
|
const result = await handler(candidate.params, {
|
|
10350
10784
|
client: ctx.client,
|
|
10351
10785
|
clientFor: ctx.clientFor,
|
|
10352
10786
|
instanceId: ctx.instanceId,
|
|
10353
10787
|
effectKey: candidate._key,
|
|
10354
|
-
log: (message, extra) => ctx.logger(`effect.${candidate.name}`).info(message, extra)
|
|
10788
|
+
log: (message, extra) => ctx.logger(`effect.${candidate.name}`).info(message, extra),
|
|
10789
|
+
commitOps: queue.commitOps,
|
|
10790
|
+
setProgress: queue.setProgress
|
|
10355
10791
|
});
|
|
10356
|
-
return {
|
|
10357
|
-
|
|
10358
|
-
outputs: result.outputs
|
|
10359
|
-
} : {},
|
|
10360
|
-
...result?.ops !== void 0 ? {
|
|
10361
|
-
ops: result.ops
|
|
10362
|
-
} : {}
|
|
10792
|
+
return result === void 0 ? {} : {
|
|
10793
|
+
result: result
|
|
10363
10794
|
};
|
|
10364
10795
|
} catch (err) {
|
|
10365
|
-
const message = invariants.errorMessage(err), stack = err instanceof Error && err.stack !== void 0 ? err.stack : void 0;
|
|
10366
10796
|
return {
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
stack: stack
|
|
10370
|
-
} : {
|
|
10371
|
-
message: message
|
|
10797
|
+
thrown: {
|
|
10798
|
+
err: err
|
|
10372
10799
|
}
|
|
10373
10800
|
};
|
|
10374
10801
|
}
|
|
10375
10802
|
}
|
|
10376
10803
|
|
|
10804
|
+
function shapeDispatchError(err) {
|
|
10805
|
+
const message = invariants.errorMessage(err), stack = err instanceof Error && err.stack !== void 0 ? err.stack : void 0;
|
|
10806
|
+
return stack !== void 0 ? {
|
|
10807
|
+
message: message,
|
|
10808
|
+
stack: stack
|
|
10809
|
+
} : {
|
|
10810
|
+
message: message
|
|
10811
|
+
};
|
|
10812
|
+
}
|
|
10813
|
+
|
|
10814
|
+
async function dispatchEffect(args) {
|
|
10815
|
+
const {result: result, thrown: thrown} = await invokeHandler(args), settleFailure = await args.queue.settle(), failed = thrown ?? (settleFailure !== void 0 ? {
|
|
10816
|
+
err: settleFailure
|
|
10817
|
+
} : void 0);
|
|
10818
|
+
return failed !== void 0 ? {
|
|
10819
|
+
dispatchError: shapeDispatchError(failed.err)
|
|
10820
|
+
} : {
|
|
10821
|
+
...result?.outputs !== void 0 ? {
|
|
10822
|
+
outputs: result.outputs
|
|
10823
|
+
} : {},
|
|
10824
|
+
...result?.ops !== void 0 ? {
|
|
10825
|
+
ops: result.ops
|
|
10826
|
+
} : {}
|
|
10827
|
+
};
|
|
10828
|
+
}
|
|
10829
|
+
|
|
10377
10830
|
async function applyMissingHandler({policy: policy, info: info, log: log}) {
|
|
10378
10831
|
if (policy === "fail") return "fail";
|
|
10379
10832
|
if (policy === "skip") return log.warn(`Missing effect handler "${info.name}" — skipping`, {
|
|
@@ -10850,6 +11303,7 @@ function createEngine(args) {
|
|
|
10850
11303
|
fireAction: rest => workflow.fireAction(withScope(rest)),
|
|
10851
11304
|
editField: rest => workflow.editField(withScope(rest)),
|
|
10852
11305
|
completeEffect: rest => workflow.completeEffect(withScope(rest)),
|
|
11306
|
+
commitEffectOps: rest => workflow.commitEffectOps(withScope(rest)),
|
|
10853
11307
|
tick: rest => workflow.tick(withScope(rest)),
|
|
10854
11308
|
evaluate: rest => workflow.evaluate(withScope(rest)),
|
|
10855
11309
|
diagnose: rest => workflow.diagnose(withScope(rest)),
|
|
@@ -11256,6 +11710,10 @@ const HISTORY_DISPLAY = {
|
|
|
11256
11710
|
title: "Number value",
|
|
11257
11711
|
description: "Numeric entry."
|
|
11258
11712
|
},
|
|
11713
|
+
progress: {
|
|
11714
|
+
title: "Progress",
|
|
11715
|
+
description: "Application-defined completion, 0–100 inclusive (fractions allowed)."
|
|
11716
|
+
},
|
|
11259
11717
|
boolean: {
|
|
11260
11718
|
title: "Boolean value",
|
|
11261
11719
|
description: "True/false entry."
|
|
@@ -11686,6 +12144,8 @@ exports.CONTEXT_ENTRY_DISPLAY = CONTEXT_ENTRY_DISPLAY;
|
|
|
11686
12144
|
|
|
11687
12145
|
exports.CascadeLimitError = CascadeLimitError;
|
|
11688
12146
|
|
|
12147
|
+
exports.ConcurrentCommitEffectOpsError = ConcurrentCommitEffectOpsError;
|
|
12148
|
+
|
|
11689
12149
|
exports.ConcurrentCompleteEffectError = ConcurrentCompleteEffectError;
|
|
11690
12150
|
|
|
11691
12151
|
exports.ConcurrentEditFieldError = ConcurrentEditFieldError;
|
|
@@ -11702,6 +12162,10 @@ exports.DISPLAY = DISPLAY;
|
|
|
11702
12162
|
|
|
11703
12163
|
exports.DRIVER_KIND_DISPLAY = DRIVER_KIND_DISPLAY;
|
|
11704
12164
|
|
|
12165
|
+
exports.EFFECT_COMMIT_DISPATCH_CAP = EFFECT_COMMIT_DISPATCH_CAP;
|
|
12166
|
+
|
|
12167
|
+
exports.EFFECT_COMMIT_QUEUE_DEPTH = EFFECT_COMMIT_QUEUE_DEPTH;
|
|
12168
|
+
|
|
11705
12169
|
exports.ENGINE_API_VERSION = ENGINE_API_VERSION;
|
|
11706
12170
|
|
|
11707
12171
|
exports.EXECUTION_KINDS = EXECUTION_KINDS;
|
|
@@ -11710,6 +12174,8 @@ exports.EXECUTOR_CLASSIFICATION_DISPLAY = EXECUTOR_CLASSIFICATION_DISPLAY;
|
|
|
11710
12174
|
|
|
11711
12175
|
exports.EditFieldDeniedError = EditFieldDeniedError;
|
|
11712
12176
|
|
|
12177
|
+
exports.EffectCommitQueueOverflowError = EffectCommitQueueOverflowError;
|
|
12178
|
+
|
|
11713
12179
|
exports.EffectOpsInvalidError = EffectOpsInvalidError;
|
|
11714
12180
|
|
|
11715
12181
|
exports.EffectOutputsInvalidError = EffectOutputsInvalidError;
|
|
@@ -11740,6 +12206,8 @@ exports.RefResourceUndeclaredError = RefResourceUndeclaredError;
|
|
|
11740
12206
|
|
|
11741
12207
|
exports.RequiredFieldNotProvidedError = RequiredFieldNotProvidedError;
|
|
11742
12208
|
|
|
12209
|
+
exports.StaleEffectClaimError = StaleEffectClaimError;
|
|
12210
|
+
|
|
11743
12211
|
exports.StartNotAllowedError = StartNotAllowedError;
|
|
11744
12212
|
|
|
11745
12213
|
exports.StartNotPrimedError = StartNotPrimedError;
|
|
@@ -11754,6 +12222,8 @@ exports.WorkflowDefinitionDeployed = WorkflowDefinitionDeployed;
|
|
|
11754
12222
|
|
|
11755
12223
|
exports.WorkflowEffectCompleted = WorkflowEffectCompleted;
|
|
11756
12224
|
|
|
12225
|
+
exports.WorkflowEffectStateReported = WorkflowEffectStateReported;
|
|
12226
|
+
|
|
11757
12227
|
exports.WorkflowEffectsDrained = WorkflowEffectsDrained;
|
|
11758
12228
|
|
|
11759
12229
|
exports.WorkflowFieldEdited = WorkflowFieldEdited;
|