@sanity/workflow-engine 0.17.0 → 0.18.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 +44 -0
- package/DATAMODEL.md +140 -13
- package/README.md +23 -0
- package/dist/_chunks-cjs/invariants.cjs +620 -116
- package/dist/_chunks-es/invariants.js +567 -117
- package/dist/define.cjs +6 -1
- package/dist/define.d.cts +185 -36
- package/dist/define.d.ts +185 -36
- package/dist/define.js +7 -2
- package/dist/index.cjs +852 -392
- package/dist/index.d.cts +746 -198
- package/dist/index.d.ts +746 -198
- package/dist/index.js +752 -330
- package/package.json +1 -1
|
@@ -20,6 +20,291 @@ function _interopNamespaceCompat(e) {
|
|
|
20
20
|
|
|
21
21
|
var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
|
|
22
22
|
|
|
23
|
+
class WorkflowError extends Error {
|
|
24
|
+
kind;
|
|
25
|
+
constructor(kind, message, options) {
|
|
26
|
+
super(message, options), this.kind = kind;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class ContractViolationError extends WorkflowError {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super("contract-violation", message), this.name = "ContractViolationError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class InstanceNotFoundError extends WorkflowError {
|
|
37
|
+
instanceId;
|
|
38
|
+
constructor(args) {
|
|
39
|
+
super("instance-not-found", `Workflow instance ${args.instanceId} not found${args.detail ? ` (${args.detail})` : ""}`),
|
|
40
|
+
this.name = "InstanceNotFoundError", this.instanceId = args.instanceId;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class DefinitionNotFoundError extends WorkflowError {
|
|
45
|
+
definition;
|
|
46
|
+
version;
|
|
47
|
+
constructor(args) {
|
|
48
|
+
super("definition-not-found", args.version !== void 0 ? `Workflow definition ${args.definition} v${args.version} not deployed` : `Workflow definition ${args.definition} has no deployed versions`),
|
|
49
|
+
this.name = "DefinitionNotFoundError", this.definition = args.definition, args.version !== void 0 && (this.version = args.version);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class SpawnContractsInvalidError extends WorkflowError {
|
|
54
|
+
issues;
|
|
55
|
+
constructor(args) {
|
|
56
|
+
super("spawn-contracts-invalid", args.message), this.name = "SpawnContractsInvalidError",
|
|
57
|
+
this.issues = args.issues;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class DefinitionInUseError extends WorkflowError {
|
|
62
|
+
definition;
|
|
63
|
+
blockedBy;
|
|
64
|
+
constructor(args) {
|
|
65
|
+
super("definition-in-use", definitionInUseMessage(args.definition, args.blockedBy)),
|
|
66
|
+
this.name = "DefinitionInUseError", this.definition = args.definition, this.blockedBy = args.blockedBy;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function definitionInUseMessage(definition, blockedBy) {
|
|
71
|
+
if (blockedBy.reason === "non-terminal-instances") {
|
|
72
|
+
const head = blockedBy.instanceIds.slice(0, 3).join(", "), preview = blockedBy.instanceIds.length > 3 ? `${head}, …` : head;
|
|
73
|
+
return `Cannot delete ${definition}: ${blockedBy.instanceIds.length} non-terminal instance(s) exist (${preview}). Pass cascade to abort them first — instances are aborted in place, never deleted.`;
|
|
74
|
+
}
|
|
75
|
+
const names = blockedBy.referrers.map(r => `${r.definition} v${r.version}`).join(", ");
|
|
76
|
+
return `Cannot delete ${definition}: still spawn-referenced by deployed definition(s) ${names}. Delete or redeploy the referrer(s) first.`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
class EffectNotFoundError extends WorkflowError {
|
|
80
|
+
instanceId;
|
|
81
|
+
effectKey;
|
|
82
|
+
settled;
|
|
83
|
+
constructor(args) {
|
|
84
|
+
super("effect-not-found", effectNotFoundMessage(args)), this.name = "EffectNotFoundError",
|
|
85
|
+
this.instanceId = args.instanceId, this.effectKey = args.effectKey, args.settled !== void 0 && (this.settled = args.settled);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function effectNotFoundMessage(args) {
|
|
90
|
+
const base = `Pending effect "${args.effectKey}" not found on instance ${args.instanceId}`;
|
|
91
|
+
if (args.settled === void 0) return base;
|
|
92
|
+
const cause = args.settled.detail !== void 0 ? ` (${args.settled.detail})` : "";
|
|
93
|
+
return args.settled.status === "cancelled" ? `${base} — it was cancelled at ${args.settled.ranAt}${cause}` : `${base} — it already settled "${args.settled.status}" at ${args.settled.ranAt}${cause}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function errorMessage(err) {
|
|
97
|
+
return (err instanceof Error ? err.message : String(err)).replace(/[^\P{Cc}\n\t]/gu, "");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function rethrowWithContext(err, context) {
|
|
101
|
+
throw new Error(`${context}: ${errorMessage(err)}`, {
|
|
102
|
+
cause: err
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
|
|
107
|
+
|
|
108
|
+
function terminalState(instance) {
|
|
109
|
+
return instance.abortedAt !== void 0 ? "aborted" : instance.completedAt !== void 0 ? "completed" : "in-flight";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isUnprimed(instance) {
|
|
113
|
+
return instance.stages.length === 0 && terminalState(instance) === "in-flight";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseDefinitionSnapshotValue(instance) {
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(instance.definitionSnapshot);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseDefinitionSnapshot(instance) {
|
|
125
|
+
return parseDefinitionSnapshotValue(instance);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function parentRef(instance) {
|
|
129
|
+
return instance.ancestors.at(-1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const DATA_MODEL_VERSION = 2, DATA_MODEL_MIN_READER = 2, READER_MODEL_ROLLOUT_URL = "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
|
|
133
|
+
|
|
134
|
+
class ReaderModelAcknowledgementError extends WorkflowError {
|
|
135
|
+
code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
|
|
136
|
+
expectedMinReaderModel;
|
|
137
|
+
engineMinReaderModel=DATA_MODEL_MIN_READER;
|
|
138
|
+
engineModelVersion=DATA_MODEL_VERSION;
|
|
139
|
+
documentationUrl=READER_MODEL_ROLLOUT_URL;
|
|
140
|
+
constructor(expectedMinReaderModel, context = "Deployment") {
|
|
141
|
+
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}`),
|
|
143
|
+
this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
|
|
148
|
+
if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
|
|
152
|
+
id: "governed-model-stamps",
|
|
153
|
+
introducedInModel: 1,
|
|
154
|
+
minReaderModel: 0,
|
|
155
|
+
documentTypes: Object.freeze([ "definition", "instance" ]),
|
|
156
|
+
compatibility: "additive",
|
|
157
|
+
applicability: "unconditional",
|
|
158
|
+
summary: "Definition and instance documents carry model provenance and reader-floor stamps."
|
|
159
|
+
}), Object.freeze({
|
|
160
|
+
id: "subject-field-kind",
|
|
161
|
+
introducedInModel: 2,
|
|
162
|
+
minReaderModel: 0,
|
|
163
|
+
documentTypes: Object.freeze([ "definition", "instance" ]),
|
|
164
|
+
compatibility: "additive",
|
|
165
|
+
applicability: "detectable",
|
|
166
|
+
summary: "A workflow-level subject field identifies the document a workflow is about."
|
|
167
|
+
}), Object.freeze({
|
|
168
|
+
id: "typed-scalar-choice-lists",
|
|
169
|
+
introducedInModel: 2,
|
|
170
|
+
minReaderModel: 2,
|
|
171
|
+
documentTypes: Object.freeze([ "definition", "instance" ]),
|
|
172
|
+
compatibility: "reader-floor",
|
|
173
|
+
applicability: "detectable",
|
|
174
|
+
summary: "Scalar fields may constrain writes to a persisted typed choice list."
|
|
175
|
+
}), Object.freeze({
|
|
176
|
+
id: "action-semantics",
|
|
177
|
+
introducedInModel: 2,
|
|
178
|
+
minReaderModel: 0,
|
|
179
|
+
documentTypes: Object.freeze([ "definition" ]),
|
|
180
|
+
compatibility: "additive",
|
|
181
|
+
applicability: "detectable",
|
|
182
|
+
summary: "Ordinary actions may carry a closed bag of advisory workflow semantics."
|
|
183
|
+
}), Object.freeze({
|
|
184
|
+
id: "inclusive-scalar-bounds",
|
|
185
|
+
introducedInModel: 2,
|
|
186
|
+
minReaderModel: 2,
|
|
187
|
+
documentTypes: Object.freeze([ "definition", "instance" ]),
|
|
188
|
+
compatibility: "reader-floor",
|
|
189
|
+
applicability: "detectable",
|
|
190
|
+
summary: "String, text, and number values may carry persisted inclusive bounds."
|
|
191
|
+
}) ]);
|
|
192
|
+
|
|
193
|
+
function recordOf(value) {
|
|
194
|
+
return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function recordsAt(record, key) {
|
|
198
|
+
const value = record[key];
|
|
199
|
+
return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function nestedFieldEntries(entries) {
|
|
203
|
+
return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function parsedDefinitionSnapshot(root) {
|
|
207
|
+
if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
|
|
208
|
+
_id: typeof root._id == "string" ? root._id : "<unknown instance>",
|
|
209
|
+
definitionSnapshot: root.definitionSnapshot
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function persistedFieldEntries(document) {
|
|
214
|
+
const root = recordOf(document);
|
|
215
|
+
if (root === void 0) return [];
|
|
216
|
+
const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], stages = roots.flatMap(candidate => recordsAt(candidate, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions")), effects = actions.flatMap(action => recordsAt(action, "effects"));
|
|
217
|
+
return nestedFieldEntries([ ...roots.flatMap(candidate => recordsAt(candidate, "fields")), ...stages.flatMap(stage => recordsAt(stage, "fields")), ...activities.flatMap(activity => recordsAt(activity, "fields")), ...actions.flatMap(action => recordsAt(action, "params")), ...effects.flatMap(effect => recordsAt(effect, "outputs")) ]);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function hasChoiceList(document) {
|
|
221
|
+
return persistedFieldEntries(document).some(entry => {
|
|
222
|
+
const options = recordOf(entry.options);
|
|
223
|
+
return options !== void 0 && Array.isArray(options.list);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function hasSubjectField(document) {
|
|
228
|
+
return persistedFieldEntries(document).some(entry => entry.type === "subject" || entry._type === "subject");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function hasActionSemantics(document) {
|
|
232
|
+
const root = recordOf(document);
|
|
233
|
+
return root === void 0 ? !1 : recordsAt(root, "stages").flatMap(stage => recordsAt(stage, "activities")).flatMap(activity => recordsAt(activity, "actions")).some(action => Array.isArray(action.semantics));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function hasScalarValidation(document) {
|
|
237
|
+
return persistedFieldEntries(document).some(entry => {
|
|
238
|
+
const validation = recordOf(entry.validation);
|
|
239
|
+
return typeof validation?.min == "number" || typeof validation?.max == "number";
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const featureDetectors = {
|
|
244
|
+
"governed-model-stamps": () => !0,
|
|
245
|
+
"subject-field-kind": hasSubjectField,
|
|
246
|
+
"typed-scalar-choice-lists": hasChoiceList,
|
|
247
|
+
"action-semantics": hasActionSemantics,
|
|
248
|
+
"inclusive-scalar-bounds": hasScalarValidation
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
function requiredModelFeatures(documentType, document) {
|
|
252
|
+
return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function requiredReaderModel(documentType, document) {
|
|
256
|
+
return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function modelStampFor(args) {
|
|
260
|
+
return {
|
|
261
|
+
modelVersion: DATA_MODEL_VERSION,
|
|
262
|
+
minReaderModel: Math.max(args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function fieldTreeShape(value) {
|
|
267
|
+
if (Array.isArray(value)) return value.map(fieldTreeShape);
|
|
268
|
+
if (value === null) return "null";
|
|
269
|
+
if (typeof value == "object") {
|
|
270
|
+
const record = value;
|
|
271
|
+
return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
|
|
272
|
+
}
|
|
273
|
+
return typeof value;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function modelVersionOf(doc) {
|
|
277
|
+
const stamp = doc.modelVersion;
|
|
278
|
+
return typeof stamp == "number" ? stamp : 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function minReaderModelOf(doc) {
|
|
282
|
+
const floor = doc.minReaderModel;
|
|
283
|
+
return typeof floor == "number" ? floor : modelVersionOf(doc);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
class ModelVersionAheadError extends WorkflowError {
|
|
287
|
+
documentId;
|
|
288
|
+
documentModelVersion;
|
|
289
|
+
requiredReaderModel;
|
|
290
|
+
engineModelVersion;
|
|
291
|
+
constructor(args) {
|
|
292
|
+
super("model-version-ahead", `Document "${args.documentId}" was written by engine data model ${args.documentModelVersion} and requires a reader at model ${args.requiredReaderModel} or newer; this engine reads up to model ${DATA_MODEL_VERSION}. Upgrade @sanity/workflow-engine to a version that understands it.`),
|
|
293
|
+
this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
|
|
294
|
+
this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function assertReadableModel(doc) {
|
|
299
|
+
const documentReaderModel = minReaderModelOf(doc);
|
|
300
|
+
if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
|
|
301
|
+
documentId: doc._id,
|
|
302
|
+
documentModelVersion: modelVersionOf(doc),
|
|
303
|
+
requiredReaderModel: documentReaderModel
|
|
304
|
+
});
|
|
305
|
+
return doc;
|
|
306
|
+
}
|
|
307
|
+
|
|
23
308
|
function isCascadeFired(action) {
|
|
24
309
|
return action.when !== void 0;
|
|
25
310
|
}
|
|
@@ -40,16 +325,6 @@ function driverKind(actor) {
|
|
|
40
325
|
return actor.kind === "person" || actor.kind === "agent" ? actor.kind : "service";
|
|
41
326
|
}
|
|
42
327
|
|
|
43
|
-
function errorMessage(err) {
|
|
44
|
-
return (err instanceof Error ? err.message : String(err)).replace(/[^\P{Cc}\n\t]/gu, "");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function rethrowWithContext(err, context) {
|
|
48
|
-
throw new Error(`${context}: ${errorMessage(err)}`, {
|
|
49
|
-
cause: err
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
328
|
function andConditions(parts) {
|
|
54
329
|
const present = parts.filter(p => p !== void 0);
|
|
55
330
|
if (present.length !== 0) return present.length === 1 ? present[0] : present.map(p => `(${p})`).join(" && ");
|
|
@@ -250,71 +525,6 @@ function isGdr(value) {
|
|
|
250
525
|
return typeof value == "object" && value !== null && typeof value.id == "string" && typeof value.type == "string";
|
|
251
526
|
}
|
|
252
527
|
|
|
253
|
-
class WorkflowError extends Error {
|
|
254
|
-
kind;
|
|
255
|
-
constructor(kind, message, options) {
|
|
256
|
-
super(message, options), this.kind = kind;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
class ContractViolationError extends WorkflowError {
|
|
261
|
-
constructor(message) {
|
|
262
|
-
super("contract-violation", message), this.name = "ContractViolationError";
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
class InstanceNotFoundError extends WorkflowError {
|
|
267
|
-
instanceId;
|
|
268
|
-
constructor(args) {
|
|
269
|
-
super("instance-not-found", `Workflow instance ${args.instanceId} not found${args.detail ? ` (${args.detail})` : ""}`),
|
|
270
|
-
this.name = "InstanceNotFoundError", this.instanceId = args.instanceId;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
class DefinitionNotFoundError extends WorkflowError {
|
|
275
|
-
definition;
|
|
276
|
-
version;
|
|
277
|
-
constructor(args) {
|
|
278
|
-
super("definition-not-found", args.version !== void 0 ? `Workflow definition ${args.definition} v${args.version} not deployed` : `Workflow definition ${args.definition} has no deployed versions`),
|
|
279
|
-
this.name = "DefinitionNotFoundError", this.definition = args.definition, args.version !== void 0 && (this.version = args.version);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
class DefinitionInUseError extends WorkflowError {
|
|
284
|
-
definition;
|
|
285
|
-
blockedBy;
|
|
286
|
-
constructor(args) {
|
|
287
|
-
super("definition-in-use", definitionInUseMessage(args.definition, args.blockedBy)),
|
|
288
|
-
this.name = "DefinitionInUseError", this.definition = args.definition, this.blockedBy = args.blockedBy;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function definitionInUseMessage(definition, blockedBy) {
|
|
293
|
-
if (blockedBy.reason === "non-terminal-instances") {
|
|
294
|
-
const head = blockedBy.instanceIds.slice(0, 3).join(", "), preview = blockedBy.instanceIds.length > 3 ? `${head}, …` : head;
|
|
295
|
-
return `Cannot delete ${definition}: ${blockedBy.instanceIds.length} non-terminal instance(s) exist (${preview}). Pass cascade to abort them first — instances are aborted in place, never deleted.`;
|
|
296
|
-
}
|
|
297
|
-
const names = blockedBy.referrers.map(r => `${r.definition} v${r.version}`).join(", ");
|
|
298
|
-
return `Cannot delete ${definition}: still spawn-referenced by deployed definition(s) ${names}. Delete or redeploy the referrer(s) first.`;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
class EffectNotFoundError extends WorkflowError {
|
|
302
|
-
instanceId;
|
|
303
|
-
effectKey;
|
|
304
|
-
settled;
|
|
305
|
-
constructor(args) {
|
|
306
|
-
super("effect-not-found", effectNotFoundMessage(args)), this.name = "EffectNotFoundError",
|
|
307
|
-
this.instanceId = args.instanceId, this.effectKey = args.effectKey, args.settled !== void 0 && (this.settled = args.settled);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function effectNotFoundMessage(args) {
|
|
312
|
-
const base = `Pending effect "${args.effectKey}" not found on instance ${args.instanceId}`;
|
|
313
|
-
if (args.settled === void 0) return base;
|
|
314
|
-
const cause = args.settled.detail !== void 0 ? ` (${args.settled.detail})` : "";
|
|
315
|
-
return args.settled.status === "cancelled" ? `${base} — it was cancelled at ${args.settled.ranAt}${cause}` : `${base} — it already settled "${args.settled.status}" at ${args.settled.ranAt}${cause}`;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
528
|
const LAKE_ID_SEGMENT_RE = /^[a-z0-9][a-z0-9-]*$/, LAKE_ID_SEGMENT_GLOSS = "ASCII lowercase + digits + dashes, no leading dash, no dots";
|
|
319
529
|
|
|
320
530
|
function validateTag(tag) {
|
|
@@ -354,6 +564,7 @@ const isValidTag = asPredicate(validateTag), isValidAliasName = asPredicate(vali
|
|
|
354
564
|
resource: WorkflowResourceSchema
|
|
355
565
|
}), DefinitionSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.name == "string", "expected a workflow definition (an object with a string `name`)"), DeploymentSchema = v__namespace.object({
|
|
356
566
|
name: NonEmptyString$1,
|
|
567
|
+
expectedMinReaderModel: v__namespace.optional(v__namespace.custom(() => !0), void 0),
|
|
357
568
|
tag: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty(), v__namespace.check(isValidTag, "invalid tag — lowercase letters, digits and dashes only, no leading dash, no dots")),
|
|
358
569
|
workflowResource: WorkflowResourceSchema,
|
|
359
570
|
resourceAliases: v__namespace.optional(v__namespace.pipe(v__namespace.array(ResourceBindingSchema), v__namespace.check(bindings => new Set(bindings.map(binding => binding.name)).size === bindings.length, "duplicate resource handle name — each binding name must be unique within a deployment"))),
|
|
@@ -596,6 +807,8 @@ function desugarFieldEntry({entry: entry, path: path, ctx: ctx}) {
|
|
|
596
807
|
required: entry.required,
|
|
597
808
|
initialValue: entry.initialValue,
|
|
598
809
|
editable: editable,
|
|
810
|
+
options: entry.options,
|
|
811
|
+
validation: entry.validation,
|
|
599
812
|
types: entry.types,
|
|
600
813
|
fields: entry.fields,
|
|
601
814
|
of: entry.of
|
|
@@ -738,7 +951,7 @@ function desugarActivity({activity: activity, path: path, stageEnv: stageEnv, ct
|
|
|
738
951
|
};
|
|
739
952
|
}
|
|
740
953
|
|
|
741
|
-
const TARGET_DOC_KINDS = [ "doc.ref", "doc.refs", "release.ref" ];
|
|
954
|
+
const TARGET_DOC_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref" ];
|
|
742
955
|
|
|
743
956
|
function desugarTarget({target: target, env: env, path: path, ctx: ctx}) {
|
|
744
957
|
if (target === void 0 || target.type === "url") return target;
|
|
@@ -759,18 +972,15 @@ function desugarTarget({target: target, env: env, path: path, ctx: ctx}) {
|
|
|
759
972
|
};
|
|
760
973
|
}
|
|
761
974
|
|
|
762
|
-
function
|
|
763
|
-
|
|
764
|
-
action: action,
|
|
765
|
-
path: path,
|
|
766
|
-
env: env,
|
|
767
|
-
ctx: ctx
|
|
768
|
-
});
|
|
769
|
-
action.roles !== void 0 && action.roles.length === 0 && ctx.issues.push({
|
|
975
|
+
function reportEmptyActionRoles({action: action, path: path, ctx: ctx}) {
|
|
976
|
+
action.roles === void 0 || action.roles.length > 0 || ctx.issues.push({
|
|
770
977
|
path: [ ...path, "roles" ],
|
|
771
978
|
message: "roles: [] names no roles — omit it to allow any identity, or list at least one role"
|
|
772
979
|
});
|
|
773
|
-
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function desugarActionOps(args) {
|
|
983
|
+
const {action: action, path: path, env: env, activityName: activityName, ctx: ctx} = args, ops = desugarOps({
|
|
774
984
|
ops: action.ops,
|
|
775
985
|
path: [ ...path, "ops" ],
|
|
776
986
|
env: env,
|
|
@@ -781,9 +991,32 @@ function desugarAction({action: action, path: path, env: env, activityName: acti
|
|
|
781
991
|
type: "status.set",
|
|
782
992
|
activity: activityName,
|
|
783
993
|
status: action.status
|
|
784
|
-
}),
|
|
994
|
+
}), ops;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function desugarAction({action: action, path: path, env: env, activityName: activityName, ctx: ctx}) {
|
|
998
|
+
if ("type" in action) return desugarClaimAction({
|
|
999
|
+
action: action,
|
|
1000
|
+
path: path,
|
|
1001
|
+
env: env,
|
|
1002
|
+
ctx: ctx
|
|
1003
|
+
});
|
|
1004
|
+
reportEmptyActionRoles({
|
|
1005
|
+
action: action,
|
|
1006
|
+
path: path,
|
|
1007
|
+
ctx: ctx
|
|
1008
|
+
});
|
|
1009
|
+
const cascadeFired = isCascadeFired(action), filter = cascadeFired ? action.filter : andConditions([ rolesCondition(action.roles, ctx.roleAliases), action.filter ]), ops = desugarActionOps({
|
|
1010
|
+
action: action,
|
|
1011
|
+
path: path,
|
|
1012
|
+
env: env,
|
|
1013
|
+
activityName: activityName,
|
|
1014
|
+
ctx: ctx
|
|
1015
|
+
});
|
|
1016
|
+
return {
|
|
785
1017
|
...stripUndefined({
|
|
786
1018
|
name: action.name,
|
|
1019
|
+
semantics: action.semantics,
|
|
787
1020
|
title: action.title,
|
|
788
1021
|
description: action.description,
|
|
789
1022
|
group: normalizeGroup(action.group),
|
|
@@ -1170,7 +1403,7 @@ function isTerminalActivityStatus(status) {
|
|
|
1170
1403
|
return TERMINAL_ACTIVITY_STATUSES.includes(status);
|
|
1171
1404
|
}
|
|
1172
1405
|
|
|
1173
|
-
const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISSIONS = [ "create", "read", "update" ], MUTATION_GUARD_ACTIONS = [ "create", "update", "delete", "publish", "unpublish" ], ACTIVITY_KINDS = [ "user", "service", "script", "manual", "receive" ], EXECUTOR_CLASSIFICATIONS = [ "autonomous", "interactive", "off-system", "hybrid" ], GROUP_KINDS = [ "core", "details" ], DRIVER_KINDS = [ "person", "agent", "service", "engine" ], CONDITION_VARS = [ {
|
|
1406
|
+
const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISSIONS = [ "create", "read", "update" ], MUTATION_GUARD_ACTIONS = [ "create", "update", "delete", "publish", "unpublish" ], ACTIVITY_KINDS = [ "user", "service", "script", "manual", "receive" ], EXECUTOR_CLASSIFICATIONS = [ "autonomous", "interactive", "off-system", "hybrid" ], GROUP_KINDS = [ "core", "details" ], DRIVER_KINDS = [ "person", "agent", "service", "engine" ], CONDITION_VARS = [ {
|
|
1174
1407
|
name: "self",
|
|
1175
1408
|
binding: "always",
|
|
1176
1409
|
label: "this workflow instance",
|
|
@@ -1179,7 +1412,7 @@ const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISS
|
|
|
1179
1412
|
name: "fields",
|
|
1180
1413
|
binding: "always",
|
|
1181
1414
|
label: "the workflow's fields",
|
|
1182
|
-
description: "Declared field entries rendered by name (`$fields.<name>` is the value, no wrapper). Stage/activity scopes overlay lexically. What a read puts in your hand follows the declared kind: a singular `doc.ref` DEREFERENCES into the hydrated document (lake `_id`/`_type` plus content fields — which may themselves be named `id`/`type`), while `doc.refs` elements and `release.ref` stay REFERENCES — `{id, type[, releaseName]}` with `id` a GDR URI — because identity reads (membership, counting, joins) must stay total without hydrating every target, and targets may live in resources the evaluation cannot fetch from. Conditions evaluate against the in-memory snapshot only, so a dereferencing plural kind would silently hole wherever hydration lagged."
|
|
1415
|
+
description: "Declared field entries rendered by name (`$fields.<name>` is the value, no wrapper). Stage/activity scopes overlay lexically. What a read puts in your hand follows the declared kind: a singular `doc.ref` (or `subject`) DEREFERENCES into the hydrated document (lake `_id`/`_type` plus content fields — which may themselves be named `id`/`type`), while `doc.refs` elements and `release.ref` stay REFERENCES — `{id, type[, releaseName]}` with `id` a GDR URI — because identity reads (membership, counting, joins) must stay total without hydrating every target, and targets may live in resources the evaluation cannot fetch from. Conditions evaluate against the in-memory snapshot only, so a dereferencing plural kind would silently hole wherever hydration lagged."
|
|
1183
1416
|
}, {
|
|
1184
1417
|
name: "parent",
|
|
1185
1418
|
binding: "always",
|
|
@@ -1260,18 +1493,26 @@ const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISS
|
|
|
1260
1493
|
binding: "always",
|
|
1261
1494
|
label: "the spawned subworkflows",
|
|
1262
1495
|
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`."
|
|
1263
|
-
} ], 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 = [ {
|
|
1496
|
+
} ], SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR = "subjectHasInFlightInstance", RESERVED_CONDITION_VARS = [ ...CONDITION_VARS.map(v2 => v2.name), SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR ], 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 = [ {
|
|
1264
1497
|
name: "tag",
|
|
1498
|
+
label: "this engine tag",
|
|
1265
1499
|
description: "The engine's tag partition — scope `*[...]` instance scans with `tag == $tag`."
|
|
1266
1500
|
}, {
|
|
1267
1501
|
name: "definition",
|
|
1502
|
+
label: "this workflow definition",
|
|
1268
1503
|
description: "The `name` of the definition under evaluation (its own start block binds it)."
|
|
1269
1504
|
}, {
|
|
1270
1505
|
name: "now",
|
|
1506
|
+
label: "the current time",
|
|
1271
1507
|
description: "The ISO clock reading of the evaluating engine."
|
|
1508
|
+
}, {
|
|
1509
|
+
name: SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR,
|
|
1510
|
+
label: "the subject already has an in-flight workflow",
|
|
1511
|
+
description: "Whether any instance in this engine tag, across all definitions, has the same resource-qualified subject and no `completedAt`. Advisory under concurrent starts."
|
|
1272
1512
|
} ], START_ALLOWED_VARS = [ ...START_FILTER_VARS, {
|
|
1273
1513
|
name: "fields",
|
|
1274
|
-
|
|
1514
|
+
label: "the start's input fields",
|
|
1515
|
+
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."
|
|
1275
1516
|
} ], GUARD_PREDICATE_VARS = [ {
|
|
1276
1517
|
name: "guard",
|
|
1277
1518
|
description: "The guard document itself (its `metadata` carries deploy-time resolved values)."
|
|
@@ -1421,6 +1662,18 @@ function releaseRef({res: res, releaseName: releaseName}) {
|
|
|
1421
1662
|
};
|
|
1422
1663
|
}
|
|
1423
1664
|
|
|
1665
|
+
function isSingleDocRefKind(kind) {
|
|
1666
|
+
return kind === "doc.ref" || kind === "subject";
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
function refKindAcceptsTypes(kind) {
|
|
1670
|
+
return isSingleDocRefKind(kind) || kind === "doc.refs";
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
function isSingleDocRefEntry(entry) {
|
|
1674
|
+
return isSingleDocRefKind(entry._type);
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1424
1677
|
function isTodoListItem(row) {
|
|
1425
1678
|
if (typeof row != "object" || row === null) return !1;
|
|
1426
1679
|
const candidate = row, status = candidate.status;
|
|
@@ -1471,9 +1724,34 @@ const GdrUriSchema = v__namespace.custom(s => typeof s == "string" && isGdrUri(s
|
|
|
1471
1724
|
}), tolerantObject()({
|
|
1472
1725
|
type: v__namespace.literal("role"),
|
|
1473
1726
|
role: NonEmptyString
|
|
1474
|
-
}) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString,
|
|
1727
|
+
}) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "datetime", "dateTime" ]);
|
|
1728
|
+
|
|
1729
|
+
function normalizedChoiceKind(kind) {
|
|
1730
|
+
return kind === "dateTime" ? "datetime" : kind;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
function checkChoiceList(args) {
|
|
1734
|
+
const {entryType: entryType, options: options, validation: validation} = args;
|
|
1735
|
+
if (options === void 0) return;
|
|
1736
|
+
if (!CHOICE_KINDS.has(entryType)) return [ `\`options\` is not valid on "${entryType}" values` ];
|
|
1737
|
+
const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => checkValueAgainst({
|
|
1738
|
+
entryType: kind,
|
|
1739
|
+
value: option.value,
|
|
1740
|
+
validation: validation
|
|
1741
|
+
}, valueSchemas)?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
|
|
1742
|
+
for (const option of options.list) seen.has(option.value) && issues.push(`duplicate option value ${JSON.stringify(option.value)}`),
|
|
1743
|
+
seen.add(option.value);
|
|
1744
|
+
return issues.length === 0 ? void 0 : issues;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
function choiceValueIssues(options, value) {
|
|
1748
|
+
if (!(options === void 0 || value === null || value === void 0)) return options.list.some(option => Object.is(option.value, value)) ? void 0 : [ `value ${JSON.stringify(value)} is not declared in \`options.list\`; expected one of ${options.list.map(option => JSON.stringify(option.value)).join(", ")}` ];
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
const fieldValueSchemas = {
|
|
1475
1752
|
"doc.ref": v__namespace.union([ v__namespace.null(), GdrShape ]),
|
|
1476
1753
|
"doc.refs": v__namespace.array(GdrShape),
|
|
1754
|
+
subject: v__namespace.union([ v__namespace.null(), GdrShape ]),
|
|
1477
1755
|
"release.ref": v__namespace.union([ v__namespace.null(), ReleaseRefShape ]),
|
|
1478
1756
|
string: NullableString,
|
|
1479
1757
|
text: NullableString,
|
|
@@ -1491,7 +1769,56 @@ const GdrUriSchema = v__namespace.custom(s => typeof s == "string" && isGdrUri(s
|
|
|
1491
1769
|
};
|
|
1492
1770
|
|
|
1493
1771
|
function shapeValueSchema(shape, leaf) {
|
|
1494
|
-
|
|
1772
|
+
if (shape.type === "object") return objectSchema(shape.fields ?? [], leaf);
|
|
1773
|
+
if (shape.type === "array") return v__namespace.array(objectSchema(shape.of ?? [], leaf));
|
|
1774
|
+
const schema = leaf[shape.type] ?? v__namespace.any();
|
|
1775
|
+
return constrainedScalarSchema({
|
|
1776
|
+
schema: schema,
|
|
1777
|
+
entryType: shape.type,
|
|
1778
|
+
...shape
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
function scalarMeasurement(entryType, value) {
|
|
1783
|
+
if (entryType === "number" && typeof value == "number") return value;
|
|
1784
|
+
if ((entryType === "string" || entryType === "text") && typeof value == "string") return value.length;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
function scalarBoundIssue(args) {
|
|
1788
|
+
const {entryType: entryType, measured: measured, bound: bound, limit: limit} = args;
|
|
1789
|
+
return bound === void 0 || limit === "min" && measured >= bound || limit === "max" && measured <= bound ? void 0 : `${entryType === "number" ? "" : "length "}must be ${limit === "min" ? "greater than or equal to" : "less than or equal to"} ${bound}`;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
function scalarValidationIssues(args) {
|
|
1793
|
+
const {entryType: entryType, validation: validation, value: value} = args;
|
|
1794
|
+
if (validation === void 0 || value === null || value === void 0) return;
|
|
1795
|
+
const measured = scalarMeasurement(entryType, value);
|
|
1796
|
+
if (measured === void 0) return;
|
|
1797
|
+
const issues = [ scalarBoundIssue({
|
|
1798
|
+
entryType: entryType,
|
|
1799
|
+
measured: measured,
|
|
1800
|
+
bound: validation.min,
|
|
1801
|
+
limit: "min"
|
|
1802
|
+
}), scalarBoundIssue({
|
|
1803
|
+
entryType: entryType,
|
|
1804
|
+
measured: measured,
|
|
1805
|
+
bound: validation.max,
|
|
1806
|
+
limit: "max"
|
|
1807
|
+
}) ].filter(issue => issue !== void 0);
|
|
1808
|
+
return issues.length === 0 ? void 0 : issues;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
function constrainedScalarSchema(args) {
|
|
1812
|
+
const {schema: schema, entryType: entryType, options: options, validation: validation} = args;
|
|
1813
|
+
return options === void 0 && validation === void 0 ? schema : v__namespace.pipe(schema, v__namespace.check(value => choiceValueIssues(options, value) === void 0 && scalarValidationIssues({
|
|
1814
|
+
entryType: entryType,
|
|
1815
|
+
validation: validation,
|
|
1816
|
+
value: value
|
|
1817
|
+
}) === void 0, issue => [ ...choiceValueIssues(options, issue.input) ?? [], ...scalarValidationIssues({
|
|
1818
|
+
entryType: entryType,
|
|
1819
|
+
validation: validation,
|
|
1820
|
+
value: issue.input
|
|
1821
|
+
}) ?? [] ].join("; ")));
|
|
1495
1822
|
}
|
|
1496
1823
|
|
|
1497
1824
|
function objectSchema(fields, leaf) {
|
|
@@ -1514,7 +1841,7 @@ function appendItemSchema(entryType, shape) {
|
|
|
1514
1841
|
function rejectedRefTypes(args) {
|
|
1515
1842
|
const {entryType: entryType, types: types, value: value} = args;
|
|
1516
1843
|
if (types === void 0 || value === null || value === void 0) return [];
|
|
1517
|
-
if (entryType
|
|
1844
|
+
if (!refKindAcceptsTypes(entryType)) return [];
|
|
1518
1845
|
let items = [ value ];
|
|
1519
1846
|
return entryType === "doc.refs" && (items = Array.isArray(value) ? value : []),
|
|
1520
1847
|
[ ...new Set(items.map(gdrTypeOf).filter(t => t !== void 0 && !types.includes(t))) ];
|
|
@@ -1549,6 +1876,10 @@ function checkValueAgainst(args, leaf) {
|
|
|
1549
1876
|
entryType: args.entryType,
|
|
1550
1877
|
types: args.types,
|
|
1551
1878
|
value: args.value
|
|
1879
|
+
}) ?? choiceValueIssues(args.options, args.value) ?? scalarValidationIssues({
|
|
1880
|
+
entryType: args.entryType,
|
|
1881
|
+
validation: args.validation,
|
|
1882
|
+
value: args.value
|
|
1552
1883
|
}) : formatIssues(result.issues);
|
|
1553
1884
|
}
|
|
1554
1885
|
|
|
@@ -1579,6 +1910,7 @@ const AuthoringRefId = v__namespace.pipe(v__namespace.string(), v__namespace.che
|
|
|
1579
1910
|
...valueSchemas,
|
|
1580
1911
|
"doc.ref": v__namespace.union([ v__namespace.null(), AuthoringGdrShape ]),
|
|
1581
1912
|
"doc.refs": v__namespace.array(AuthoringGdrShape),
|
|
1913
|
+
subject: v__namespace.union([ v__namespace.null(), AuthoringGdrShape ]),
|
|
1582
1914
|
"release.ref": v__namespace.union([ v__namespace.null(), v__namespace.looseObject({
|
|
1583
1915
|
id: AuthoringRefId,
|
|
1584
1916
|
type: v__namespace.literal("system.release"),
|
|
@@ -1618,10 +1950,10 @@ function validateFieldAppendItem(args) {
|
|
|
1618
1950
|
});
|
|
1619
1951
|
}
|
|
1620
1952
|
|
|
1621
|
-
function formatIssues(issues) {
|
|
1953
|
+
function formatIssues(issues, formatMessage = issue => issue.message) {
|
|
1622
1954
|
return issues.map(i => {
|
|
1623
1955
|
const keys = i.path?.map(p => p.key) ?? [];
|
|
1624
|
-
return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${i
|
|
1956
|
+
return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(i)}`;
|
|
1625
1957
|
});
|
|
1626
1958
|
}
|
|
1627
1959
|
|
|
@@ -1747,7 +2079,15 @@ function groupMembershipNames(group) {
|
|
|
1747
2079
|
return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
|
|
1748
2080
|
}
|
|
1749
2081
|
|
|
1750
|
-
const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "release.ref", "string", "text", "number", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), FieldEntryName = groqIdentifier("`$fields.<name>`")
|
|
2082
|
+
const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "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({
|
|
2083
|
+
min: v__namespace.optional(FiniteNumber),
|
|
2084
|
+
max: v__namespace.optional(FiniteNumber)
|
|
2085
|
+
}), 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({
|
|
2086
|
+
list: v__namespace.pipe(v__namespace.array(v__namespace.strictObject({
|
|
2087
|
+
title: NonEmpty,
|
|
2088
|
+
value: v__namespace.union([ v__namespace.string(), v__namespace.number() ])
|
|
2089
|
+
})), v__namespace.minLength(1, "declare at least one choice, or omit `options`"))
|
|
2090
|
+
});
|
|
1751
2091
|
|
|
1752
2092
|
function asShape(input) {
|
|
1753
2093
|
return typeof input == "object" && input !== null ? input : {};
|
|
@@ -1781,14 +2121,16 @@ function compositeChecked(entries) {
|
|
|
1781
2121
|
return v__namespace.pipe(v__namespace.strictObject(entries), v__namespace.check(input => compositeShapeOk(input), issue => compositeShapeMessage(issue.input)), v__namespace.check(input => duplicateSubfieldName(input) === void 0, issue => `duplicate sub-field name "${duplicateSubfieldName(issue.input)}" — sub-field names must be unique within \`fields\` / \`of\``));
|
|
1782
2122
|
}
|
|
1783
2123
|
|
|
1784
|
-
const FieldShapeSchema = v__namespace.lazy(() => compositeChecked({
|
|
2124
|
+
const FieldShapeSchema = v__namespace.lazy(() => v__namespace.pipe(compositeChecked({
|
|
1785
2125
|
type: FieldValueKindSchema,
|
|
1786
2126
|
name: FieldEntryName,
|
|
1787
2127
|
title: v__namespace.optional(v__namespace.string()),
|
|
1788
2128
|
description: v__namespace.optional(v__namespace.string()),
|
|
2129
|
+
options: v__namespace.optional(ChoiceOptionsSchema),
|
|
2130
|
+
validation: v__namespace.optional(ScalarValidationSchema),
|
|
1789
2131
|
fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
|
|
1790
2132
|
of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
|
|
1791
|
-
})), StoredEditableSchema = v__namespace.union([ v__namespace.literal(!0), NonEmpty ]), AuthoringEditableSchema = v__namespace.union([ v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty ]);
|
|
2133
|
+
}), choiceOptionsCheck(), scalarValidationCheck())), StoredEditableSchema = v__namespace.union([ v__namespace.literal(!0), NonEmpty ]), AuthoringEditableSchema = v__namespace.union([ v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty ]);
|
|
1792
2134
|
|
|
1793
2135
|
function fieldBase(editable, group) {
|
|
1794
2136
|
return {
|
|
@@ -1806,6 +2148,8 @@ function fieldEntryFields(editable, group) {
|
|
|
1806
2148
|
return {
|
|
1807
2149
|
type: FieldKindSchema,
|
|
1808
2150
|
...fieldBase(editable, group),
|
|
2151
|
+
options: v__namespace.optional(ChoiceOptionsSchema),
|
|
2152
|
+
validation: v__namespace.optional(ScalarValidationSchema),
|
|
1809
2153
|
types: v__namespace.optional(v__namespace.pipe(v__namespace.array(NonEmpty), v__namespace.minLength(1, "declare at least one accepted type, or omit `types` to accept any"))),
|
|
1810
2154
|
fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
|
|
1811
2155
|
of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
|
|
@@ -1818,7 +2162,9 @@ function literalSeedIssues(entry) {
|
|
|
1818
2162
|
value: entry.initialValue.value,
|
|
1819
2163
|
types: entry.types,
|
|
1820
2164
|
fields: entry.fields,
|
|
1821
|
-
of: entry.of
|
|
2165
|
+
of: entry.of,
|
|
2166
|
+
options: entry.options,
|
|
2167
|
+
validation: entry.validation
|
|
1822
2168
|
});
|
|
1823
2169
|
}
|
|
1824
2170
|
|
|
@@ -1827,10 +2173,37 @@ function literalSeedCheck() {
|
|
|
1827
2173
|
}
|
|
1828
2174
|
|
|
1829
2175
|
function refTypesCheck() {
|
|
1830
|
-
return v__namespace.check(entry => entry.types === void 0 || entry.type
|
|
2176
|
+
return v__namespace.check(entry => entry.types === void 0 || refKindAcceptsTypes(entry.type), issue => `\`types\` is only valid on \`doc.ref\` / \`doc.refs\` / \`subject\` entries, not "${issue.input.type}"`);
|
|
1831
2177
|
}
|
|
1832
2178
|
|
|
1833
|
-
|
|
2179
|
+
function choiceOptionsCheck() {
|
|
2180
|
+
return v__namespace.check(entry => checkChoiceList({
|
|
2181
|
+
entryType: entry.type,
|
|
2182
|
+
options: entry.options,
|
|
2183
|
+
validation: entry.validation
|
|
2184
|
+
}) === void 0, issue => (checkChoiceList({
|
|
2185
|
+
entryType: issue.input.type,
|
|
2186
|
+
options: issue.input.options,
|
|
2187
|
+
validation: issue.input.validation
|
|
2188
|
+
}) ?? []).join("; "));
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
const SCALAR_VALIDATION_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number" ]);
|
|
2192
|
+
|
|
2193
|
+
function scalarValidationCheck() {
|
|
2194
|
+
return v__namespace.check(entry => scalarValidationDeclarationIssues(entry) === void 0, issue => (scalarValidationDeclarationIssues(issue.input) ?? []).join("; "));
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
function scalarValidationDeclarationIssues(entry) {
|
|
2198
|
+
const {type: type, validation: validation} = entry;
|
|
2199
|
+
if (validation === void 0) return;
|
|
2200
|
+
if (!SCALAR_VALIDATION_KINDS.has(type)) return [ `\`validation\` is only valid on \`string\` / \`text\` / \`number\` values, not "${type}"` ];
|
|
2201
|
+
if (type === "number") return;
|
|
2202
|
+
const issues = Object.entries(validation).flatMap(([bound, value]) => Number.isInteger(value) && value >= 0 ? [] : [ `\`validation.${bound}\` must be a non-negative integer for ${type} length` ]);
|
|
2203
|
+
return issues.length === 0 ? void 0 : issues;
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(StoredEditableSchema, StoredGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(AuthoringEditableSchema, AuthoringGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v__namespace.strictObject({
|
|
1834
2207
|
type: v__namespace.literal("claim"),
|
|
1835
2208
|
name: FieldEntryName,
|
|
1836
2209
|
title: v__namespace.optional(v__namespace.string()),
|
|
@@ -1861,17 +2234,25 @@ const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("
|
|
|
1861
2234
|
with: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
|
|
1862
2235
|
context: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
|
|
1863
2236
|
onExit: v__namespace.optional(picklist([ "detach", "abort" ]))
|
|
1864
|
-
}), ActionParamSchema = v__namespace.strictObject({
|
|
2237
|
+
}), ActionParamSchema = v__namespace.pipe(v__namespace.strictObject({
|
|
1865
2238
|
type: picklist([ "string", "number", "boolean", "url", "dateTime", "actor", "doc.ref", "doc.refs", "json" ]),
|
|
1866
2239
|
name: NonEmpty,
|
|
1867
2240
|
title: v__namespace.optional(v__namespace.string()),
|
|
1868
2241
|
description: v__namespace.optional(v__namespace.string()),
|
|
1869
|
-
required: v__namespace.optional(v__namespace.boolean())
|
|
1870
|
-
|
|
2242
|
+
required: v__namespace.optional(v__namespace.boolean()),
|
|
2243
|
+
options: v__namespace.optional(ChoiceOptionsSchema),
|
|
2244
|
+
validation: v__namespace.optional(ScalarValidationSchema)
|
|
2245
|
+
}), choiceOptionsCheck(), scalarValidationCheck());
|
|
2246
|
+
|
|
2247
|
+
function hasUniqueSemanticNamespaces(semantics) {
|
|
2248
|
+
const namespaces = semantics.map(semantic => semantic.split(".", 1)[0]);
|
|
2249
|
+
return new Set(namespaces).size === namespaces.length;
|
|
2250
|
+
}
|
|
1871
2251
|
|
|
1872
2252
|
function actionFields(op, group) {
|
|
1873
2253
|
return {
|
|
1874
2254
|
name: NonEmpty,
|
|
2255
|
+
semantics: v__namespace.optional(v__namespace.pipe(v__namespace.array(picklist(ACTION_SEMANTICS)), v__namespace.minLength(1, "declare at least one semantic, or omit `semantics`"), v__namespace.check(hasUniqueSemanticNamespaces, "declare at most one semantic from each namespace"))),
|
|
1875
2256
|
title: v__namespace.optional(v__namespace.string()),
|
|
1876
2257
|
description: v__namespace.optional(v__namespace.string()),
|
|
1877
2258
|
group: v__namespace.optional(group),
|
|
@@ -2060,7 +2441,7 @@ function startKindOf(definition) {
|
|
|
2060
2441
|
}
|
|
2061
2442
|
|
|
2062
2443
|
function isSubjectEntry(entry) {
|
|
2063
|
-
return entry.
|
|
2444
|
+
return entry.type === "subject";
|
|
2064
2445
|
}
|
|
2065
2446
|
|
|
2066
2447
|
function isInputSourced(entry) {
|
|
@@ -2562,6 +2943,52 @@ function checkAssigneesEntries(def, issues) {
|
|
|
2562
2943
|
});
|
|
2563
2944
|
}
|
|
2564
2945
|
|
|
2946
|
+
function nestedSubjectPaths(shapes, base) {
|
|
2947
|
+
return (shapes ?? []).flatMap((shape, i) => isSubjectEntry(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedSubjectPaths(shape.fields, [ ...base, i, "fields" ]), ...nestedSubjectPaths(shape.of, [ ...base, i, "of" ]) ]);
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
function checkSubjectEffectOutputs(def, issues) {
|
|
2951
|
+
for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushSubjectOutputIssues({
|
|
2952
|
+
action: action,
|
|
2953
|
+
path: [ "stages", i, "activities", j, "actions", a ],
|
|
2954
|
+
issues: issues
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
function pushSubjectOutputIssues(args) {
|
|
2959
|
+
const {action: action, path: path, issues: issues} = args;
|
|
2960
|
+
for (const [e, effect] of (action.effects ?? []).entries()) {
|
|
2961
|
+
const base = [ ...path, "effects", e, "outputs" ];
|
|
2962
|
+
for (const nestedPath of nestedSubjectPaths(effect.outputs, base)) issues.push({
|
|
2963
|
+
path: nestedPath,
|
|
2964
|
+
message: `effect "${effect.name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
function checkSubjectEntries(def, issues) {
|
|
2970
|
+
for (const {entries: entries, scope: scope, path: path, label: label} of fieldScopes(def)) {
|
|
2971
|
+
const subjects = (entries ?? []).flatMap((entry, n) => isSubjectEntry(entry) ? [ {
|
|
2972
|
+
entry: entry,
|
|
2973
|
+
n: n
|
|
2974
|
+
} ] : []);
|
|
2975
|
+
if (scope !== "workflow") for (const {entry: entry, n: n} of subjects) issues.push({
|
|
2976
|
+
path: [ ...path, n, "type" ],
|
|
2977
|
+
message: `${label} entry "${entry.name}" is a \`subject\` — the subject names the document the WORKFLOW is about, so it is valid only on a workflow-scope entry. Declare \`doc.ref\` for a plain reference here`
|
|
2978
|
+
}); else for (const {n: n} of subjects.slice(1)) issues.push({
|
|
2979
|
+
path: [ ...path, n ],
|
|
2980
|
+
message: "at most one subject-kind field entry per workflow — the runtime identifies THE subject by kind, and a second one makes it ambiguous"
|
|
2981
|
+
});
|
|
2982
|
+
for (const [n, entry] of (entries ?? []).entries()) {
|
|
2983
|
+
const nested = [ ...nestedSubjectPaths(entry.fields, [ ...path, n, "fields" ]), ...nestedSubjectPaths(entry.of, [ ...path, n, "of" ]) ];
|
|
2984
|
+
for (const nestedPath of nested) issues.push({
|
|
2985
|
+
path: nestedPath,
|
|
2986
|
+
message: `${label} entry "${entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2565
2992
|
function checkActivityTerminalPaths(def, issues) {
|
|
2566
2993
|
for (const [i, stage] of def.stages.entries()) {
|
|
2567
2994
|
const resolvable = terminallyResolvableActivities(stage);
|
|
@@ -2612,12 +3039,30 @@ function checkStart(def, issues) {
|
|
|
2612
3039
|
if (def.start !== void 0 && (def.lifecycle === "child" && issues.push({
|
|
2613
3040
|
path: [ "start" ],
|
|
2614
3041
|
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'`"
|
|
2615
|
-
}), checkStartFilterReads(def, issues), checkStartAllowedReads(def, issues), def
|
|
3042
|
+
}), checkStartFilterReads(def, issues), checkStartAllowedReads(def, issues), checkStartSubjectVariable(def, issues),
|
|
3043
|
+
def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
|
|
2616
3044
|
path: [ "fields", n, "required" ],
|
|
2617
|
-
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
|
|
3045
|
+
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)`
|
|
2618
3046
|
});
|
|
2619
3047
|
}
|
|
2620
3048
|
|
|
3049
|
+
function checkStartSubjectVariable(def, issues) {
|
|
3050
|
+
const subject = (def.fields ?? []).find(isSubjectEntry);
|
|
3051
|
+
for (const [key, condition] of [ [ "filter", def.start?.filter ], [ "allowed", def.start?.allowed ] ]) if (condition !== void 0 && conditionParameterNames(condition).has(SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR)) {
|
|
3052
|
+
if (subject === void 0) {
|
|
3053
|
+
issues.push({
|
|
3054
|
+
path: [ "start", key ],
|
|
3055
|
+
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`
|
|
3056
|
+
});
|
|
3057
|
+
continue;
|
|
3058
|
+
}
|
|
3059
|
+
key === "allowed" && !isInputSourced(subject) && issues.push({
|
|
3060
|
+
path: [ "start", key ],
|
|
3061
|
+
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`
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
|
|
2621
3066
|
function checkStartFilterReads(def, issues) {
|
|
2622
3067
|
const filter = def.start?.filter;
|
|
2623
3068
|
filter !== void 0 && (conditionParameterNames(filter).has("fields") && issues.push({
|
|
@@ -2625,7 +3070,7 @@ function checkStartFilterReads(def, issues) {
|
|
|
2625
3070
|
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.allowed, the start-time permission predicate that binds $fields and is enforced by startInstance"
|
|
2626
3071
|
}), readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
|
|
2627
3072
|
path: [ "start", "filter" ],
|
|
2628
|
-
message: "start.filter reads the candidate document (its root), but the definition declares no
|
|
3073
|
+
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"
|
|
2629
3074
|
}));
|
|
2630
3075
|
}
|
|
2631
3076
|
|
|
@@ -2942,7 +3387,7 @@ function checkFieldReadOpValues(def, issues) {
|
|
|
2942
3387
|
ops: site.ops,
|
|
2943
3388
|
path: site.path,
|
|
2944
3389
|
label: site.label,
|
|
2945
|
-
activityEntries:
|
|
3390
|
+
activityEntries: site.activity.fields ?? []
|
|
2946
3391
|
});
|
|
2947
3392
|
}
|
|
2948
3393
|
|
|
@@ -2964,6 +3409,9 @@ function fieldReadsIn(value, path) {
|
|
|
2964
3409
|
|
|
2965
3410
|
function checkOpFieldRead({read: read, where: where, path: path, workflowEntries: workflowEntries, stageEntries: stageEntries, activityEntries: activityEntries, issues: issues}) {
|
|
2966
3411
|
const hosts = [ {
|
|
3412
|
+
scope: "activity",
|
|
3413
|
+
entries: activityEntries
|
|
3414
|
+
}, {
|
|
2967
3415
|
scope: "stage",
|
|
2968
3416
|
entries: stageEntries
|
|
2969
3417
|
}, {
|
|
@@ -2976,8 +3424,7 @@ function checkOpFieldRead({read: read, where: where, path: path, workflowEntries
|
|
|
2976
3424
|
message: opFieldReadMissMessage({
|
|
2977
3425
|
read: read,
|
|
2978
3426
|
where: where,
|
|
2979
|
-
hosts: hosts
|
|
2980
|
-
activityEntries: activityEntries
|
|
3427
|
+
hosts: hosts
|
|
2981
3428
|
})
|
|
2982
3429
|
});
|
|
2983
3430
|
return;
|
|
@@ -2991,9 +3438,9 @@ function checkOpFieldRead({read: read, where: where, path: path, workflowEntries
|
|
|
2991
3438
|
});
|
|
2992
3439
|
}
|
|
2993
3440
|
|
|
2994
|
-
function opFieldReadMissMessage({read: read, where: where, hosts: hosts
|
|
2995
|
-
const searched = read.scope === void 0 ? "stage or workflow scope" : `${read.scope} scope`,
|
|
2996
|
-
return `${where} reads field "${read.field}", which is not declared at ${searched} — the read resolves to undefined at op time, so the write silently lands empty
|
|
3441
|
+
function opFieldReadMissMessage({read: read, where: where, hosts: hosts}) {
|
|
3442
|
+
const searched = read.scope === void 0 ? "activity, stage, or workflow scope" : `${read.scope} scope`, known = hosts.flatMap(host => host.entries.map(entry => `${host.scope}:${entry.name}`));
|
|
3443
|
+
return `${where} reads field "${read.field}", which is not declared at ${searched} — the read resolves to undefined at op time, so the write silently lands empty. Known: ${known.join(", ") || "(none)"}`;
|
|
2997
3444
|
}
|
|
2998
3445
|
|
|
2999
3446
|
function checkUpdateWhereOps(def, issues) {
|
|
@@ -3156,6 +3603,7 @@ const SCALAR = {
|
|
|
3156
3603
|
kind: "list",
|
|
3157
3604
|
item: GDR_VALUE
|
|
3158
3605
|
}),
|
|
3606
|
+
subject: () => DOC_CONTENT,
|
|
3159
3607
|
"release.ref": () => RELEASE_VALUE,
|
|
3160
3608
|
string: () => SCALAR,
|
|
3161
3609
|
text: () => SCALAR,
|
|
@@ -3180,7 +3628,8 @@ const SCALAR = {
|
|
|
3180
3628
|
})
|
|
3181
3629
|
}, START_ALLOWED_VALUE_NODES = {
|
|
3182
3630
|
...VALUE_NODES,
|
|
3183
|
-
"doc.ref": () => GDR_VALUE
|
|
3631
|
+
"doc.ref": () => GDR_VALUE,
|
|
3632
|
+
subject: () => GDR_VALUE
|
|
3184
3633
|
};
|
|
3185
3634
|
|
|
3186
3635
|
function valueNodeFor(shape, nodes) {
|
|
@@ -3252,11 +3701,14 @@ function checkWorkflowInvariants(def) {
|
|
|
3252
3701
|
checkRequiredField(def, issues), checkStart(def, issues), checkPredicates(def, issues),
|
|
3253
3702
|
checkUnboundConditionVars(def, issues), checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues),
|
|
3254
3703
|
checkFieldReadOpValues(def, issues), checkUpdateWhereOps(def, issues), checkGuardFieldReads(def, issues),
|
|
3255
|
-
checkAssigneesEntries(def, issues),
|
|
3704
|
+
checkAssigneesEntries(def, issues), checkSubjectEntries(def, issues), checkSubjectEffectOutputs(def, issues),
|
|
3705
|
+
checkActivityTerminalPaths(def, issues), checkTerminalStageActivities(def, issues),
|
|
3256
3706
|
checkTriggeredActionParams(def, issues), checkStoredRolesPlacement(def, issues),
|
|
3257
3707
|
checkGroups(def, issues), issues;
|
|
3258
3708
|
}
|
|
3259
3709
|
|
|
3710
|
+
exports.ACTION_SEMANTICS = ACTION_SEMANTICS;
|
|
3711
|
+
|
|
3260
3712
|
exports.ACTIVITY_KINDS = ACTIVITY_KINDS;
|
|
3261
3713
|
|
|
3262
3714
|
exports.ACTIVITY_STATUSES = ACTIVITY_STATUSES;
|
|
@@ -3287,6 +3739,12 @@ exports.CONDITION_VARS = CONDITION_VARS;
|
|
|
3287
3739
|
|
|
3288
3740
|
exports.ContractViolationError = ContractViolationError;
|
|
3289
3741
|
|
|
3742
|
+
exports.DATA_MODEL_CHANGES = DATA_MODEL_CHANGES;
|
|
3743
|
+
|
|
3744
|
+
exports.DATA_MODEL_MIN_READER = DATA_MODEL_MIN_READER;
|
|
3745
|
+
|
|
3746
|
+
exports.DATA_MODEL_VERSION = DATA_MODEL_VERSION;
|
|
3747
|
+
|
|
3290
3748
|
exports.DEFAULT_TRANSITION_WHEN = DEFAULT_TRANSITION_WHEN;
|
|
3291
3749
|
|
|
3292
3750
|
exports.DOCUMENT_VALUE_PERMISSIONS = DOCUMENT_VALUE_PERMISSIONS;
|
|
@@ -3329,22 +3787,34 @@ exports.IsoTimestamp = IsoTimestamp;
|
|
|
3329
3787
|
|
|
3330
3788
|
exports.MUTATION_GUARD_ACTIONS = MUTATION_GUARD_ACTIONS;
|
|
3331
3789
|
|
|
3790
|
+
exports.ModelVersionAheadError = ModelVersionAheadError;
|
|
3791
|
+
|
|
3332
3792
|
exports.NonEmptyString = NonEmptyString;
|
|
3333
3793
|
|
|
3334
3794
|
exports.PersistedDocShapeError = PersistedDocShapeError;
|
|
3335
3795
|
|
|
3796
|
+
exports.READER_MODEL_ROLLOUT_URL = READER_MODEL_ROLLOUT_URL;
|
|
3797
|
+
|
|
3336
3798
|
exports.RESERVED_CONDITION_VARS = RESERVED_CONDITION_VARS;
|
|
3337
3799
|
|
|
3338
3800
|
exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
|
|
3339
3801
|
|
|
3802
|
+
exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
|
|
3803
|
+
|
|
3340
3804
|
exports.START_ALLOWED_VARS = START_ALLOWED_VARS;
|
|
3341
3805
|
|
|
3342
3806
|
exports.START_FILTER_VARS = START_FILTER_VARS;
|
|
3343
3807
|
|
|
3808
|
+
exports.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR = SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR;
|
|
3809
|
+
|
|
3810
|
+
exports.SpawnContractsInvalidError = SpawnContractsInvalidError;
|
|
3811
|
+
|
|
3344
3812
|
exports.StoredFieldOpSchema = StoredFieldOpSchema;
|
|
3345
3813
|
|
|
3346
3814
|
exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
|
|
3347
3815
|
|
|
3816
|
+
exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
|
|
3817
|
+
|
|
3348
3818
|
exports.WorkflowConfigSchema = WorkflowConfigSchema;
|
|
3349
3819
|
|
|
3350
3820
|
exports.WorkflowError = WorkflowError;
|
|
@@ -3353,10 +3823,16 @@ exports.actorFulfillsRole = actorFulfillsRole;
|
|
|
3353
3823
|
|
|
3354
3824
|
exports.andConditions = andConditions;
|
|
3355
3825
|
|
|
3826
|
+
exports.assertReadableModel = assertReadableModel;
|
|
3827
|
+
|
|
3828
|
+
exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
|
|
3829
|
+
|
|
3356
3830
|
exports.checkFieldValue = checkFieldValue;
|
|
3357
3831
|
|
|
3358
3832
|
exports.checkWorkflowInvariants = checkWorkflowInvariants;
|
|
3359
3833
|
|
|
3834
|
+
exports.choiceValueIssues = choiceValueIssues;
|
|
3835
|
+
|
|
3360
3836
|
exports.clientConfigFromResource = clientConfigFromResource;
|
|
3361
3837
|
|
|
3362
3838
|
exports.conditionEffectReads = conditionEffectReads;
|
|
@@ -3389,6 +3865,8 @@ exports.evaluatePredicates = evaluatePredicates;
|
|
|
3389
3865
|
|
|
3390
3866
|
exports.extractDocumentId = extractDocumentId;
|
|
3391
3867
|
|
|
3868
|
+
exports.fieldTreeShape = fieldTreeShape;
|
|
3869
|
+
|
|
3392
3870
|
exports.fieldValueSchemas = fieldValueSchemas;
|
|
3393
3871
|
|
|
3394
3872
|
exports.formatIssuePath = formatIssuePath;
|
|
@@ -3425,6 +3903,10 @@ exports.isNotesEntry = isNotesEntry;
|
|
|
3425
3903
|
|
|
3426
3904
|
exports.isParseableInstant = isParseableInstant;
|
|
3427
3905
|
|
|
3906
|
+
exports.isSingleDocRefEntry = isSingleDocRefEntry;
|
|
3907
|
+
|
|
3908
|
+
exports.isSingleDocRefKind = isSingleDocRefKind;
|
|
3909
|
+
|
|
3428
3910
|
exports.isStartableDefinition = isStartableDefinition;
|
|
3429
3911
|
|
|
3430
3912
|
exports.isSubjectEntry = isSubjectEntry;
|
|
@@ -3437,8 +3919,20 @@ exports.isTodoListItem = isTodoListItem;
|
|
|
3437
3919
|
|
|
3438
3920
|
exports.isUnevaluable = isUnevaluable;
|
|
3439
3921
|
|
|
3922
|
+
exports.isUnprimed = isUnprimed;
|
|
3923
|
+
|
|
3440
3924
|
exports.labelFor = labelFor;
|
|
3441
3925
|
|
|
3926
|
+
exports.minReaderModelOf = minReaderModelOf;
|
|
3927
|
+
|
|
3928
|
+
exports.modelStampFor = modelStampFor;
|
|
3929
|
+
|
|
3930
|
+
exports.modelVersionOf = modelVersionOf;
|
|
3931
|
+
|
|
3932
|
+
exports.parentRef = parentRef;
|
|
3933
|
+
|
|
3934
|
+
exports.parseDefinitionSnapshot = parseDefinitionSnapshot;
|
|
3935
|
+
|
|
3442
3936
|
exports.parseGdr = parseGdr;
|
|
3443
3937
|
|
|
3444
3938
|
exports.parseOrThrow = parseOrThrow;
|
|
@@ -3457,6 +3951,8 @@ exports.refDashboard = refDashboard;
|
|
|
3457
3951
|
|
|
3458
3952
|
exports.refDataset = refDataset;
|
|
3459
3953
|
|
|
3954
|
+
exports.refKindAcceptsTypes = refKindAcceptsTypes;
|
|
3955
|
+
|
|
3460
3956
|
exports.refMediaLibrary = refMediaLibrary;
|
|
3461
3957
|
|
|
3462
3958
|
exports.refTypeIssues = refTypeIssues;
|
|
@@ -3467,6 +3963,10 @@ exports.releaseDocId = releaseDocId;
|
|
|
3467
3963
|
|
|
3468
3964
|
exports.releaseRef = releaseRef;
|
|
3469
3965
|
|
|
3966
|
+
exports.requiredModelFeatures = requiredModelFeatures;
|
|
3967
|
+
|
|
3968
|
+
exports.requiredReaderModel = requiredReaderModel;
|
|
3969
|
+
|
|
3470
3970
|
exports.resourceAliasesToMap = resourceAliasesToMap;
|
|
3471
3971
|
|
|
3472
3972
|
exports.resourceFromGdrUri = resourceFromGdrUri;
|
|
@@ -3481,6 +3981,8 @@ exports.runGroq = runGroq;
|
|
|
3481
3981
|
|
|
3482
3982
|
exports.sameResource = sameResource;
|
|
3483
3983
|
|
|
3984
|
+
exports.scalarValidationIssues = scalarValidationIssues;
|
|
3985
|
+
|
|
3484
3986
|
exports.schemaTreeShape = schemaTreeShape;
|
|
3485
3987
|
|
|
3486
3988
|
exports.selfGdr = selfGdr;
|
|
@@ -3489,6 +3991,8 @@ exports.startKindOf = startKindOf;
|
|
|
3489
3991
|
|
|
3490
3992
|
exports.tagScopeFilter = tagScopeFilter;
|
|
3491
3993
|
|
|
3994
|
+
exports.terminalState = terminalState;
|
|
3995
|
+
|
|
3492
3996
|
exports.toBareId = toBareId;
|
|
3493
3997
|
|
|
3494
3998
|
exports.toPhysicalGdr = toPhysicalGdr;
|