@sanity/workflow-engine 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +196 -0
- package/DATAMODEL.md +168 -0
- package/dist/_chunks-cjs/invariants.cjs +275 -94
- package/dist/_chunks-es/invariants.js +264 -89
- package/dist/define.d.cts +58 -40
- package/dist/define.d.ts +58 -40
- package/dist/index.cjs +1940 -901
- package/dist/index.d.cts +524 -236
- package/dist/index.d.ts +524 -236
- package/dist/index.js +1928 -911
- package/package.json +3 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var v = require("valibot"), groqConditionDescribe = require("@sanity/groq-condition-describe"), groqJs = require("groq-js");
|
|
3
|
+
var v = require("valibot"), groqConditionDescribe = require("@sanity/groq-condition-describe"), groqJs = require("groq-js"), idUtils = require("@sanity/id-utils");
|
|
4
4
|
|
|
5
5
|
function _interopNamespaceCompat(e) {
|
|
6
6
|
if (e && typeof e == "object" && "default" in e) return e;
|
|
@@ -115,12 +115,33 @@ function isUnprimed(instance) {
|
|
|
115
115
|
|
|
116
116
|
function parseDefinitionSnapshotValue(instance) {
|
|
117
117
|
try {
|
|
118
|
-
return JSON.parse(instance.definitionSnapshot);
|
|
118
|
+
return normalizeLegacyActivityRequirements(JSON.parse(instance.definitionSnapshot));
|
|
119
119
|
} catch (err) {
|
|
120
120
|
rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
function normalizeLegacyActivityRequirements(value) {
|
|
125
|
+
for (const stage of arrayMember(value, "stages")) for (const activity of arrayMember(stage, "activities")) normalizeLegacyRequirementMap(activity);
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function arrayMember(value, key) {
|
|
130
|
+
if (typeof value != "object" || value === null) return [];
|
|
131
|
+
const member = value[key];
|
|
132
|
+
return Array.isArray(member) ? member : [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function normalizeLegacyRequirementMap(value) {
|
|
136
|
+
if (typeof value != "object" || value === null) return;
|
|
137
|
+
const activity = value, requirements = activity.requirements;
|
|
138
|
+
typeof requirements != "object" || requirements === null || Array.isArray(requirements) || (activity.requirements = Object.entries(requirements).map(([name, query]) => ({
|
|
139
|
+
type: "groq",
|
|
140
|
+
name: name,
|
|
141
|
+
query: query
|
|
142
|
+
})));
|
|
143
|
+
}
|
|
144
|
+
|
|
124
145
|
function parseDefinitionSnapshot(instance) {
|
|
125
146
|
return parseDefinitionSnapshotValue(instance);
|
|
126
147
|
}
|
|
@@ -129,7 +150,7 @@ function parentRef(instance) {
|
|
|
129
150
|
return instance.ancestors.at(-1);
|
|
130
151
|
}
|
|
131
152
|
|
|
132
|
-
const DATA_MODEL_VERSION =
|
|
153
|
+
const DATA_MODEL_VERSION = 4, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
|
|
133
154
|
|
|
134
155
|
class ReaderModelAcknowledgementError extends WorkflowError {
|
|
135
156
|
code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
|
|
@@ -139,7 +160,7 @@ class ReaderModelAcknowledgementError extends WorkflowError {
|
|
|
139
160
|
documentationUrl=READER_MODEL_ROLLOUT_URL;
|
|
140
161
|
constructor(expectedMinReaderModel, context = "Deployment") {
|
|
141
162
|
const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
|
|
142
|
-
super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}. Dependency upgrades can change writer compatibility. Upgrade all readers and Functions before accepting a higher floor; after verifying the rollout, change the literal in deployment configuration. ${READER_MODEL_ROLLOUT_URL}`),
|
|
163
|
+
super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}. Dependency upgrades can change writer compatibility. Upgrade all readers and Functions before accepting a higher floor; after verifying the rollout, change the literal in deployment configuration. Instances written before the new floor may stop matching user-identity queries, and older readers refuse documents this engine touches — a prerelease deployment with no data worth migrating can reset every engine-owned document with \`sanity-workflows nuke\` and start fresh. ${READER_MODEL_ROLLOUT_URL}`),
|
|
143
164
|
this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
|
|
144
165
|
}
|
|
145
166
|
}
|
|
@@ -204,6 +225,22 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
|
|
|
204
225
|
compatibility: "additive",
|
|
205
226
|
applicability: "detectable",
|
|
206
227
|
summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
|
|
228
|
+
}), Object.freeze({
|
|
229
|
+
id: "classified-principal-ids",
|
|
230
|
+
introducedInModel: 4,
|
|
231
|
+
minReaderModel: 4,
|
|
232
|
+
documentTypes: Object.freeze([ "instance" ]),
|
|
233
|
+
compatibility: "reader-floor",
|
|
234
|
+
applicability: "unconditional",
|
|
235
|
+
summary: "Principal ids are namespace-classified: actor and assignee writes carry the account-global user id only, and readers resolve legacy project-scoped ids through the prefix classifier at the instance read funnel."
|
|
236
|
+
}), Object.freeze({
|
|
237
|
+
id: "readiness-requirements",
|
|
238
|
+
introducedInModel: 4,
|
|
239
|
+
minReaderModel: 4,
|
|
240
|
+
documentTypes: Object.freeze([ "definition" ]),
|
|
241
|
+
compatibility: "reader-floor",
|
|
242
|
+
applicability: "detectable",
|
|
243
|
+
summary: "Start and activity readiness use named polymorphic requirement arrays."
|
|
207
244
|
}) ]);
|
|
208
245
|
|
|
209
246
|
function recordOf(value) {
|
|
@@ -264,6 +301,11 @@ function hasClaimTokens(document) {
|
|
|
264
301
|
});
|
|
265
302
|
}
|
|
266
303
|
|
|
304
|
+
function hasReadinessRequirements(document) {
|
|
305
|
+
const root = recordOf(document);
|
|
306
|
+
return root === void 0 ? !1 : Array.isArray(recordOf(root.start)?.requirements) ? !0 : recordsAt(root, "stages").some(stage => recordsAt(stage, "activities").some(activity => Array.isArray(activity.requirements)));
|
|
307
|
+
}
|
|
308
|
+
|
|
267
309
|
const featureDetectors = {
|
|
268
310
|
"governed-model-stamps": () => !0,
|
|
269
311
|
"subject-field-kind": document => hasFieldKind(document, "subject"),
|
|
@@ -271,7 +313,9 @@ const featureDetectors = {
|
|
|
271
313
|
"action-semantics": hasActionSemantics,
|
|
272
314
|
"inclusive-scalar-bounds": hasScalarValidation,
|
|
273
315
|
"progress-field-kind": document => hasFieldKind(document, "progress"),
|
|
274
|
-
"effect-claim-tokens": hasClaimTokens
|
|
316
|
+
"effect-claim-tokens": hasClaimTokens,
|
|
317
|
+
"classified-principal-ids": () => !0,
|
|
318
|
+
"readiness-requirements": hasReadinessRequirements
|
|
275
319
|
};
|
|
276
320
|
|
|
277
321
|
function requiredModelFeatures(documentType, document) {
|
|
@@ -285,7 +329,7 @@ function requiredReaderModel(documentType, document) {
|
|
|
285
329
|
function modelStampFor(args) {
|
|
286
330
|
return {
|
|
287
331
|
modelVersion: DATA_MODEL_VERSION,
|
|
288
|
-
minReaderModel: Math.max(args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
|
|
332
|
+
minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
|
|
289
333
|
};
|
|
290
334
|
}
|
|
291
335
|
|
|
@@ -358,6 +402,21 @@ function andConditions(parts) {
|
|
|
358
402
|
|
|
359
403
|
const KNOWN_SCHEMES = /* @__PURE__ */ new Set([ "dataset", "canvas", "media-library", "dashboard" ]), KNOWN_SCHEMES_TEXT = [ ...KNOWN_SCHEMES ].join(", ");
|
|
360
404
|
|
|
405
|
+
class VersionSpecificDatasetGdrError extends Error {
|
|
406
|
+
documentId;
|
|
407
|
+
stableDocumentId;
|
|
408
|
+
constructor(documentId, uri) {
|
|
409
|
+
const stableDocumentId = idUtils.getPublishedId(documentId);
|
|
410
|
+
super(`Invalid GDR "${uri}": dataset document ID "${documentId}" identifies a stored draft or release version. Use the stable document ID "${stableDocumentId}" and select drafts/releases through the workflow perspective.`),
|
|
411
|
+
this.name = "VersionSpecificDatasetGdrError", this.documentId = documentId, this.stableDocumentId = stableDocumentId;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function assertStableDatasetDocumentId(documentId, uri) {
|
|
416
|
+
const sanityId = documentId;
|
|
417
|
+
if (!(!idUtils.isDraftId(sanityId) && !idUtils.isVersionId(sanityId))) throw new VersionSpecificDatasetGdrError(documentId, uri);
|
|
418
|
+
}
|
|
419
|
+
|
|
361
420
|
function parseGdr(uri) {
|
|
362
421
|
const colon = uri.indexOf(":");
|
|
363
422
|
if (colon < 0) throw new Error(`Invalid GDR "${uri}": must be a URI of form "<scheme>:<...id-parts>". Known schemes: ${KNOWN_SCHEMES_TEXT}.`);
|
|
@@ -367,11 +426,12 @@ function parseGdr(uri) {
|
|
|
367
426
|
if (parts.some(part => part.length === 0)) throw new Error(`Invalid GDR "${uri}": id parts must be non-empty (no leading, trailing, or doubled ":").`);
|
|
368
427
|
if (scheme === "dataset") {
|
|
369
428
|
if (parts.length !== 3) throw new Error(`Invalid GDR "${uri}": dataset scheme requires <projectId>:<dataset>:<documentId> (3 parts after scheme); got ${parts.length}.`);
|
|
370
|
-
|
|
429
|
+
const documentId = parts[2];
|
|
430
|
+
return assertStableDatasetDocumentId(documentId, uri), {
|
|
371
431
|
scheme: "dataset",
|
|
372
432
|
projectId: parts[0],
|
|
373
433
|
dataset: parts[1],
|
|
374
|
-
documentId:
|
|
434
|
+
documentId: documentId
|
|
375
435
|
};
|
|
376
436
|
}
|
|
377
437
|
if (parts.length !== 2) throw new Error(`Invalid GDR "${uri}": ${scheme} scheme requires <resourceId>:<documentId> (2 parts after scheme); got ${parts.length}.`);
|
|
@@ -391,7 +451,11 @@ function tryParseGdr(uri) {
|
|
|
391
451
|
}
|
|
392
452
|
|
|
393
453
|
function gdrUri(parts) {
|
|
394
|
-
|
|
454
|
+
if (parts.scheme === "dataset") {
|
|
455
|
+
const uri = `dataset:${parts.projectId}:${parts.dataset}:${parts.documentId}`;
|
|
456
|
+
return assertStableDatasetDocumentId(parts.documentId, uri), uri;
|
|
457
|
+
}
|
|
458
|
+
return `${parts.scheme}:${parts.resourceId}:${parts.documentId}`;
|
|
395
459
|
}
|
|
396
460
|
|
|
397
461
|
function extractDocumentId(gdrUriString) {
|
|
@@ -794,8 +858,8 @@ function desugarStart(start) {
|
|
|
794
858
|
...start.filter !== void 0 ? {
|
|
795
859
|
filter: start.filter
|
|
796
860
|
} : {},
|
|
797
|
-
...start.
|
|
798
|
-
|
|
861
|
+
...start.requirements !== void 0 ? {
|
|
862
|
+
requirements: start.requirements
|
|
799
863
|
} : {}
|
|
800
864
|
};
|
|
801
865
|
}
|
|
@@ -1557,7 +1621,7 @@ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES
|
|
|
1557
1621
|
binding: "always",
|
|
1558
1622
|
label: "the spawned subworkflows",
|
|
1559
1623
|
description: "Every row of the instance's subworkflow registry, faceted by `activity`/`action`/`definition`/`rowKey`/`status` (`'active'|'done'|'aborted'`) with `current` marking the open stage entry's cohort and `stage` the child's current stage. Usable anywhere — transition `when`s, requirements, any stage's gates; the settled gate is `count($subworkflows[activity == <name> && current && status == 'active']) == 0`."
|
|
1560
|
-
} ],
|
|
1624
|
+
} ], RESERVED_CONDITION_VARS = CONDITION_VARS.map(v2 => v2.name), FILTER_SCOPE_VARS = CONDITION_VARS.filter(v2 => v2.binding === "always").map(v2 => v2.name), CALLER_BOUND_VARS = CONDITION_VARS.filter(v2 => v2.binding === "caller").map(v2 => v2.name), START_FILTER_VARS = [ {
|
|
1561
1625
|
name: "tag",
|
|
1562
1626
|
label: "this engine tag",
|
|
1563
1627
|
description: "The engine's tag partition — scope `*[...]` instance scans with `tag == $tag`."
|
|
@@ -1569,11 +1633,7 @@ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES
|
|
|
1569
1633
|
name: "now",
|
|
1570
1634
|
label: "the current time",
|
|
1571
1635
|
description: "The ISO clock reading of the evaluating engine."
|
|
1572
|
-
}, {
|
|
1573
|
-
name: SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR,
|
|
1574
|
-
label: "the subject already has an in-flight workflow",
|
|
1575
|
-
description: "Whether any instance in this engine tag, across all definitions, has the same resource-qualified subject and no `completedAt`. Advisory under concurrent starts."
|
|
1576
|
-
} ], START_ALLOWED_VARS = [ ...START_FILTER_VARS, {
|
|
1636
|
+
} ], START_REQUIREMENT_VARS = [ ...START_FILTER_VARS, {
|
|
1577
1637
|
name: "fields",
|
|
1578
1638
|
label: "the start's input fields",
|
|
1579
1639
|
description: "The caller's input entries by name (`initialFields` — at `startInstance`, the values the start would seed; at a pre-flight, the values gathered so far, so a read of a not-yet-supplied entry is GROQ null). Document references bind as GDR envelopes — `$fields.<entry>.id` is the GDR URI, never a string authors assemble — a singular `doc.ref` or `subject` included (nothing hydrates at the gate or the pre-flight). Pathed reads are deploy-checked against these envelope shapes."
|
|
@@ -1758,6 +1818,37 @@ function isNotesEntry(entry) {
|
|
|
1758
1818
|
return columns !== void 0 && columns.has("body") && columns.has("actor") && columns.has("at");
|
|
1759
1819
|
}
|
|
1760
1820
|
|
|
1821
|
+
const ANONYMOUS_IDENTITY = "<anonymous>", SYSTEM_IDENTITY = "<system>", E_PREFIXED_PROJECT_ID = /^e-(.+)$/;
|
|
1822
|
+
|
|
1823
|
+
function classifyPrincipalId(id) {
|
|
1824
|
+
if (id === ANONYMOUS_IDENTITY || id === SYSTEM_IDENTITY) return {
|
|
1825
|
+
namespace: "sentinel"
|
|
1826
|
+
};
|
|
1827
|
+
if (id.startsWith("g")) return {
|
|
1828
|
+
namespace: "global",
|
|
1829
|
+
globalId: id
|
|
1830
|
+
};
|
|
1831
|
+
if (id.startsWith("p-")) return {
|
|
1832
|
+
namespace: "robot",
|
|
1833
|
+
globalId: id
|
|
1834
|
+
};
|
|
1835
|
+
const embeddedGlobal = E_PREFIXED_PROJECT_ID.exec(id)?.[1];
|
|
1836
|
+
return embeddedGlobal !== void 0 ? embeddedGlobal.startsWith("g") ? {
|
|
1837
|
+
namespace: "project",
|
|
1838
|
+
globalId: embeddedGlobal
|
|
1839
|
+
} : {
|
|
1840
|
+
namespace: "unknown"
|
|
1841
|
+
} : id.startsWith("p") ? {
|
|
1842
|
+
namespace: "project"
|
|
1843
|
+
} : {
|
|
1844
|
+
namespace: "unknown"
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
function lakePrincipalId(args) {
|
|
1849
|
+
return args.localPrincipalId ?? args.actor.id;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1761
1852
|
class FieldValueShapeError extends WorkflowError {
|
|
1762
1853
|
entryType;
|
|
1763
1854
|
entryName;
|
|
@@ -1798,11 +1889,11 @@ function checkChoiceList(args) {
|
|
|
1798
1889
|
const {entryType: entryType, options: options, validation: validation} = args;
|
|
1799
1890
|
if (options === void 0) return;
|
|
1800
1891
|
if (!CHOICE_KINDS.has(entryType)) return [ `\`options\` is not valid on "${entryType}" values` ];
|
|
1801
|
-
const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => checkValueAgainst({
|
|
1892
|
+
const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => issuesOf(checkValueAgainst({
|
|
1802
1893
|
entryType: kind,
|
|
1803
1894
|
value: option.value,
|
|
1804
1895
|
validation: validation
|
|
1805
|
-
}, valueSchemas)?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
|
|
1896
|
+
}, valueSchemas))?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
|
|
1806
1897
|
for (const option of options.list) seen.has(option.value) && issues.push(`duplicate option value ${JSON.stringify(option.value)}`),
|
|
1807
1898
|
seen.add(option.value);
|
|
1808
1899
|
return issues.length === 0 ? void 0 : issues;
|
|
@@ -1828,8 +1919,27 @@ const fieldValueSchemas = {
|
|
|
1828
1919
|
actor: v__namespace.union([ v__namespace.null(), ActorShape ]),
|
|
1829
1920
|
assignee: v__namespace.union([ v__namespace.null(), AssigneeShape ]),
|
|
1830
1921
|
assignees: v__namespace.array(AssigneeShape)
|
|
1831
|
-
},
|
|
1922
|
+
}, WritePrincipalId = v__namespace.pipe(NonEmptyString, v__namespace.rawTransform(({dataset: dataset, addIssue: addIssue}) => {
|
|
1923
|
+
const classified = classifyPrincipalId(dataset.value);
|
|
1924
|
+
return classified.namespace === "global" || classified.namespace === "robot" ? dataset.value : classified.namespace === "project" && classified.globalId !== void 0 ? classified.globalId : (addIssue({
|
|
1925
|
+
message: `principal id "${dataset.value}" is not an account-global user id. Workflow user ids are the global \`sanityUserId\` (or a robot token's id). Resolve project members through your surface's member hook, or /projects/<projectId>/users/<id> → sanityUserId.`
|
|
1926
|
+
}), dataset.value);
|
|
1927
|
+
})), ActorWriteShape = tolerantObject()({
|
|
1928
|
+
kind: v__namespace.picklist(ACTOR_KINDS),
|
|
1929
|
+
id: WritePrincipalId,
|
|
1930
|
+
roles: v__namespace.exactOptional(v__namespace.array(v__namespace.string())),
|
|
1931
|
+
onBehalfOf: v__namespace.exactOptional(v__namespace.string())
|
|
1932
|
+
}), AssigneeWriteShape = v__namespace.union([ tolerantObject()({
|
|
1933
|
+
type: v__namespace.literal("user"),
|
|
1934
|
+
id: WritePrincipalId
|
|
1935
|
+
}), tolerantObject()({
|
|
1936
|
+
type: v__namespace.literal("role"),
|
|
1937
|
+
role: NonEmptyString
|
|
1938
|
+
}) ]), valueSchemas = {
|
|
1832
1939
|
...fieldValueSchemas,
|
|
1940
|
+
actor: v__namespace.nullable(ActorWriteShape),
|
|
1941
|
+
assignee: v__namespace.nullable(AssigneeWriteShape),
|
|
1942
|
+
assignees: v__namespace.array(AssigneeWriteShape),
|
|
1833
1943
|
query: v__namespace.any()
|
|
1834
1944
|
};
|
|
1835
1945
|
|
|
@@ -1900,7 +2010,7 @@ function wholeValueSchema(args) {
|
|
|
1900
2010
|
function appendItemSchema(entryType, shape) {
|
|
1901
2011
|
if (entryType === "array") return objectSchema(shape.of ?? [], valueSchemas);
|
|
1902
2012
|
if (entryType === "doc.refs") return GdrShape;
|
|
1903
|
-
if (entryType === "assignees") return
|
|
2013
|
+
if (entryType === "assignees") return AssigneeWriteShape;
|
|
1904
2014
|
}
|
|
1905
2015
|
|
|
1906
2016
|
function rejectedRefTypes(args) {
|
|
@@ -1925,7 +2035,7 @@ function gdrTypeOf(item) {
|
|
|
1925
2035
|
return typeof t == "string" ? t : void 0;
|
|
1926
2036
|
}
|
|
1927
2037
|
|
|
1928
|
-
function
|
|
2038
|
+
function parseFieldValue(args) {
|
|
1929
2039
|
return checkValueAgainst(args, valueSchemas);
|
|
1930
2040
|
}
|
|
1931
2041
|
|
|
@@ -1935,9 +2045,14 @@ function checkValueAgainst(args, leaf) {
|
|
|
1935
2045
|
shape: args,
|
|
1936
2046
|
leaf: leaf
|
|
1937
2047
|
});
|
|
1938
|
-
if (schema === void 0) return
|
|
2048
|
+
if (schema === void 0) return {
|
|
2049
|
+
issues: [ `unknown field entry type ${args.entryType}` ]
|
|
2050
|
+
};
|
|
1939
2051
|
const result = v__namespace.safeParse(schema, args.value);
|
|
1940
|
-
|
|
2052
|
+
if (!result.success) return {
|
|
2053
|
+
issues: formatIssues(result.issues)
|
|
2054
|
+
};
|
|
2055
|
+
const postIssues = refTypeIssues({
|
|
1941
2056
|
entryType: args.entryType,
|
|
1942
2057
|
types: args.types,
|
|
1943
2058
|
value: args.value
|
|
@@ -1945,17 +2060,27 @@ function checkValueAgainst(args, leaf) {
|
|
|
1945
2060
|
entryType: args.entryType,
|
|
1946
2061
|
validation: args.validation,
|
|
1947
2062
|
value: args.value
|
|
1948
|
-
})
|
|
2063
|
+
});
|
|
2064
|
+
return postIssues !== void 0 ? {
|
|
2065
|
+
issues: postIssues
|
|
2066
|
+
} : {
|
|
2067
|
+
output: result.output
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
function issuesOf(check) {
|
|
2072
|
+
return "issues" in check ? check.issues : void 0;
|
|
1949
2073
|
}
|
|
1950
2074
|
|
|
1951
2075
|
function validateFieldValue(args) {
|
|
1952
|
-
const
|
|
1953
|
-
if (issues
|
|
2076
|
+
const check = checkValueAgainst(args, valueSchemas);
|
|
2077
|
+
if ("issues" in check) throw new FieldValueShapeError({
|
|
1954
2078
|
entryType: args.entryType,
|
|
1955
2079
|
entryName: args.entryName,
|
|
1956
|
-
issues: issues,
|
|
2080
|
+
issues: check.issues,
|
|
1957
2081
|
mode: "value"
|
|
1958
2082
|
});
|
|
2083
|
+
return check.output;
|
|
1959
2084
|
}
|
|
1960
2085
|
|
|
1961
2086
|
const BARE_ID_SOURCE = "[A-Za-z0-9_][A-Za-z0-9._-]*", BARE_ID_RE = new RegExp(`^${BARE_ID_SOURCE}$`), ALIAS_REF_RE = new RegExp(`^@${RESOURCE_ALIAS_NAME_SOURCE}:${BARE_ID_SOURCE}$`);
|
|
@@ -1984,7 +2109,7 @@ const AuthoringRefId = v__namespace.pipe(v__namespace.string(), v__namespace.che
|
|
|
1984
2109
|
};
|
|
1985
2110
|
|
|
1986
2111
|
function checkLiteralSeed(args) {
|
|
1987
|
-
return args.value === null ? [ "a literal seed cannot be null — omit `initialValue` to start the field empty" ] : checkValueAgainst(args, seedValueSchemas);
|
|
2112
|
+
return args.value === null ? [ "a literal seed cannot be null — omit `initialValue` to start the field empty" ] : issuesOf(checkValueAgainst(args, seedValueSchemas));
|
|
1988
2113
|
}
|
|
1989
2114
|
|
|
1990
2115
|
function validateFieldAppendItem(args) {
|
|
@@ -2013,13 +2138,15 @@ function validateFieldAppendItem(args) {
|
|
|
2013
2138
|
issues: typeIssues,
|
|
2014
2139
|
mode: "item"
|
|
2015
2140
|
});
|
|
2141
|
+
return result.output;
|
|
2016
2142
|
}
|
|
2017
2143
|
|
|
2018
2144
|
function formatIssues(issues, formatMessage = issue => issue.message) {
|
|
2019
|
-
|
|
2020
|
-
const keys =
|
|
2021
|
-
return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(
|
|
2022
|
-
}
|
|
2145
|
+
const formatOne = (issue, prefix) => {
|
|
2146
|
+
const keys = [ ...prefix, ...issue.path?.map(p => p.key) ?? [] ], sub = issue.issues?.filter(candidate => candidate.expected !== "null");
|
|
2147
|
+
return sub !== void 0 && sub.length > 0 ? sub.flatMap(candidate => formatOne(candidate, keys)) : [ `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(issue)}` ];
|
|
2148
|
+
};
|
|
2149
|
+
return issues.flatMap(issue => formatOne(issue, []));
|
|
2023
2150
|
}
|
|
2024
2151
|
|
|
2025
2152
|
const NonEmpty = NonEmptyString, PositiveInt = v__namespace.pipe(v__namespace.number(), v__namespace.integer(), v__namespace.minValue(1)), GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -2029,7 +2156,15 @@ function groqIdentifier(referencedAs) {
|
|
|
2029
2156
|
}
|
|
2030
2157
|
|
|
2031
2158
|
function picklist(options) {
|
|
2032
|
-
return v__namespace.picklist(options,
|
|
2159
|
+
return v__namespace.picklist(options, invalidOptionMessage(options));
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
function invalidOptionMessage(options) {
|
|
2163
|
+
return `Invalid option: expected one of ${options.map(option => `"${option}"`).join("|")}`;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
function exhaustiveOptions() {
|
|
2167
|
+
return options => options;
|
|
2033
2168
|
}
|
|
2034
2169
|
|
|
2035
2170
|
function pinned() {
|
|
@@ -2044,12 +2179,12 @@ const LiteralSchema = v__namespace.strictObject({
|
|
|
2044
2179
|
scope: v__namespace.optional(v__namespace.union([ v__namespace.literal("workflow"), v__namespace.literal("stage") ])),
|
|
2045
2180
|
field: NonEmpty,
|
|
2046
2181
|
path: v__namespace.optional(v__namespace.string())
|
|
2047
|
-
}), FieldSourceSchema = v__namespace.
|
|
2182
|
+
}), FieldSourceSchema = v__namespace.variant("type", [ v__namespace.strictObject({
|
|
2048
2183
|
type: v__namespace.literal("input")
|
|
2049
2184
|
}), v__namespace.strictObject({
|
|
2050
2185
|
type: v__namespace.literal("query"),
|
|
2051
2186
|
query: NonEmpty
|
|
2052
|
-
}), LiteralSchema, FieldReadSchema ]), ValueExprSchema = v__namespace.lazy(() => v__namespace.
|
|
2187
|
+
}), LiteralSchema, FieldReadSchema ]), ValueExprSchema = v__namespace.lazy(() => v__namespace.variant("type", [ LiteralSchema, FieldReadSchema, v__namespace.strictObject({
|
|
2053
2188
|
type: v__namespace.literal("param"),
|
|
2054
2189
|
param: NonEmpty
|
|
2055
2190
|
}), v__namespace.strictObject({
|
|
@@ -2144,7 +2279,7 @@ function groupMembershipNames(group) {
|
|
|
2144
2279
|
return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
|
|
2145
2280
|
}
|
|
2146
2281
|
|
|
2147
|
-
const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v__namespace.pipe(v__namespace.number(), v__namespace.finite("must be finite")), ScalarValidationSchema = v__namespace.pipe(v__namespace.strictObject({
|
|
2282
|
+
const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v__namespace.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v__namespace.pipe(v__namespace.number(), v__namespace.finite("must be finite")), ScalarValidationSchema = v__namespace.pipe(v__namespace.strictObject({
|
|
2148
2283
|
min: v__namespace.optional(FiniteNumber),
|
|
2149
2284
|
max: v__namespace.optional(FiniteNumber)
|
|
2150
2285
|
}), v__namespace.check(validation => validation.min !== void 0 || validation.max !== void 0, "declare at least one bound, or omit `validation`"), v__namespace.check(validation => validation.min === void 0 || validation.max === void 0 || validation.min <= validation.max, "`min` must be less than or equal to `max`")), ChoiceOptionsSchema = v__namespace.strictObject({
|
|
@@ -2209,9 +2344,9 @@ function fieldBase(editable, group) {
|
|
|
2209
2344
|
};
|
|
2210
2345
|
}
|
|
2211
2346
|
|
|
2212
|
-
function fieldEntryFields(editable, group) {
|
|
2347
|
+
function fieldEntryFields({editable: editable, group: group, kind: kind = FieldKindSchema}) {
|
|
2213
2348
|
return {
|
|
2214
|
-
type:
|
|
2349
|
+
type: kind,
|
|
2215
2350
|
...fieldBase(editable, group),
|
|
2216
2351
|
options: v__namespace.optional(ChoiceOptionsSchema),
|
|
2217
2352
|
validation: v__namespace.optional(ScalarValidationSchema),
|
|
@@ -2272,7 +2407,14 @@ function scalarValidationDeclarationIssues(entry) {
|
|
|
2272
2407
|
return issues.length === 0 ? void 0 : issues;
|
|
2273
2408
|
}
|
|
2274
2409
|
|
|
2275
|
-
const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(
|
|
2410
|
+
const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields({
|
|
2411
|
+
editable: StoredEditableSchema,
|
|
2412
|
+
group: StoredGroupMembershipSchema
|
|
2413
|
+
})), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields({
|
|
2414
|
+
editable: AuthoringEditableSchema,
|
|
2415
|
+
group: AuthoringGroupMembershipSchema,
|
|
2416
|
+
kind: AuthoringRawFieldKindSchema
|
|
2417
|
+
})), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v__namespace.strictObject({
|
|
2276
2418
|
type: v__namespace.literal("claim"),
|
|
2277
2419
|
name: FieldEntryName,
|
|
2278
2420
|
title: v__namespace.optional(v__namespace.string()),
|
|
@@ -2287,7 +2429,10 @@ function listSugarFields(type) {
|
|
|
2287
2429
|
};
|
|
2288
2430
|
}
|
|
2289
2431
|
|
|
2290
|
-
const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("todoList"))), NotesFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("notes"))), AuthoringFieldEntrySchema = pinned()(v__namespace.
|
|
2432
|
+
const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("todoList"))), NotesFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("notes"))), AuthoringFieldEntrySchema = pinned()(v__namespace.lazy(input => {
|
|
2433
|
+
const type = asShape(input).type;
|
|
2434
|
+
return type === "claim" ? ClaimFieldSchema : type === "todoList" ? TodoListFieldSchema : type === "notes" ? NotesFieldSchema : RawAuthoringFieldEntrySchema;
|
|
2435
|
+
})), EffectSchema = v__namespace.strictObject({
|
|
2291
2436
|
name: NonEmpty,
|
|
2292
2437
|
title: v__namespace.optional(v__namespace.string()),
|
|
2293
2438
|
description: v__namespace.optional(v__namespace.string()),
|
|
@@ -2352,7 +2497,18 @@ const StoredActionSchema = pinned()(v__namespace.strictObject({
|
|
|
2352
2497
|
filter: v__namespace.optional(ConditionSchema),
|
|
2353
2498
|
params: v__namespace.optional(v__namespace.array(ActionParamSchema)),
|
|
2354
2499
|
effects: v__namespace.optional(v__namespace.array(EffectSchema))
|
|
2355
|
-
})), AuthoringActionSchema = pinned()(v__namespace.lazy(input => typeof input == "object" && input !== null && "type" in input ? ClaimActionSchema : RawAuthoringActionSchema))
|
|
2500
|
+
})), AuthoringActionSchema = pinned()(v__namespace.lazy(input => typeof input == "object" && input !== null && "type" in input ? ClaimActionSchema : RawAuthoringActionSchema)), requirementBase = {
|
|
2501
|
+
name: NonEmpty,
|
|
2502
|
+
title: v__namespace.optional(v__namespace.string()),
|
|
2503
|
+
description: v__namespace.optional(v__namespace.string())
|
|
2504
|
+
}, GroqRequirementSchemaRaw = v__namespace.strictObject({
|
|
2505
|
+
...requirementBase,
|
|
2506
|
+
type: v__namespace.literal("groq"),
|
|
2507
|
+
query: ConditionSchema
|
|
2508
|
+
}), SingleSubjectRequirementSchemaRaw = v__namespace.strictObject({
|
|
2509
|
+
...requirementBase,
|
|
2510
|
+
type: v__namespace.literal("singleSubject")
|
|
2511
|
+
}), GroqRequirementSchema = pinned()(GroqRequirementSchemaRaw), StartRequirementSchema = pinned()(v__namespace.variant("type", [ GroqRequirementSchemaRaw, SingleSubjectRequirementSchemaRaw ]));
|
|
2356
2512
|
|
|
2357
2513
|
function activityFields({field: field, action: action, target: target, group: group}) {
|
|
2358
2514
|
return {
|
|
@@ -2363,7 +2519,7 @@ function activityFields({field: field, action: action, target: target, group: gr
|
|
|
2363
2519
|
group: v__namespace.optional(group),
|
|
2364
2520
|
target: v__namespace.optional(target),
|
|
2365
2521
|
filter: v__namespace.optional(ConditionSchema),
|
|
2366
|
-
requirements: v__namespace.optional(v__namespace.
|
|
2522
|
+
requirements: v__namespace.optional(v__namespace.array(GroqRequirementSchema)),
|
|
2367
2523
|
actions: v__namespace.optional(v__namespace.array(action)),
|
|
2368
2524
|
fields: v__namespace.optional(v__namespace.array(field))
|
|
2369
2525
|
};
|
|
@@ -2459,7 +2615,7 @@ function startFields(kind) {
|
|
|
2459
2615
|
return {
|
|
2460
2616
|
kind: kind,
|
|
2461
2617
|
filter: v__namespace.optional(ConditionSchema),
|
|
2462
|
-
|
|
2618
|
+
requirements: v__namespace.optional(v__namespace.array(StartRequirementSchema))
|
|
2463
2619
|
};
|
|
2464
2620
|
}
|
|
2465
2621
|
|
|
@@ -2598,6 +2754,13 @@ function checkActivities({def: def, i: i, activityNames: activityNames, issues:
|
|
|
2598
2754
|
})),
|
|
2599
2755
|
what: `action name in activity "${activity.name}"`,
|
|
2600
2756
|
issues: issues
|
|
2757
|
+
}), checkDuplicates({
|
|
2758
|
+
names: (activity.requirements ?? []).map((requirement, r) => ({
|
|
2759
|
+
name: requirement.name,
|
|
2760
|
+
path: [ ...path, "requirements", r, "name" ]
|
|
2761
|
+
})),
|
|
2762
|
+
what: `requirement name in activity "${activity.name}"`,
|
|
2763
|
+
issues: issues
|
|
2601
2764
|
}), checkStatusSetTargets({
|
|
2602
2765
|
activity: activity,
|
|
2603
2766
|
activityNames: activityNames,
|
|
@@ -2906,10 +3069,10 @@ function collectActivityConditionSites({activity: activity, path: path, stageFie
|
|
|
2906
3069
|
policy: "cascade",
|
|
2907
3070
|
fields: fields
|
|
2908
3071
|
});
|
|
2909
|
-
for (const [
|
|
2910
|
-
groq:
|
|
2911
|
-
path: [ ...path, "requirements",
|
|
2912
|
-
label: `activity "${activity.name}" requirement "${name}"`,
|
|
3072
|
+
for (const [index, requirement] of (activity.requirements ?? []).entries()) sites.push({
|
|
3073
|
+
groq: requirement.query,
|
|
3074
|
+
path: [ ...path, "requirements", index, "query" ],
|
|
3075
|
+
label: `activity "${activity.name}" requirement "${requirement.name}"`,
|
|
2913
3076
|
policy: "caller-bound",
|
|
2914
3077
|
fields: fields
|
|
2915
3078
|
});
|
|
@@ -3105,73 +3268,83 @@ function checkTriggeredActionParams(def, issues) {
|
|
|
3105
3268
|
}
|
|
3106
3269
|
|
|
3107
3270
|
function checkStart(def, issues) {
|
|
3108
|
-
if (def.start !== void 0 && (
|
|
3271
|
+
if (def.start !== void 0 && (checkDuplicates({
|
|
3272
|
+
names: (def.start.requirements ?? []).map((requirement, index) => ({
|
|
3273
|
+
name: requirement.name,
|
|
3274
|
+
path: [ "start", "requirements", index, "name" ]
|
|
3275
|
+
})),
|
|
3276
|
+
what: "start requirement name",
|
|
3277
|
+
issues: issues
|
|
3278
|
+
}), def.lifecycle === "child" && issues.push({
|
|
3109
3279
|
path: [ "start" ],
|
|
3110
3280
|
message: "a spawn-only (lifecycle 'child') definition declares `start` — children are instantiated by a parent's `spawn`, never started standalone, so the block would never apply. Remove `start`, or drop `lifecycle: 'child'`"
|
|
3111
|
-
}), checkStartFilterReads(def, issues),
|
|
3112
|
-
def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
|
|
3281
|
+
}), checkStartFilterReads(def, issues), checkStartRequirementReads(def, issues),
|
|
3282
|
+
checkSingleSubjectRequirements(def, issues), def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
|
|
3113
3283
|
path: [ "fields", n, "required" ],
|
|
3114
3284
|
message: `start.kind 'autonomous' means runs are initiated by a system reacting to a document, so every required input must be derivable from that triggering document — required entry "${entry.name}" (kind "${entry.type}") is not the workflow's subject. Make it optional, seed it another way (query/literal), or declare it the \`subject\` entry (the document the run is about)`
|
|
3115
3285
|
});
|
|
3116
3286
|
}
|
|
3117
3287
|
|
|
3118
|
-
function
|
|
3288
|
+
function checkSingleSubjectRequirements(def, issues) {
|
|
3289
|
+
const indexes = (def.start?.requirements ?? []).map((requirement, index) => ({
|
|
3290
|
+
requirement: requirement,
|
|
3291
|
+
index: index
|
|
3292
|
+
})).filter(({requirement: requirement}) => requirement.type === "singleSubject"), [first] = indexes;
|
|
3293
|
+
if (first === void 0) return;
|
|
3119
3294
|
const subject = (def.fields ?? []).find(isSubjectEntry);
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
message: `start.${key} reads $${SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the definition declares no \`subject\` entry — the engine has no prospective subject identity to match. Declare a \`subject\` entry (the document the workflow is about), or remove the variable`
|
|
3125
|
-
});
|
|
3126
|
-
continue;
|
|
3127
|
-
}
|
|
3128
|
-
key === "allowed" && !isInputSourced(subject) && issues.push({
|
|
3129
|
-
path: [ "start", key ],
|
|
3130
|
-
message: `start.allowed reads $${SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the definition's subject entry "${subject.name}" is not \`input\`-sourced — the start gate cannot bind its prospective subject. Make the subject input-sourced, or remove the variable`
|
|
3295
|
+
if (subject === void 0) {
|
|
3296
|
+
issues.push({
|
|
3297
|
+
path: [ "start", "requirements", first.index ],
|
|
3298
|
+
message: "a singleSubject start requirement caps the definition at one in-flight run per subject, but the definition declares no `subject` entry — there is no subject identity to dedupe on, so the rule could never apply. Declare a `subject` entry (the document the workflow is about), or remove the requirement"
|
|
3131
3299
|
});
|
|
3300
|
+
return;
|
|
3132
3301
|
}
|
|
3302
|
+
isInputSourced(subject) || issues.push({
|
|
3303
|
+
path: [ "start", "requirements", first.index ],
|
|
3304
|
+
message: `a singleSubject start requirement matches the prospective subject against in-flight runs, but the definition's subject entry "${subject.name}" is not \`input\`-sourced — the start gate cannot bind a prospective subject. Make the subject input-sourced, or remove the requirement`
|
|
3305
|
+
});
|
|
3133
3306
|
}
|
|
3134
3307
|
|
|
3135
3308
|
function checkStartFilterReads(def, issues) {
|
|
3136
3309
|
const filter = def.start?.filter;
|
|
3137
3310
|
filter !== void 0 && (conditionParameterNames(filter).has("fields") && issues.push({
|
|
3138
3311
|
path: [ "start", "filter" ],
|
|
3139
|
-
message: "start.filter reads $fields, but the filter is browse-time-pure — a start surface evaluates it per document, before any inputs exist, so $fields cannot be bound. Move the input-dependent rule to start
|
|
3312
|
+
message: "start.filter reads $fields, but the filter is browse-time-pure — a start surface evaluates it per document, before any inputs exist, so $fields cannot be bound. Move the input-dependent rule to a start requirement, the start-time readiness predicate that binds $fields and is enforced by startInstance"
|
|
3140
3313
|
}), readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
|
|
3141
3314
|
path: [ "start", "filter" ],
|
|
3142
3315
|
message: "start.filter reads the candidate document (its root), but the definition declares no `subject` entry — a read surface would never have a document to bind as root, so every root read is GROQ null and the filter silently misevaluates. Declare a `subject` entry (the document the workflow is about), or gate on the dataset instead"
|
|
3143
3316
|
}));
|
|
3144
3317
|
}
|
|
3145
3318
|
|
|
3146
|
-
function
|
|
3147
|
-
const allowed = def.start?.allowed;
|
|
3148
|
-
if (allowed === void 0) return;
|
|
3319
|
+
function checkStartRequirementReads(def, issues) {
|
|
3149
3320
|
const bindable = new Map((def.fields ?? []).filter(isInputSourced).map(entry => [ entry.name, entry ])), declared = new Set((def.fields ?? []).map(entry => entry.name)), nullVerdict = `so the read is GROQ null and null semantics decide the verdict (refuse-all or vacuously-allow, by the expression's shape), never the caller's real input. Bindable (input) fields: ${knownList(bindable.keys())}`;
|
|
3150
|
-
for (const
|
|
3151
|
-
const
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3321
|
+
for (const [index, requirement] of (def.start?.requirements ?? []).entries()) if (requirement.type === "groq") {
|
|
3322
|
+
for (const read of conditionFieldReads(requirement.query)) {
|
|
3323
|
+
const entry = bindable.get(read.name);
|
|
3324
|
+
if (entry === void 0) {
|
|
3325
|
+
issues.push({
|
|
3326
|
+
path: [ "start", "requirements", index, "query" ],
|
|
3327
|
+
message: declared.has(read.name) ? `start requirement reads $fields.${read.name}, but "${read.name}" is not an \`input\`-sourced entry — $fields binds only the caller's input entries (query/literal/fieldRead entries resolve at materialisation, after the start gate), ${nullVerdict}` : `start requirement reads $fields.${read.name}, but no workflow-scope field entry named "${read.name}" is declared — $fields binds only the caller's input entries, ${nullVerdict}`
|
|
3328
|
+
});
|
|
3329
|
+
continue;
|
|
3330
|
+
}
|
|
3331
|
+
pushFieldReadPathIssue({
|
|
3332
|
+
where: "start requirement",
|
|
3333
|
+
read: {
|
|
3334
|
+
field: read.name,
|
|
3335
|
+
path: read.path
|
|
3336
|
+
},
|
|
3337
|
+
target: entry,
|
|
3338
|
+
path: [ "start", "requirements", index, "query" ],
|
|
3339
|
+
issues: issues,
|
|
3340
|
+
nodes: START_REQUIREMENT_VALUE_NODES
|
|
3156
3341
|
});
|
|
3157
|
-
continue;
|
|
3158
3342
|
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
field: read.name,
|
|
3163
|
-
path: read.path
|
|
3164
|
-
},
|
|
3165
|
-
target: entry,
|
|
3166
|
-
path: [ "start", "allowed" ],
|
|
3167
|
-
issues: issues,
|
|
3168
|
-
nodes: START_ALLOWED_VALUE_NODES
|
|
3343
|
+
readsRootDocument(requirement.query) && issues.push({
|
|
3344
|
+
path: [ "start", "requirements", index, "query" ],
|
|
3345
|
+
message: "start requirement reads the candidate document as its root, but no root ever binds in the start-requirement context — startInstance holds inputs, not a loaded document, so the read is GROQ null and null semantics decide the verdict, never the workflow's real state. Read the subject as $fields.<entry> (its GDR URI is $fields.<entry>.id); a per-document visibility rule belongs in start.filter"
|
|
3169
3346
|
});
|
|
3170
3347
|
}
|
|
3171
|
-
readsRootDocument(allowed) && issues.push({
|
|
3172
|
-
path: [ "start", "allowed" ],
|
|
3173
|
-
message: "start.allowed reads the candidate document as its root, but no root ever binds in the start-allowed context — startInstance holds inputs, not a loaded document, so the read is GROQ null and null semantics decide the verdict, never the workflow's real state. Read the subject as $fields.<entry> (its GDR URI is $fields.<entry>.id); a per-document visibility rule belongs in start.filter"
|
|
3174
|
-
});
|
|
3175
3348
|
}
|
|
3176
3349
|
|
|
3177
3350
|
function checkGroups(def, issues) {
|
|
@@ -3696,7 +3869,7 @@ const SCALAR = {
|
|
|
3696
3869
|
kind: "rows",
|
|
3697
3870
|
of: shape.of ?? []
|
|
3698
3871
|
})
|
|
3699
|
-
},
|
|
3872
|
+
}, START_REQUIREMENT_VALUE_NODES = {
|
|
3700
3873
|
...VALUE_NODES,
|
|
3701
3874
|
"doc.ref": () => GDR_VALUE,
|
|
3702
3875
|
subject: () => GDR_VALUE
|
|
@@ -3785,6 +3958,8 @@ exports.ACTIVITY_STATUSES = ACTIVITY_STATUSES;
|
|
|
3785
3958
|
|
|
3786
3959
|
exports.ACTOR_KINDS = ACTOR_KINDS;
|
|
3787
3960
|
|
|
3961
|
+
exports.ANONYMOUS_IDENTITY = ANONYMOUS_IDENTITY;
|
|
3962
|
+
|
|
3788
3963
|
exports.ActorShape = ActorShape;
|
|
3789
3964
|
|
|
3790
3965
|
exports.AuthoringActionSchema = AuthoringActionSchema;
|
|
@@ -3871,16 +4046,18 @@ exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
|
|
|
3871
4046
|
|
|
3872
4047
|
exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
|
|
3873
4048
|
|
|
3874
|
-
exports.START_ALLOWED_VARS = START_ALLOWED_VARS;
|
|
3875
|
-
|
|
3876
4049
|
exports.START_FILTER_VARS = START_FILTER_VARS;
|
|
3877
4050
|
|
|
3878
|
-
exports.
|
|
4051
|
+
exports.START_REQUIREMENT_VARS = START_REQUIREMENT_VARS;
|
|
4052
|
+
|
|
4053
|
+
exports.SYSTEM_IDENTITY = SYSTEM_IDENTITY;
|
|
3879
4054
|
|
|
3880
4055
|
exports.SpawnContractsInvalidError = SpawnContractsInvalidError;
|
|
3881
4056
|
|
|
3882
4057
|
exports.StoredFieldOpSchema = StoredFieldOpSchema;
|
|
3883
4058
|
|
|
4059
|
+
exports.VersionSpecificDatasetGdrError = VersionSpecificDatasetGdrError;
|
|
4060
|
+
|
|
3884
4061
|
exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
|
|
3885
4062
|
|
|
3886
4063
|
exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
|
|
@@ -3897,12 +4074,12 @@ exports.assertReadableModel = assertReadableModel;
|
|
|
3897
4074
|
|
|
3898
4075
|
exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
|
|
3899
4076
|
|
|
3900
|
-
exports.checkFieldValue = checkFieldValue;
|
|
3901
|
-
|
|
3902
4077
|
exports.checkWorkflowInvariants = checkWorkflowInvariants;
|
|
3903
4078
|
|
|
3904
4079
|
exports.choiceValueIssues = choiceValueIssues;
|
|
3905
4080
|
|
|
4081
|
+
exports.classifyPrincipalId = classifyPrincipalId;
|
|
4082
|
+
|
|
3906
4083
|
exports.clientConfigFromResource = clientConfigFromResource;
|
|
3907
4084
|
|
|
3908
4085
|
exports.conditionEffectReads = conditionEffectReads;
|
|
@@ -3993,6 +4170,8 @@ exports.isUnprimed = isUnprimed;
|
|
|
3993
4170
|
|
|
3994
4171
|
exports.labelFor = labelFor;
|
|
3995
4172
|
|
|
4173
|
+
exports.lakePrincipalId = lakePrincipalId;
|
|
4174
|
+
|
|
3996
4175
|
exports.minReaderModelOf = minReaderModelOf;
|
|
3997
4176
|
|
|
3998
4177
|
exports.modelStampFor = modelStampFor;
|
|
@@ -4003,6 +4182,8 @@ exports.parentRef = parentRef;
|
|
|
4003
4182
|
|
|
4004
4183
|
exports.parseDefinitionSnapshot = parseDefinitionSnapshot;
|
|
4005
4184
|
|
|
4185
|
+
exports.parseFieldValue = parseFieldValue;
|
|
4186
|
+
|
|
4006
4187
|
exports.parseGdr = parseGdr;
|
|
4007
4188
|
|
|
4008
4189
|
exports.parseOrThrow = parseOrThrow;
|