@sanity/workflow-engine 0.14.0 → 0.16.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/dist/define.cjs CHANGED
@@ -1,979 +1,141 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var v = require("valibot"), schema = require("./_chunks-cjs/schema.cjs");
4
- function _interopNamespaceCompat(e) {
5
- if (e && typeof e == "object" && "default" in e) return e;
6
- var n = /* @__PURE__ */ Object.create(null);
7
- return e && Object.keys(e).forEach(function(k) {
8
- if (k !== "default") {
9
- var d = Object.getOwnPropertyDescriptor(e, k);
10
- Object.defineProperty(n, k, d.get ? d : {
11
- enumerable: !0,
12
- get: function() {
13
- return e[k];
14
- }
15
- });
16
- }
17
- }), n.default = e, Object.freeze(n);
18
- }
19
- var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
20
- function groq(strings, ...values) {
21
- return strings.reduce((out, part, i) => i === 0 ? part : `${out}${serializeGroqValue(values[i - 1])}${part}`, "");
22
- }
23
- function serializeGroqValue(value) {
24
- const serialized = JSON.stringify(value);
25
- if (serialized === void 0)
26
- throw new Error(
27
- `groq tag cannot serialize ${typeof value} \u2014 interpolate JSON-representable values only`
28
- );
29
- return serialized;
30
- }
31
- function desugarWorkflow(authoring) {
32
- const issues = [];
33
- checkReservedRoleAliasKeys(authoring.roleAliases, issues);
34
- const roleAliases = schema.normalizeRoleAliases(authoring.roleAliases), ctx = {
35
- issues,
36
- claimFields: /* @__PURE__ */ new Map(),
37
- claimedFields: /* @__PURE__ */ new Set(),
38
- roleAliases
39
- }, workflowFields = desugarFieldEntries({ entries: authoring.fields, path: ["fields"], ctx }), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
40
- const path = ["stages", i], stageFields = desugarFieldEntries({ entries: stage.fields, path: [...path, "fields"], ctx }), stageEnv = {
41
- layers: [
42
- { scope: "stage", entries: layerOf(stageFields) },
43
- { scope: "workflow", entries: workflowLayer }
44
- ]
45
- }, activities = (stage.activities ?? []).map(
46
- (activity, j) => desugarActivity({ activity, path: [...path, "activities", j], stageEnv, ctx })
47
- ), transitions = (stage.transitions ?? []).map(
48
- (transition, k) => desugarTransition({ transition, path: [...path, "transitions", k], stageEnv, ctx })
49
- ), editable = desugarStageEditable({
50
- overrides: stage.editable,
51
- inScope: editableFieldNames({ workflowFields, stageFields, activities }),
52
- path: [...path, "editable"],
53
- ctx
54
- });
55
- return {
56
- ...stripUndefined({
57
- name: stage.name,
58
- title: stage.title,
59
- description: stage.description,
60
- guards: stage.guards?.map(desugarGuard)
61
- }),
62
- ...stageFields ? { fields: stageFields } : {},
63
- ...activities.length > 0 ? { activities } : {},
64
- ...transitions.length > 0 ? { transitions } : {},
65
- ...editable ? { editable } : {}
66
- };
67
- });
68
- return checkUnclaimedClaimFields(ctx), { definition: {
69
- ...stripUndefined({
70
- name: authoring.name,
71
- title: authoring.title,
72
- description: authoring.description,
73
- lifecycle: authoring.lifecycle,
74
- initialStage: authoring.initialStage,
75
- predicates: authoring.predicates,
76
- roleAliases
77
- }),
78
- ...workflowFields ? { fields: workflowFields } : {},
79
- stages
80
- }, issues: ctx.issues };
81
- }
82
- function checkReservedRoleAliasKeys(aliases, issues) {
83
- for (const key of Object.keys(aliases ?? {}))
84
- key.startsWith("$") && issues.push({
85
- path: ["roleAliases", key],
86
- message: `role alias key "${key}" uses the reserved "$" prefix \u2014 that namespace is the engine's stored spelling for the universal fulfiller. Use "*" to mean "fulfills any gate", or rename the role.`
87
- });
88
- }
89
- const TODOLIST_OF = [
90
- { type: "string", name: "label", title: "Label" },
91
- { type: "string", name: "status", title: "Status" },
92
- { type: "assignee", name: "assignee", title: "Assignee" },
93
- { type: "date", name: "dueDate", title: "Due date" }
94
- ], NOTES_OF = [
95
- { type: "text", name: "body", title: "Body" },
96
- { type: "actor", name: "actor", title: "Actor" },
97
- { type: "datetime", name: "at", title: "At" }
98
- ];
99
- function desugarFieldEntries({
100
- entries,
101
- path,
102
- ctx
103
- }) {
104
- return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => desugarFieldEntry({ entry, path: [...path, i], ctx }));
105
- }
106
- function desugarFieldEntry({
107
- entry,
108
- path,
109
- ctx
110
- }) {
111
- if (entry.type === "claim") return desugarClaimField({ entry, path, ctx });
112
- if (entry.type === "todoList" || entry.type === "notes")
113
- return desugarListField({ entry, path, ctx });
114
- const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
115
- return {
116
- ...stripUndefined({
117
- type: entry.type,
118
- name: entry.name,
119
- title: entry.title,
120
- description: entry.description,
121
- required: entry.required,
122
- initialValue: entry.initialValue,
123
- editable,
124
- fields: entry.fields,
125
- of: entry.of
126
- })
127
- };
128
- }
129
- function desugarClaimField({
130
- entry,
131
- path,
132
- ctx
133
- }) {
134
- const desugared = {
135
- ...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
136
- type: "actor"
137
- };
138
- return ctx.claimFields.set(desugared, { name: entry.name, path }), desugared;
139
- }
140
- function desugarListField({
141
- entry,
142
- path,
143
- ctx
144
- }) {
145
- const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
146
- return {
147
- ...stripUndefined({
148
- name: entry.name,
149
- title: entry.title,
150
- description: entry.description,
151
- required: entry.required,
152
- initialValue: entry.initialValue,
153
- editable
154
- }),
155
- type: "array",
156
- of: entry.type === "todoList" ? TODOLIST_OF : NOTES_OF
157
- };
158
- }
159
- function normalizeEditable({
160
- editable,
161
- path,
162
- ctx
163
- }) {
164
- if (editable === void 0 || editable === !0) return editable;
165
- if (Array.isArray(editable)) {
166
- const condition = rolesCondition(editable, ctx.roleAliases);
167
- if (condition === void 0) {
168
- ctx.issues.push({
169
- path,
170
- message: "editable: [] names no roles \u2014 use `true` to open the field to anyone in its scope, or list at least one role"
171
- });
172
- return;
173
- }
174
- return condition;
175
- }
176
- return editable;
177
- }
178
- function editableFieldNames({
179
- workflowFields,
180
- stageFields,
181
- activities
182
- }) {
183
- const names = /* @__PURE__ */ new Set(), collect = (entries) => {
184
- for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
185
- };
186
- collect(workflowFields), collect(stageFields);
187
- for (const activity of activities) collect(activity.fields);
188
- return names;
189
- }
190
- function desugarStageEditable({
191
- overrides,
192
- inScope,
193
- path,
194
- ctx
195
- }) {
196
- if (overrides === void 0) return;
197
- const out = {};
198
- for (const [name, value] of Object.entries(overrides)) {
199
- if (!inScope.has(name)) {
200
- ctx.issues.push({
201
- path: [...path, name],
202
- message: `stage editable override "${name}" does not narrow an editable field in scope \u2014 name a workflow/stage/activity field of this stage that declares \`editable\``
203
- });
204
- continue;
205
- }
206
- const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
207
- normalized !== void 0 && (out[name] = normalized);
208
- }
209
- return Object.keys(out).length > 0 ? out : void 0;
210
- }
211
- function layerOf(entries) {
212
- return new Map((entries ?? []).map((entry) => [entry.name, entry]));
213
- }
214
- function desugarActivity({
215
- activity,
216
- path,
217
- stageEnv,
218
- ctx
219
- }) {
220
- const activityFields = desugarFieldEntries({
221
- entries: activity.fields,
222
- path: [...path, "fields"],
223
- ctx
224
- }), env = {
225
- layers: [{ scope: "activity", entries: layerOf(activityFields) }, ...stageEnv.layers]
226
- }, ops = desugarOps({
227
- ops: activity.ops,
228
- path: [...path, "ops"],
229
- env,
230
- firingActivity: activity.name,
231
- ctx
232
- }), actions = (activity.actions ?? []).map(
233
- (action, a) => desugarAction({ action, path: [...path, "actions", a], env, activityName: activity.name, ctx })
234
- ), target = desugarTarget({ target: activity.target, env, path: [...path, "target"], ctx });
235
- return {
236
- ...stripUndefined({
237
- name: activity.name,
238
- title: activity.title,
239
- description: activity.description,
240
- kind: activity.kind,
241
- filter: activity.filter,
242
- requirements: activity.requirements,
243
- completeWhen: activity.completeWhen,
244
- failWhen: activity.failWhen,
245
- effects: activity.effects,
246
- subworkflows: activity.subworkflows
247
- }),
248
- activation: activity.activation ?? "manual",
249
- ...target ? { target } : {},
250
- ...activityFields ? { fields: activityFields } : {},
251
- ...ops ? { ops } : {},
252
- ...actions.length > 0 ? { actions } : {}
253
- };
254
- }
255
- const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
256
- function desugarTarget({
257
- target,
258
- env,
259
- path,
260
- ctx
261
- }) {
262
- if (target === void 0 || target.type === "url") return target;
263
- const ref = typeof target.field == "string" ? { field: target.field } : target.field, field = resolveRef({ ref, env, path: [...path, "field"], ctx }) ?? fallbackRef(ref), entry = entryAt(env, field);
264
- return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
265
- path: [...path, "field"],
266
- message: `manual activity target references "${field.field}" of kind "${entry.type}" \u2014 a deep-link target needs a document-valued entry (${TARGET_DOC_KINDS.join(", ")})`
267
- }), { type: "field", field };
268
- }
269
- function desugarAction({
270
- action,
271
- path,
272
- env,
273
- activityName,
274
- ctx
275
- }) {
276
- if ("type" in action)
277
- return desugarClaimAction({ action, path, env, ctx });
278
- const filter = schema.andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps({ ops: action.ops, path: [...path, "ops"], env, firingActivity: activityName, ctx }) ?? [];
279
- return action.status !== void 0 && ops.push({ type: "status.set", activity: activityName, status: action.status }), {
280
- ...stripUndefined({
281
- name: action.name,
282
- title: action.title,
283
- description: action.description,
284
- params: action.params,
285
- effects: action.effects
286
- }),
287
- ...filter ? { filter } : {},
288
- ...ops.length > 0 ? { ops } : {}
289
- };
290
- }
291
- function desugarClaimAction({
292
- action,
293
- path,
294
- env,
295
- ctx
296
- }) {
297
- const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef({ ref, env, path: [...path, "field"], ctx });
298
- if (resolved) {
299
- const entry = entryAt(env, resolved);
300
- entry && entry.type !== "actor" && ctx.issues.push({
301
- path: [...path, "field"],
302
- message: `claim action "${action.name}" references "${resolved.field}" of kind "${entry.type}" \u2014 a claim pair needs an actor-valued entry (a "claim" or "actor" field declaration)`
303
- }), checkShadowedClaimTarget({
304
- actionName: action.name,
305
- field: ref.field,
306
- resolved,
307
- env,
308
- path: [...path, "field"],
309
- ctx
310
- }), entry && ctx.claimedFields.add(entry);
311
- }
312
- const noSteal = `!defined($fields.${ref.field})`, filter = schema.andConditions([
313
- noSteal,
314
- rolesCondition(action.roles, ctx.roleAliases),
315
- action.filter
316
- ]), ops = resolved ? [{ type: "field.set", target: resolved, value: { type: "actor" } }] : [];
317
- return {
318
- ...stripUndefined({
319
- name: action.name,
320
- title: action.title,
321
- description: action.description,
322
- params: action.params,
323
- effects: action.effects
324
- }),
325
- filter,
326
- ...ops.length > 0 ? { ops } : {}
327
- };
328
- }
329
- function checkShadowedClaimTarget({
330
- actionName,
331
- field,
332
- resolved,
333
- env,
334
- path,
335
- ctx
336
- }) {
337
- const nearest = env.layers.find((l) => l.entries.has(field));
338
- nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
339
- path,
340
- message: `claim action "${actionName}" targets "${field}" at scope "${resolved.scope}", but a nearer ${nearest.scope}-scope entry of the same name shadows it in $fields \u2014 the no-steal filter would read the shadowing entry while the claim writes the "${resolved.scope}" one. Rename one of the entries or claim the nearer one`
341
- });
342
- }
343
- function checkUnclaimedClaimFields(ctx) {
344
- for (const [entry, { name, path }] of ctx.claimFields)
345
- ctx.claimedFields.has(entry) || ctx.issues.push({
346
- path,
347
- message: `claim field "${name}" is never referenced by a claim action \u2014 you announced the pattern and wrote half of it. Declare a defineAction({ type: "claim", field: "${name}" }) or use a raw actor entry`
348
- });
349
- }
350
- function desugarTransition({
351
- transition,
352
- path,
353
- stageEnv,
354
- ctx
355
- }) {
356
- const ops = desugarOps({
357
- ops: transition.ops,
358
- path: [...path, "ops"],
359
- env: stageEnv,
360
- firingActivity: void 0,
361
- ctx
362
- });
363
- return {
364
- ...stripUndefined({
365
- name: transition.name,
366
- title: transition.title,
367
- description: transition.description,
368
- to: transition.to,
369
- effects: transition.effects
370
- }),
371
- filter: transition.filter ?? "$allActivitiesDone",
372
- ...ops ? { ops } : {}
373
- };
374
- }
375
- function desugarGuard(guard) {
376
- const { match, metadata, ...rest } = guard, { idRefs, ...matchRest } = match;
377
- return {
378
- ...rest,
379
- match: {
380
- ...matchRest,
381
- ...idRefs !== void 0 ? { idRefs: idRefs.map(schema.printGuardRead) } : {}
382
- },
383
- ...metadata !== void 0 ? {
384
- metadata: Object.fromEntries(
385
- Object.entries(metadata).map(([key, read]) => [key, schema.printGuardRead(read)])
386
- )
387
- } : {}
388
- };
389
- }
390
- function desugarOps({
391
- ops,
392
- path,
393
- env,
394
- firingActivity,
395
- ctx
396
- }) {
397
- if (ops)
398
- return ops.map((op, i) => desugarOp({ op, path: [...path, i], env, firingActivity, ctx }));
399
- }
400
- function desugarOp({
401
- op,
402
- path,
403
- env,
404
- firingActivity,
405
- ctx
406
- }) {
407
- if (op.type === "status.set") {
408
- const activity = op.activity ?? firingActivity;
409
- return activity === void 0 && ctx.issues.push({
410
- path: [...path, "activity"],
411
- message: "status.set outside an action must name its target activity"
412
- }), { type: "status.set", activity: activity ?? "", status: op.status };
413
- }
414
- if (op.type === "audit") return desugarAuditOp({ op, path, env, ctx });
415
- const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
416
- return { ...op, target };
417
- }
418
- const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
419
- function desugarAuditOp({
420
- op,
421
- path,
422
- env,
423
- ctx
424
- }) {
425
- const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
426
- if (op.value.type !== "object")
427
- return ctx.issues.push({
428
- path: [...path, "value"],
429
- message: `audit value must be an object source carrying the domain fields (got "${op.value.type}")`
430
- }), { type: "field.append", target, value: op.value };
431
- const actorField = op.stampFields?.actor ?? "actor", atField = op.stampFields?.at ?? "at", fields = { ...op.value.fields };
432
- for (const [stamp, source] of [
433
- [actorField, AUDIT_STAMPS.actor],
434
- [atField, AUDIT_STAMPS.at]
435
- ]) {
436
- if (stamp in fields) {
437
- ctx.issues.push({
438
- path: [...path, "value", "fields", stamp],
439
- message: `audit stamp field "${stamp}" collides with an authored domain field \u2014 rename yours or remap the stamp via stampFields`
440
- });
441
- continue;
442
- }
443
- fields[stamp] = source;
444
- }
445
- return { type: "field.append", target, value: { type: "object", fields } };
446
- }
447
- function resolveRef({
448
- ref,
449
- env,
450
- path,
451
- ctx
452
- }) {
453
- const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
454
- for (const layer of layers)
455
- if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
456
- const reachable = env.layers.flatMap((l) => [...l.entries.keys()].map((n) => `${l.scope}:${n}`));
457
- ctx.issues.push({
458
- path,
459
- message: `field reference "${ref.field}"${ref.scope ? ` (scope "${ref.scope}")` : ""} does not resolve to a declared entry. Reachable: ${reachable.join(", ") || "(none)"}`
460
- });
461
- }
462
- function entryAt(env, ref) {
463
- return env.layers.find((l) => l.scope === ref.scope)?.entries.get(ref.field);
464
- }
465
- function fallbackRef(ref) {
466
- return { scope: ref.scope ?? "workflow", field: ref.field };
467
- }
468
- function rolesCondition(roles, aliases) {
469
- if (!(!roles || roles.length === 0))
470
- return groq`count($actor.roles[@ in ${schema.expandRequiredRoles(roles, aliases)}]) > 0`;
471
- }
472
- function stripUndefined(obj) {
473
- const out = {};
474
- for (const [k, value] of Object.entries(obj))
475
- value !== void 0 && (out[k] = value);
476
- return out;
477
- }
478
- const PREDICATE_CALLER_VARS = schema.CONDITION_VARS.filter((v2) => v2.binding === "caller").map(
479
- (v2) => v2.name
480
- );
481
- function knownList(ids) {
482
- return [...ids].map((s) => `"${s}"`).join(", ");
483
- }
484
- function checkDuplicates({
485
- names,
486
- what,
487
- issues
488
- }) {
489
- const seen = /* @__PURE__ */ new Set();
490
- for (const { name, path } of names)
491
- seen.has(name) && issues.push({ path, message: `duplicate ${what} "${name}" (already declared earlier)` }), seen.add(name);
492
- return seen;
493
- }
494
- function checkStages(def, issues) {
495
- const stageNames = checkDuplicates({
496
- names: def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
497
- what: "stage name",
498
- issues
499
- });
500
- for (const [i, stage] of def.stages.entries()) {
501
- const activityNames = checkDuplicates({
502
- names: (stage.activities ?? []).map((activity, j) => ({
503
- name: activity.name,
504
- path: ["stages", i, "activities", j, "name"]
505
- })),
506
- what: `activity name in stage "${stage.name}"`,
507
- issues
508
- });
509
- checkDuplicates({
510
- names: (stage.transitions ?? []).map((t, k) => ({
511
- name: t.name,
512
- path: ["stages", i, "transitions", k, "name"]
513
- })),
514
- what: `transition name in stage "${stage.name}"`,
515
- issues
516
- }), checkActivities({ def, i, activityNames, issues });
517
- }
518
- return stageNames;
519
- }
520
- function checkActivities({
521
- def,
522
- i,
523
- activityNames,
524
- issues
525
- }) {
526
- const stage = def.stages[i];
527
- for (const [j, activity] of (stage.activities ?? []).entries()) {
528
- const path = ["stages", i, "activities", j];
529
- checkDuplicates({
530
- names: (activity.actions ?? []).map((action, a) => ({
531
- name: action.name,
532
- path: [...path, "actions", a, "name"]
533
- })),
534
- what: `action name in activity "${activity.name}"`,
535
- issues
536
- }), checkStatusSetTargets({ activity, activityNames, path, issues });
537
- }
538
- }
539
- function checkStatusSetTargets({
540
- activity,
541
- activityNames,
542
- path,
543
- issues
544
- }) {
545
- checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
546
- for (const [a, action] of (activity.actions ?? []).entries())
547
- checkStatusSetOps({
548
- ops: action.ops,
549
- activityNames,
550
- path: [...path, "actions", a, "ops"],
551
- issues
552
- });
553
- }
554
- function checkStatusSetOps({
555
- ops,
556
- activityNames,
557
- path,
558
- issues
559
- }) {
560
- for (const [o, op] of (ops ?? []).entries())
561
- op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
562
- path: [...path, o, "activity"],
563
- message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
564
- });
565
- }
566
- function checkInitialStage({
567
- def,
568
- stageNames,
569
- issues
570
- }) {
571
- stageNames.has(def.initialStage) || issues.push({
572
- path: ["initialStage"],
573
- message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
574
- });
575
- }
576
- function checkTransitionTargets({
577
- def,
578
- stageNames,
579
- issues
580
- }) {
581
- for (const [i, stage] of def.stages.entries())
582
- for (const [k, t] of (stage.transitions ?? []).entries())
583
- stageNames.has(t.to) || issues.push({
584
- path: ["stages", i, "transitions", k, "to"],
585
- message: `transition target "${t.to}" is not a declared stage. Known stages: ${knownList(stageNames)}`
586
- });
587
- }
588
- function checkEffectNames(def, issues) {
589
- const sites = [];
590
- for (const [i, stage] of def.stages.entries()) {
591
- for (const [j, activity] of (stage.activities ?? []).entries()) {
592
- collectEffects({
593
- effects: activity.effects,
594
- path: ["stages", i, "activities", j, "effects"],
595
- sites
596
- });
597
- for (const [a, action] of (activity.actions ?? []).entries())
598
- collectEffects({
599
- effects: action.effects,
600
- path: ["stages", i, "activities", j, "actions", a, "effects"],
601
- sites
602
- });
603
- }
604
- for (const [k, t] of (stage.transitions ?? []).entries())
605
- collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
606
- }
607
- checkDuplicates({
608
- names: sites,
609
- what: "effect name (registry key \u2014 unique per definition)",
610
- issues
611
- });
612
- }
613
- function collectEffects({
614
- effects,
615
- path,
616
- sites
617
- }) {
618
- for (const [e, effect] of (effects ?? []).entries())
619
- sites.push({ name: effect.name, path: [...path, e, "name"] });
620
- }
621
- function checkGuardNames(def, issues) {
622
- const sites = def.stages.flatMap(
623
- (stage, i) => (stage.guards ?? []).map((guard, g) => ({
624
- name: guard.name,
625
- path: ["stages", i, "guards", g, "name"]
626
- }))
627
- );
628
- checkDuplicates({
629
- names: sites,
630
- what: "guard name (the guard lake _id derives from it \u2014 unique per definition)",
631
- issues
632
- });
633
- }
634
- function fieldScopes(def) {
635
- const scopes = [
636
- { entries: def.fields, scope: "workflow", path: ["fields"], label: "workflow fields" }
637
- ];
638
- for (const [i, stage] of def.stages.entries()) {
639
- scopes.push({
640
- entries: stage.fields,
641
- scope: "stage",
642
- path: ["stages", i, "fields"],
643
- label: `stage "${stage.name}" fields`
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: !0
5
+ });
6
+
7
+ var invariants = require("./_chunks-cjs/invariants.cjs");
8
+
9
+ function defineWorkflow(definition) {
10
+ const label = invariants.labelFor("defineWorkflow", definition), parsed = invariants.parseOrThrow({
11
+ schema: invariants.AuthoringWorkflowSchema,
12
+ input: definition,
13
+ label: label
14
+ }), {definition: stored, issues: desugarIssues} = invariants.desugarWorkflow(parsed), issues = [ ...desugarIssues, ...invariants.checkWorkflowInvariants(stored) ];
15
+ if (issues.length > 0) throw new Error(invariants.formatValidationError(label, issues));
16
+ return stored;
17
+ }
18
+
19
+ function defineWorkflowConfig(config) {
20
+ return invariants.parseOrThrow({
21
+ schema: invariants.WorkflowConfigSchema,
22
+ input: config,
23
+ label: "defineWorkflowConfig"
644
24
  });
645
- for (const [j, activity] of (stage.activities ?? []).entries())
646
- scopes.push({
647
- entries: activity.fields,
648
- scope: "activity",
649
- path: ["stages", i, "activities", j, "fields"],
650
- label: `activity "${activity.name}" fields`
651
- });
652
- }
653
- return scopes;
654
25
  }
655
- function checkRequiredField(def, issues) {
656
- for (const { entries, scope, path, label } of fieldScopes(def))
657
- for (const [n, entry] of (entries ?? []).entries())
658
- if (entry.required === !0) {
659
- if (scope !== "workflow")
660
- issues.push({
661
- path: [...path, n, "required"],
662
- message: `${label} entry "${entry.name}" is \`required\`, but \`required\` applies only to workflow-scope \`input\` entries \u2014 only those are caller-supplied at start/spawn`
663
- });
664
- else if (entry.initialValue?.type !== "input") {
665
- const seed = entry.initialValue?.type ?? "working memory (no initialValue)";
666
- issues.push({
667
- path: [...path, n, "required"],
668
- message: `field entry "${entry.name}" has initialValue "${seed}" \u2014 \`required\` applies only to \`input\`-sourced entries (the caller fills them at start/spawn)`
669
- });
670
- }
671
- }
672
- }
673
- function checkFieldEntryNames(def, issues) {
674
- for (const { entries, path, label } of fieldScopes(def))
675
- checkDuplicates({
676
- names: (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
677
- what: `field entry name in ${label}`,
678
- issues
26
+
27
+ function defineStage(stage) {
28
+ return invariants.parseOrThrow({
29
+ schema: invariants.AuthoringStageSchema,
30
+ input: stage,
31
+ label: invariants.labelFor("defineStage", stage)
679
32
  });
680
33
  }
681
- function checkPredicates(def, issues) {
682
- const reserved = new Set(schema.RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
683
- for (const name of names)
684
- reserved.has(name) && issues.push({
685
- path: ["predicates", name],
686
- message: `predicate "${name}" shadows the built-in $${name} \u2014 pick another name`
34
+
35
+ function defineActivity(activity) {
36
+ return invariants.parseOrThrow({
37
+ schema: invariants.AuthoringActivitySchema,
38
+ input: activity,
39
+ label: invariants.labelFor("defineActivity", activity)
687
40
  });
688
- for (const [name, groq2] of Object.entries(def.predicates ?? {}))
689
- checkPredicateBody({ name, groq: groq2, names, issues });
690
41
  }
691
- function checkPredicateBody({
692
- name,
693
- groq: groq2,
694
- names,
695
- issues
696
- }) {
697
- for (const caller of PREDICATE_CALLER_VARS)
698
- referencesVar(groq2, caller) && issues.push({
699
- path: ["predicates", name],
700
- message: `predicate "${name}" reads $${caller} \u2014 predicates are instance-level (pre-evaluated once, without a caller); compose caller gates at the condition site instead`
701
- });
702
- for (const other of names)
703
- other === name || !referencesVar(groq2, other) || issues.push({
704
- path: ["predicates", name],
705
- message: `predicate "${name}" references predicate $${other} \u2014 predicates may read built-in vars only (no cross-references; compose at the condition site instead)`
42
+
43
+ function defineAction(action) {
44
+ return invariants.parseOrThrow({
45
+ schema: invariants.AuthoringActionSchema,
46
+ input: action,
47
+ label: invariants.labelFor("defineAction", action)
706
48
  });
707
49
  }
708
- function referencesVar(groq2, name) {
709
- return schema.GROQ_IDENTIFIER.test(name) ? new RegExp(`\\$${name}\\b`).test(groq2) : !1;
710
- }
711
- function checkCanOutsideActionFilters(def, issues) {
712
- for (const site of nonActionFilterConditionSites(def))
713
- referencesVar(site.groq, "can") && issues.push({
714
- path: site.path,
715
- message: `${site.label} reads $can \u2014 $can (the caller's grants) is bound only when an action fires, so it may appear in action filters only`
50
+
51
+ function defineTransition(transition) {
52
+ return invariants.parseOrThrow({
53
+ schema: invariants.AuthoringTransitionSchema,
54
+ input: transition,
55
+ label: transitionLabel(transition)
716
56
  });
717
57
  }
718
- function nonActionFilterConditionSites(def) {
719
- const sites = [];
720
- for (const [i, stage] of def.stages.entries()) {
721
- for (const [k, t] of (stage.transitions ?? []).entries())
722
- sites.push({
723
- groq: t.filter,
724
- path: ["stages", i, "transitions", k, "filter"],
725
- label: `transition "${t.name}" filter`
726
- }), collectBindingSites({
727
- effects: t.effects,
728
- path: ["stages", i, "transitions", k, "effects"],
729
- label: `transition "${t.name}"`,
730
- sites
731
- }), collectOpWhereSites({
732
- ops: t.ops,
733
- path: ["stages", i, "transitions", k, "ops"],
734
- label: `transition "${t.name}"`,
735
- sites
736
- });
737
- for (const [j, activity] of (stage.activities ?? []).entries())
738
- collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
739
- }
740
- return sites;
741
- }
742
- function collectOpWhereSites({
743
- ops,
744
- path,
745
- label,
746
- sites
747
- }) {
748
- for (const [o, op] of (ops ?? []).entries())
749
- op.where !== void 0 && sites.push({
750
- groq: op.where,
751
- path: [...path, o, "where"],
752
- label: `${label} ${op.type} where`
58
+
59
+ function defineField(entry) {
60
+ return invariants.parseOrThrow({
61
+ schema: invariants.AuthoringFieldEntrySchema,
62
+ input: entry,
63
+ label: invariants.labelFor("defineField", entry)
753
64
  });
754
65
  }
755
- function collectActivityConditionSites({
756
- activity,
757
- path,
758
- sites
759
- }) {
760
- for (const field of ["filter", "completeWhen", "failWhen"]) {
761
- const groq2 = activity[field];
762
- groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `activity "${activity.name}".${field}` });
763
- }
764
- collectBindingSites({
765
- effects: activity.effects,
766
- path: [...path, "effects"],
767
- label: `activity "${activity.name}"`,
768
- sites
769
- }), collectOpWhereSites({
770
- ops: activity.ops,
771
- path: [...path, "ops"],
772
- label: `activity "${activity.name}"`,
773
- sites
774
- });
775
- for (const [a, action] of (activity.actions ?? []).entries())
776
- collectBindingSites({
777
- effects: action.effects,
778
- path: [...path, "actions", a, "effects"],
779
- label: `action "${action.name}"`,
780
- sites
781
- }), collectOpWhereSites({
782
- ops: action.ops,
783
- path: [...path, "actions", a, "ops"],
784
- label: `action "${action.name}"`,
785
- sites
66
+
67
+ function defineOp(op) {
68
+ return invariants.parseOrThrow({
69
+ schema: invariants.AuthoringOpSchema,
70
+ input: op,
71
+ label: "defineOp"
786
72
  });
787
- collectSubworkflowSites({ activity, path, sites });
788
73
  }
789
- function collectSubworkflowSites({
790
- activity,
791
- path,
792
- sites
793
- }) {
794
- const sub = activity.subworkflows;
795
- if (sub === void 0) return;
796
- const subPath = [...path, "subworkflows"];
797
- sites.push({
798
- groq: sub.forEach,
799
- path: [...subPath, "forEach"],
800
- label: `activity "${activity.name}".subworkflows.forEach`
801
- });
802
- for (const [group, record] of [
803
- ["with", sub.with],
804
- ["context", sub.context]
805
- ])
806
- for (const [key, groq2] of Object.entries(record ?? {}))
807
- sites.push({
808
- groq: groq2,
809
- path: [...subPath, group, key],
810
- label: `activity "${activity.name}".subworkflows.${group} "${key}"`
811
- });
812
- }
813
- function collectBindingSites({
814
- effects,
815
- path,
816
- label,
817
- sites
818
- }) {
819
- for (const [e, effect] of (effects ?? []).entries())
820
- for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
821
- sites.push({
822
- groq: groq2,
823
- path: [...path, e, "bindings", key],
824
- label: `${label} effect "${effect.name}" binding "${key}"`
825
- });
826
- }
827
- function checkAssigneesEntries(def, issues) {
828
- for (const { entries, path } of fieldScopes(def))
829
- (entries ?? []).filter((e) => e.type === "assignees").length <= 1 || issues.push({
830
- path,
831
- message: "at most one assignees-kind field entry per scope \u2014 the inbox reads it by kind"
74
+
75
+ function defineGroup(group) {
76
+ return invariants.parseOrThrow({
77
+ schema: invariants.GroupSchema,
78
+ input: group,
79
+ label: invariants.labelFor("defineGroup", group)
832
80
  });
833
81
  }
834
- function activityShape(activity) {
835
- return {
836
- hasActions: (activity.actions ?? []).length > 0,
837
- hasEffects: (activity.effects ?? []).length > 0,
838
- hasCompleteWhen: activity.completeWhen !== void 0,
839
- hasSubworkflows: activity.subworkflows !== void 0
840
- };
841
- }
842
- const KIND_SHAPE_RULES = {
843
- user: (s) => s.hasActions ? [] : ["needs at least one action for a person to fire"],
844
- service: (s) => s.hasEffects ? [] : ["needs at least one effect \u2014 the automated work it performs"],
845
- manual: (s) => [
846
- s.hasActions || s.hasCompleteWhen ? void 0 : "needs a way to complete \u2014 an action to acknowledge it, or a `completeWhen` predicate to verify it (otherwise it auto-resolves on activation)",
847
- s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own activity" : void 0
848
- ].filter((m) => m !== void 0),
849
- receive: (s) => [
850
- s.hasCompleteWhen || s.hasSubworkflows ? void 0 : "needs a `completeWhen` (or `subworkflows`) condition to wait on",
851
- s.hasActions ? "has no actor, so it cannot carry actions" : void 0
852
- ].filter((m) => m !== void 0),
853
- script: (s) => [
854
- s.hasActions ? "runs inline with no actor, so it cannot carry actions" : void 0,
855
- s.hasCompleteWhen ? "resolves on activation, so it cannot carry a `completeWhen` (that is a `receive`/`service` wait)" : void 0,
856
- s.hasSubworkflows ? "resolves on activation, so it cannot fan out with `subworkflows`" : void 0
857
- ].filter((m) => m !== void 0)
858
- };
859
- function checkActivityKinds(def, issues) {
860
- for (const [i, stage] of def.stages.entries())
861
- for (const [j, activity] of (stage.activities ?? []).entries()) {
862
- const path = ["stages", i, "activities", j];
863
- if (activity.target !== void 0 && activity.kind !== "manual" && issues.push({
864
- path: [...path, "target"],
865
- message: `activity "${activity.name}" has a \`target\` but is not \`kind: "manual"\` \u2014 a target is the deep-link for off-system manual work`
866
- }), activity.kind !== void 0)
867
- for (const fault of KIND_SHAPE_RULES[activity.kind](activityShape(activity)))
868
- issues.push({
869
- path: [...path, "kind"],
870
- message: `activity "${activity.name}" declares kind "${activity.kind}" but ${fault}`
871
- });
872
- }
873
- }
874
- function checkWorkflowInvariants(def) {
875
- const issues = [], stageNames = checkStages(def, issues);
876
- return checkInitialStage({ def, stageNames, issues }), checkTransitionTargets({ def, stageNames, issues }), checkEffectNames(def, issues), checkGuardNames(def, issues), checkFieldEntryNames(def, issues), checkRequiredField(def, issues), checkPredicates(def, issues), checkCanOutsideActionFilters(def, issues), checkAssigneesEntries(def, issues), checkActivityKinds(def, issues), issues;
877
- }
878
- function defineWorkflow(definition) {
879
- const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow({ schema: schema.AuthoringWorkflowSchema, input: definition, label }), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
880
- if (issues.length > 0) throw new Error(schema.formatValidationError(label, issues));
881
- return stored;
882
- }
883
- function defineWorkflowConfig(config) {
884
- return parseOrThrow({ schema: schema.WorkflowConfigSchema, input: config, label: "defineWorkflowConfig" });
885
- }
886
- function defineStage(stage) {
887
- return parseOrThrow({
888
- schema: schema.AuthoringStageSchema,
889
- input: stage,
890
- label: labelFor("defineStage", stage)
891
- });
892
- }
893
- function defineActivity(activity) {
894
- return parseOrThrow({
895
- schema: schema.AuthoringActivitySchema,
896
- input: activity,
897
- label: labelFor("defineActivity", activity)
898
- });
899
- }
900
- function defineAction(action) {
901
- return parseOrThrow({
902
- schema: schema.AuthoringActionSchema,
903
- input: action,
904
- label: labelFor("defineAction", action)
905
- });
906
- }
907
- function defineTransition(transition) {
908
- return parseOrThrow({
909
- schema: schema.AuthoringTransitionSchema,
910
- input: transition,
911
- label: transitionLabel(transition)
912
- });
913
- }
914
- function defineField(entry) {
915
- return parseOrThrow({
916
- schema: schema.AuthoringFieldEntrySchema,
917
- input: entry,
918
- label: labelFor("defineField", entry)
919
- });
920
- }
921
- function defineOp(op) {
922
- return parseOrThrow({ schema: schema.AuthoringOpSchema, input: op, label: "defineOp" });
923
- }
82
+
924
83
  function defineGuard(guard) {
925
- return parseOrThrow({
926
- schema: schema.AuthoringGuardSchema,
927
- input: guard,
928
- label: labelFor("defineGuard", guard)
929
- });
84
+ return invariants.parseOrThrow({
85
+ schema: invariants.AuthoringGuardSchema,
86
+ input: guard,
87
+ label: invariants.labelFor("defineGuard", guard)
88
+ });
930
89
  }
90
+
931
91
  function defineEffect(effect) {
932
- return parseOrThrow({
933
- schema: schema.EffectSchema,
934
- input: effect,
935
- label: labelFor("defineEffect", effect)
936
- });
92
+ return invariants.parseOrThrow({
93
+ schema: invariants.EffectSchema,
94
+ input: effect,
95
+ label: invariants.labelFor("defineEffect", effect)
96
+ });
937
97
  }
98
+
938
99
  function transitionLabel(transition) {
939
- const { name, to } = transition;
940
- return typeof name == "string" ? `defineTransition("${name}")` : typeof to == "string" ? `defineTransition(\u2192 "${to}")` : "defineTransition";
100
+ const {name: name, to: to} = transition;
101
+ return typeof name == "string" ? `defineTransition("${name}")` : typeof to == "string" ? `defineTransition( "${to}")` : "defineTransition";
941
102
  }
103
+
942
104
  function defineEffectDescriptor(descriptor) {
943
- if (!descriptor.name) throw new Error("EffectDescriptor missing name");
944
- return descriptor;
945
- }
946
- function parseOrThrow({
947
- schema: schema$1,
948
- input,
949
- label
950
- }) {
951
- const result = v__namespace.safeParse(schema$1, input);
952
- if (!result.success)
953
- throw new Error(schema.formatValidationError(label, schema.issuesFromValibot(result.issues)));
954
- return result.output;
955
- }
956
- function labelFor(fn, value) {
957
- if (value && typeof value == "object" && "name" in value) {
958
- const raw = value.name;
959
- if (typeof raw == "string") return `${fn}("${raw}")`;
960
- }
961
- return fn;
962
- }
963
- exports.CONDITION_VARS = schema.CONDITION_VARS;
964
- exports.FILTER_SCOPE_VARS = schema.FILTER_SCOPE_VARS;
965
- exports.GUARD_PREDICATE_VARS = schema.GUARD_PREDICATE_VARS;
966
- exports.RESERVED_CONDITION_VARS = schema.RESERVED_CONDITION_VARS;
105
+ if (!descriptor.name) throw new Error("EffectDescriptor missing name");
106
+ return descriptor;
107
+ }
108
+
109
+ exports.CONDITION_VARS = invariants.CONDITION_VARS;
110
+
111
+ exports.FILTER_SCOPE_VARS = invariants.FILTER_SCOPE_VARS;
112
+
113
+ exports.GUARD_PREDICATE_VARS = invariants.GUARD_PREDICATE_VARS;
114
+
115
+ exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
116
+
117
+ exports.groq = invariants.groq;
118
+
967
119
  exports.defineAction = defineAction;
120
+
968
121
  exports.defineActivity = defineActivity;
122
+
969
123
  exports.defineEffect = defineEffect;
124
+
970
125
  exports.defineEffectDescriptor = defineEffectDescriptor;
126
+
971
127
  exports.defineField = defineField;
128
+
129
+ exports.defineGroup = defineGroup;
130
+
972
131
  exports.defineGuard = defineGuard;
132
+
973
133
  exports.defineOp = defineOp;
134
+
974
135
  exports.defineStage = defineStage;
136
+
975
137
  exports.defineTransition = defineTransition;
138
+
976
139
  exports.defineWorkflow = defineWorkflow;
140
+
977
141
  exports.defineWorkflowConfig = defineWorkflowConfig;
978
- exports.groq = groq;
979
- //# sourceMappingURL=define.cjs.map