@sanity/workflow-engine 0.11.0 → 0.13.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
@@ -29,27 +29,29 @@ function serializeGroqValue(value) {
29
29
  return serialized;
30
30
  }
31
31
  function desugarWorkflow(authoring) {
32
- const ctx = {
33
- issues: [],
32
+ const issues = [];
33
+ checkReservedRoleAliasKeys(authoring.roleAliases, issues);
34
+ const roleAliases = schema.normalizeRoleAliases(authoring.roleAliases), ctx = {
35
+ issues,
34
36
  claimFields: /* @__PURE__ */ new Map(),
35
37
  claimedFields: /* @__PURE__ */ new Set(),
36
- roleAliases: authoring.roleAliases
37
- }, workflowFields = desugarFieldEntries(authoring.fields, ["fields"], ctx), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
38
- const path = ["stages", i], stageFields = desugarFieldEntries(stage.fields, [...path, "fields"], ctx), stageEnv = {
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 = {
39
41
  layers: [
40
42
  { scope: "stage", entries: layerOf(stageFields) },
41
43
  { scope: "workflow", entries: workflowLayer }
42
44
  ]
43
- }, tasks = (stage.tasks ?? []).map(
44
- (task, j) => desugarTask(task, [...path, "tasks", j], stageEnv, ctx)
45
+ }, activities = (stage.activities ?? []).map(
46
+ (activity, j) => desugarActivity({ activity, path: [...path, "activities", j], stageEnv, ctx })
45
47
  ), transitions = (stage.transitions ?? []).map(
46
- (transition, k) => desugarTransition(transition, [...path, "transitions", k], stageEnv, ctx)
47
- ), editable = desugarStageEditable(
48
- stage.editable,
49
- editableSlotNames(workflowFields, stageFields, tasks),
50
- [...path, "editable"],
48
+ (transition, k) => desugarTransition({ transition, path: [...path, "transitions", k], stageEnv, ctx })
49
+ ), editable = desugarStageEditable({
50
+ overrides: stage.editable,
51
+ inScope: editableSlotNames({ workflowFields, stageFields, activities }),
52
+ path: [...path, "editable"],
51
53
  ctx
52
- );
54
+ });
53
55
  return {
54
56
  ...stripUndefined({
55
57
  name: stage.name,
@@ -58,7 +60,7 @@ function desugarWorkflow(authoring) {
58
60
  guards: stage.guards
59
61
  }),
60
62
  ...stageFields ? { fields: stageFields } : {},
61
- ...tasks.length > 0 ? { tasks } : {},
63
+ ...activities.length > 0 ? { activities } : {},
62
64
  ...transitions.length > 0 ? { transitions } : {},
63
65
  ...editable ? { editable } : {}
64
66
  };
@@ -66,43 +68,99 @@ function desugarWorkflow(authoring) {
66
68
  return checkUnclaimedClaimFields(ctx), { definition: {
67
69
  ...stripUndefined({
68
70
  name: authoring.name,
69
- version: authoring.version,
70
71
  title: authoring.title,
71
72
  description: authoring.description,
72
73
  role: authoring.role,
73
74
  initialStage: authoring.initialStage,
74
75
  predicates: authoring.predicates,
75
- roleAliases: authoring.roleAliases
76
+ roleAliases
76
77
  }),
77
78
  ...workflowFields ? { fields: workflowFields } : {},
78
79
  stages
79
80
  }, issues: ctx.issues };
80
81
  }
81
- function desugarFieldEntries(entries, path, ctx) {
82
- return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => {
83
- if (entry.type === "claim") {
84
- const desugared = {
85
- ...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
86
- type: "value.actor",
87
- source: { type: "write" }
88
- };
89
- return ctx.claimFields.set(desugared, { name: entry.name, path: [...path, i] }), desugared;
90
- }
91
- const editable = normalizeEditable(entry.editable, [...path, i, "editable"], ctx);
92
- return {
93
- ...stripUndefined({
94
- type: entry.type,
95
- name: entry.name,
96
- title: entry.title,
97
- description: entry.description,
98
- required: entry.required,
99
- editable
100
- }),
101
- source: entry.source
102
- };
103
- });
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
+ });
104
88
  }
105
- function normalizeEditable(editable, path, ctx) {
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
+ }) {
106
164
  if (editable === void 0 || editable === !0) return editable;
107
165
  if (Array.isArray(editable)) {
108
166
  const condition = rolesCondition(editable, ctx.roleAliases);
@@ -117,26 +175,35 @@ function normalizeEditable(editable, path, ctx) {
117
175
  }
118
176
  return editable;
119
177
  }
120
- function editableSlotNames(workflowFields, stageFields, tasks) {
178
+ function editableSlotNames({
179
+ workflowFields,
180
+ stageFields,
181
+ activities
182
+ }) {
121
183
  const names = /* @__PURE__ */ new Set(), collect = (entries) => {
122
184
  for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
123
185
  };
124
186
  collect(workflowFields), collect(stageFields);
125
- for (const task of tasks) collect(task.fields);
187
+ for (const activity of activities) collect(activity.fields);
126
188
  return names;
127
189
  }
128
- function desugarStageEditable(overrides, inScope, path, ctx) {
190
+ function desugarStageEditable({
191
+ overrides,
192
+ inScope,
193
+ path,
194
+ ctx
195
+ }) {
129
196
  if (overrides === void 0) return;
130
197
  const out = {};
131
198
  for (const [name, value] of Object.entries(overrides)) {
132
199
  if (!inScope.has(name)) {
133
200
  ctx.issues.push({
134
201
  path: [...path, name],
135
- message: `stage editable override "${name}" does not narrow an editable slot in scope \u2014 name a workflow/stage/task slot of this stage that declares \`editable\``
202
+ message: `stage editable override "${name}" does not narrow an editable slot in scope \u2014 name a workflow/stage/activity slot of this stage that declares \`editable\``
136
203
  });
137
204
  continue;
138
205
  }
139
- const normalized = normalizeEditable(value, [...path, name], ctx);
206
+ const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
140
207
  normalized !== void 0 && (out[name] = normalized);
141
208
  }
142
209
  return Object.keys(out).length > 0 ? out : void 0;
@@ -144,46 +211,72 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
144
211
  function layerOf(entries) {
145
212
  return new Map((entries ?? []).map((entry) => [entry.name, entry]));
146
213
  }
147
- function desugarTask(task, path, stageEnv, ctx) {
148
- const taskFields = desugarFieldEntries(task.fields, [...path, "fields"], ctx), env = {
149
- layers: [{ scope: "task", entries: layerOf(taskFields) }, ...stageEnv.layers]
150
- }, ops = desugarOps(task.ops, [...path, "ops"], env, task.name, ctx), actions = (task.actions ?? []).map(
151
- (action, a) => desugarAction(action, [...path, "actions", a], env, task.name, ctx)
152
- ), target = desugarTarget(task.target, env, [...path, "target"], ctx);
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 });
153
235
  return {
154
236
  ...stripUndefined({
155
- name: task.name,
156
- title: task.title,
157
- description: task.description,
158
- kind: task.kind,
159
- filter: task.filter,
160
- requirements: task.requirements,
161
- completeWhen: task.completeWhen,
162
- failWhen: task.failWhen,
163
- effects: task.effects,
164
- subworkflows: task.subworkflows
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
165
247
  }),
166
- activation: task.activation ?? "manual",
248
+ activation: activity.activation ?? "manual",
167
249
  ...target ? { target } : {},
168
- ...taskFields ? { fields: taskFields } : {},
250
+ ...activityFields ? { fields: activityFields } : {},
169
251
  ...ops ? { ops } : {},
170
252
  ...actions.length > 0 ? { actions } : {}
171
253
  };
172
254
  }
173
255
  const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
174
- function desugarTarget(target, env, path, ctx) {
256
+ function desugarTarget({
257
+ target,
258
+ env,
259
+ path,
260
+ ctx
261
+ }) {
175
262
  if (target === void 0 || target.type === "url") return target;
176
- const ref = typeof target.field == "string" ? { field: target.field } : target.field, field = resolveRef(ref, env, [...path, "field"], ctx) ?? fallbackRef(ref), entry = entryAt(env, field);
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);
177
264
  return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
178
265
  path: [...path, "field"],
179
- message: `manual task target references "${field.field}" of kind "${entry.type}" \u2014 a deep-link target needs a document-valued entry (${TARGET_DOC_KINDS.join(", ")})`
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(", ")})`
180
267
  }), { type: "field", field };
181
268
  }
182
- function desugarAction(action, path, env, taskName, ctx) {
269
+ function desugarAction({
270
+ action,
271
+ path,
272
+ env,
273
+ activityName,
274
+ ctx
275
+ }) {
183
276
  if ("type" in action)
184
- return desugarClaimAction(action, path, env, ctx);
185
- const filter = schema.andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps(action.ops, [...path, "ops"], env, taskName, ctx) ?? [];
186
- return action.status !== void 0 && ops.push({ type: "status.set", task: taskName, status: action.status }), {
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 }), {
187
280
  ...stripUndefined({
188
281
  name: action.name,
189
282
  title: action.title,
@@ -195,14 +288,26 @@ function desugarAction(action, path, env, taskName, ctx) {
195
288
  ...ops.length > 0 ? { ops } : {}
196
289
  };
197
290
  }
198
- function desugarClaimAction(action, path, env, ctx) {
199
- const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef(ref, env, [...path, "field"], ctx);
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 });
200
298
  if (resolved) {
201
299
  const entry = entryAt(env, resolved);
202
- entry && entry.type !== "value.actor" && ctx.issues.push({
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,
203
308
  path: [...path, "field"],
204
- message: `claim action "${action.name}" references "${resolved.field}" of kind "${entry.type}" \u2014 a claim pair needs an actor-valued entry (a "claim" or "value.actor" field declaration)`
205
- }), checkShadowedClaimTarget(action.name, ref.field, resolved, env, [...path, "field"], ctx), entry && ctx.claimedFields.add(entry);
309
+ ctx
310
+ }), entry && ctx.claimedFields.add(entry);
206
311
  }
207
312
  const noSteal = `!defined($fields.${ref.field})`, filter = schema.andConditions([
208
313
  noSteal,
@@ -221,7 +326,14 @@ function desugarClaimAction(action, path, env, ctx) {
221
326
  ...ops.length > 0 ? { ops } : {}
222
327
  };
223
328
  }
224
- function checkShadowedClaimTarget(actionName, field, resolved, env, path, ctx) {
329
+ function checkShadowedClaimTarget({
330
+ actionName,
331
+ field,
332
+ resolved,
333
+ env,
334
+ path,
335
+ ctx
336
+ }) {
225
337
  const nearest = env.layers.find((l) => l.entries.has(field));
226
338
  nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
227
339
  path,
@@ -232,11 +344,22 @@ function checkUnclaimedClaimFields(ctx) {
232
344
  for (const [entry, { name, path }] of ctx.claimFields)
233
345
  ctx.claimedFields.has(entry) || ctx.issues.push({
234
346
  path,
235
- 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 value.actor entry`
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`
236
348
  });
237
349
  }
238
- function desugarTransition(transition, path, stageEnv, ctx) {
239
- const ops = desugarOps(transition.ops, [...path, "ops"], stageEnv, void 0, ctx);
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
+ });
240
363
  return {
241
364
  ...stripUndefined({
242
365
  name: transition.name,
@@ -245,29 +368,46 @@ function desugarTransition(transition, path, stageEnv, ctx) {
245
368
  to: transition.to,
246
369
  effects: transition.effects
247
370
  }),
248
- filter: transition.filter ?? "$allTasksDone",
371
+ filter: transition.filter ?? "$allActivitiesDone",
249
372
  ...ops ? { ops } : {}
250
373
  };
251
374
  }
252
- function desugarOps(ops, path, env, firingTask, ctx) {
375
+ function desugarOps({
376
+ ops,
377
+ path,
378
+ env,
379
+ firingActivity,
380
+ ctx
381
+ }) {
253
382
  if (ops)
254
- return ops.map((op, i) => desugarOp(op, [...path, i], env, firingTask, ctx));
255
- }
256
- function desugarOp(op, path, env, firingTask, ctx) {
383
+ return ops.map((op, i) => desugarOp({ op, path: [...path, i], env, firingActivity, ctx }));
384
+ }
385
+ function desugarOp({
386
+ op,
387
+ path,
388
+ env,
389
+ firingActivity,
390
+ ctx
391
+ }) {
257
392
  if (op.type === "status.set") {
258
- const task = op.task ?? firingTask;
259
- return task === void 0 && ctx.issues.push({
260
- path: [...path, "task"],
261
- message: "status.set outside an action must name its target task"
262
- }), { type: "status.set", task: task ?? "", status: op.status };
393
+ const activity = op.activity ?? firingActivity;
394
+ return activity === void 0 && ctx.issues.push({
395
+ path: [...path, "activity"],
396
+ message: "status.set outside an action must name its target activity"
397
+ }), { type: "status.set", activity: activity ?? "", status: op.status };
263
398
  }
264
- if (op.type === "audit") return desugarAuditOp(op, path, env, ctx);
265
- const target = resolveRef(op.target, env, [...path, "target"], ctx) ?? fallbackRef(op.target);
399
+ if (op.type === "audit") return desugarAuditOp({ op, path, env, ctx });
400
+ const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
266
401
  return { ...op, target };
267
402
  }
268
403
  const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
269
- function desugarAuditOp(op, path, env, ctx) {
270
- const target = resolveRef(op.target, env, [...path, "target"], ctx) ?? fallbackRef(op.target);
404
+ function desugarAuditOp({
405
+ op,
406
+ path,
407
+ env,
408
+ ctx
409
+ }) {
410
+ const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
271
411
  if (op.value.type !== "object")
272
412
  return ctx.issues.push({
273
413
  path: [...path, "value"],
@@ -289,7 +429,12 @@ function desugarAuditOp(op, path, env, ctx) {
289
429
  }
290
430
  return { type: "field.append", target, value: { type: "object", fields } };
291
431
  }
292
- function resolveRef(ref, env, path, ctx) {
432
+ function resolveRef({
433
+ ref,
434
+ env,
435
+ path,
436
+ ctx
437
+ }) {
293
438
  const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
294
439
  for (const layer of layers)
295
440
  if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
@@ -323,83 +468,115 @@ const RESERVED_CONDITION_VARS = [
323
468
  "row",
324
469
  "now",
325
470
  "effects",
326
- "tasks",
471
+ "activities",
327
472
  "subworkflows",
328
473
  "self",
329
474
  "stage",
330
475
  "parent",
331
476
  "ancestors",
332
- "allTasksDone",
333
- "anyTaskFailed"
477
+ "allActivitiesDone",
478
+ "anyActivityFailed"
334
479
  ], PREDICATE_CALLER_VARS = ["actor", "assigned", "can"];
335
480
  function knownList(ids) {
336
481
  return [...ids].map((s) => `"${s}"`).join(", ");
337
482
  }
338
- function checkDuplicates(names, what, issues) {
483
+ function checkDuplicates({
484
+ names,
485
+ what,
486
+ issues
487
+ }) {
339
488
  const seen = /* @__PURE__ */ new Set();
340
489
  for (const { name, path } of names)
341
490
  seen.has(name) && issues.push({ path, message: `duplicate ${what} "${name}" (already declared earlier)` }), seen.add(name);
342
491
  return seen;
343
492
  }
344
493
  function checkStages(def, issues) {
345
- const stageNames = checkDuplicates(
346
- def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
347
- "stage name",
494
+ const stageNames = checkDuplicates({
495
+ names: def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
496
+ what: "stage name",
348
497
  issues
349
- );
498
+ });
350
499
  for (const [i, stage] of def.stages.entries()) {
351
- const taskNames = checkDuplicates(
352
- (stage.tasks ?? []).map((task, j) => ({
353
- name: task.name,
354
- path: ["stages", i, "tasks", j, "name"]
500
+ const activityNames = checkDuplicates({
501
+ names: (stage.activities ?? []).map((activity, j) => ({
502
+ name: activity.name,
503
+ path: ["stages", i, "activities", j, "name"]
355
504
  })),
356
- `task name in stage "${stage.name}"`,
505
+ what: `activity name in stage "${stage.name}"`,
357
506
  issues
358
- );
359
- checkDuplicates(
360
- (stage.transitions ?? []).map((t, k) => ({
507
+ });
508
+ checkDuplicates({
509
+ names: (stage.transitions ?? []).map((t, k) => ({
361
510
  name: t.name,
362
511
  path: ["stages", i, "transitions", k, "name"]
363
512
  })),
364
- `transition name in stage "${stage.name}"`,
513
+ what: `transition name in stage "${stage.name}"`,
365
514
  issues
366
- ), checkTasks(def, i, taskNames, issues);
515
+ }), checkActivities({ def, i, activityNames, issues });
367
516
  }
368
517
  return stageNames;
369
518
  }
370
- function checkTasks(def, i, taskNames, issues) {
519
+ function checkActivities({
520
+ def,
521
+ i,
522
+ activityNames,
523
+ issues
524
+ }) {
371
525
  const stage = def.stages[i];
372
- for (const [j, task] of (stage.tasks ?? []).entries()) {
373
- const path = ["stages", i, "tasks", j];
374
- checkDuplicates(
375
- (task.actions ?? []).map((action, a) => ({
526
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
527
+ const path = ["stages", i, "activities", j];
528
+ checkDuplicates({
529
+ names: (activity.actions ?? []).map((action, a) => ({
376
530
  name: action.name,
377
531
  path: [...path, "actions", a, "name"]
378
532
  })),
379
- `action name in task "${task.name}"`,
533
+ what: `action name in activity "${activity.name}"`,
380
534
  issues
381
- ), checkStatusSetTargets(task, taskNames, path, issues);
535
+ }), checkStatusSetTargets({ activity, activityNames, path, issues });
382
536
  }
383
537
  }
384
- function checkStatusSetTargets(task, taskNames, path, issues) {
385
- checkStatusSetOps(task.ops, taskNames, [...path, "ops"], issues);
386
- for (const [a, action] of (task.actions ?? []).entries())
387
- checkStatusSetOps(action.ops, taskNames, [...path, "actions", a, "ops"], issues);
538
+ function checkStatusSetTargets({
539
+ activity,
540
+ activityNames,
541
+ path,
542
+ issues
543
+ }) {
544
+ checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
545
+ for (const [a, action] of (activity.actions ?? []).entries())
546
+ checkStatusSetOps({
547
+ ops: action.ops,
548
+ activityNames,
549
+ path: [...path, "actions", a, "ops"],
550
+ issues
551
+ });
388
552
  }
389
- function checkStatusSetOps(ops, taskNames, path, issues) {
553
+ function checkStatusSetOps({
554
+ ops,
555
+ activityNames,
556
+ path,
557
+ issues
558
+ }) {
390
559
  for (const [o, op] of (ops ?? []).entries())
391
- op.type !== "status.set" || taskNames.has(op.task) || issues.push({
392
- path: [...path, o, "task"],
393
- message: `status.set targets task "${op.task}" which is not declared in this stage. Known tasks: ${knownList(taskNames)}`
560
+ op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
561
+ path: [...path, o, "activity"],
562
+ message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
394
563
  });
395
564
  }
396
- function checkInitialStage(def, stageNames, issues) {
565
+ function checkInitialStage({
566
+ def,
567
+ stageNames,
568
+ issues
569
+ }) {
397
570
  stageNames.has(def.initialStage) || issues.push({
398
571
  path: ["initialStage"],
399
572
  message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
400
573
  });
401
574
  }
402
- function checkTransitionTargets(def, stageNames, issues) {
575
+ function checkTransitionTargets({
576
+ def,
577
+ stageNames,
578
+ issues
579
+ }) {
403
580
  for (const [i, stage] of def.stages.entries())
404
581
  for (const [k, t] of (stage.transitions ?? []).entries())
405
582
  stageNames.has(t.to) || issues.push({
@@ -410,17 +587,33 @@ function checkTransitionTargets(def, stageNames, issues) {
410
587
  function checkEffectNames(def, issues) {
411
588
  const sites = [];
412
589
  for (const [i, stage] of def.stages.entries()) {
413
- for (const [j, task] of (stage.tasks ?? []).entries()) {
414
- collectEffects(task.effects, ["stages", i, "tasks", j, "effects"], sites);
415
- for (const [a, action] of (task.actions ?? []).entries())
416
- collectEffects(action.effects, ["stages", i, "tasks", j, "actions", a, "effects"], sites);
590
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
591
+ collectEffects({
592
+ effects: activity.effects,
593
+ path: ["stages", i, "activities", j, "effects"],
594
+ sites
595
+ });
596
+ for (const [a, action] of (activity.actions ?? []).entries())
597
+ collectEffects({
598
+ effects: action.effects,
599
+ path: ["stages", i, "activities", j, "actions", a, "effects"],
600
+ sites
601
+ });
417
602
  }
418
603
  for (const [k, t] of (stage.transitions ?? []).entries())
419
- collectEffects(t.effects, ["stages", i, "transitions", k, "effects"], sites);
604
+ collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
420
605
  }
421
- checkDuplicates(sites, "effect name (registry key \u2014 unique per definition)", issues);
606
+ checkDuplicates({
607
+ names: sites,
608
+ what: "effect name (registry key \u2014 unique per definition)",
609
+ issues
610
+ });
422
611
  }
423
- function collectEffects(effects, path, sites) {
612
+ function collectEffects({
613
+ effects,
614
+ path,
615
+ sites
616
+ }) {
424
617
  for (const [e, effect] of (effects ?? []).entries())
425
618
  sites.push({ name: effect.name, path: [...path, e, "name"] });
426
619
  }
@@ -431,11 +624,11 @@ function checkGuardNames(def, issues) {
431
624
  path: ["stages", i, "guards", g, "name"]
432
625
  }))
433
626
  );
434
- checkDuplicates(
435
- sites,
436
- "guard name (the guard lake _id derives from it \u2014 unique per definition)",
627
+ checkDuplicates({
628
+ names: sites,
629
+ what: "guard name (the guard lake _id derives from it \u2014 unique per definition)",
437
630
  issues
438
- );
631
+ });
439
632
  }
440
633
  function fieldScopes(def) {
441
634
  const scopes = [
@@ -448,12 +641,12 @@ function fieldScopes(def) {
448
641
  path: ["stages", i, "fields"],
449
642
  label: `stage "${stage.name}" fields`
450
643
  });
451
- for (const [j, task] of (stage.tasks ?? []).entries())
644
+ for (const [j, activity] of (stage.activities ?? []).entries())
452
645
  scopes.push({
453
- entries: task.fields,
454
- scope: "task",
455
- path: ["stages", i, "tasks", j, "fields"],
456
- label: `task "${task.name}" fields`
646
+ entries: activity.fields,
647
+ scope: "activity",
648
+ path: ["stages", i, "activities", j, "fields"],
649
+ label: `activity "${activity.name}" fields`
457
650
  });
458
651
  }
459
652
  return scopes;
@@ -461,21 +654,28 @@ function fieldScopes(def) {
461
654
  function checkRequiredField(def, issues) {
462
655
  for (const { entries, scope, path, label } of fieldScopes(def))
463
656
  for (const [n, entry] of (entries ?? []).entries())
464
- entry.required === !0 && (scope !== "workflow" ? issues.push({
465
- path: [...path, n, "required"],
466
- message: `${label} entry "${entry.name}" is \`required\`, but \`required\` applies only to workflow-scope \`init\` entries \u2014 only those are caller-supplied at start/spawn`
467
- }) : entry.source.type !== "init" && issues.push({
468
- path: [...path, n, "required"],
469
- message: `field entry "${entry.name}" is \`required\` but its source is "${entry.source.type}" \u2014 \`required\` applies only to \`init\`-sourced entries (the caller fills them at start/spawn)`
470
- }));
657
+ if (entry.required === !0) {
658
+ if (scope !== "workflow")
659
+ issues.push({
660
+ path: [...path, n, "required"],
661
+ 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`
662
+ });
663
+ else if (entry.initialValue?.type !== "input") {
664
+ const seed = entry.initialValue?.type ?? "working memory (no initialValue)";
665
+ issues.push({
666
+ path: [...path, n, "required"],
667
+ message: `field entry "${entry.name}" has initialValue "${seed}" \u2014 \`required\` applies only to \`input\`-sourced entries (the caller fills them at start/spawn)`
668
+ });
669
+ }
670
+ }
471
671
  }
472
672
  function checkFieldEntryNames(def, issues) {
473
673
  for (const { entries, path, label } of fieldScopes(def))
474
- checkDuplicates(
475
- (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
476
- `field entry name in ${label}`,
674
+ checkDuplicates({
675
+ names: (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
676
+ what: `field entry name in ${label}`,
477
677
  issues
478
- );
678
+ });
479
679
  }
480
680
  function checkPredicates(def, issues) {
481
681
  const reserved = new Set(RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
@@ -485,9 +685,14 @@ function checkPredicates(def, issues) {
485
685
  message: `predicate "${name}" shadows the built-in $${name} \u2014 pick another name`
486
686
  });
487
687
  for (const [name, groq2] of Object.entries(def.predicates ?? {}))
488
- checkPredicateBody(name, groq2, names, issues);
489
- }
490
- function checkPredicateBody(name, groq2, names, issues) {
688
+ checkPredicateBody({ name, groq: groq2, names, issues });
689
+ }
690
+ function checkPredicateBody({
691
+ name,
692
+ groq: groq2,
693
+ names,
694
+ issues
695
+ }) {
491
696
  for (const caller of PREDICATE_CALLER_VARS)
492
697
  referencesVar(groq2, caller) && issues.push({
493
698
  path: ["predicates", name],
@@ -517,40 +722,53 @@ function nonActionFilterConditionSites(def) {
517
722
  groq: t.filter,
518
723
  path: ["stages", i, "transitions", k, "filter"],
519
724
  label: `transition "${t.name}" filter`
520
- }), collectBindingSites(
521
- t.effects,
522
- ["stages", i, "transitions", k, "effects"],
523
- `transition "${t.name}"`,
725
+ }), collectBindingSites({
726
+ effects: t.effects,
727
+ path: ["stages", i, "transitions", k, "effects"],
728
+ label: `transition "${t.name}"`,
524
729
  sites
525
- );
526
- for (const [j, task] of (stage.tasks ?? []).entries())
527
- collectTaskConditionSites(task, ["stages", i, "tasks", j], sites);
730
+ });
731
+ for (const [j, activity] of (stage.activities ?? []).entries())
732
+ collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
528
733
  }
529
734
  return sites;
530
735
  }
531
- function collectTaskConditionSites(task, path, sites) {
736
+ function collectActivityConditionSites({
737
+ activity,
738
+ path,
739
+ sites
740
+ }) {
532
741
  for (const field of ["filter", "completeWhen", "failWhen"]) {
533
- const groq2 = task[field];
534
- groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `task "${task.name}".${field}` });
742
+ const groq2 = activity[field];
743
+ groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `activity "${activity.name}".${field}` });
535
744
  }
536
- collectBindingSites(task.effects, [...path, "effects"], `task "${task.name}"`, sites);
537
- for (const [a, action] of (task.actions ?? []).entries())
538
- collectBindingSites(
539
- action.effects,
540
- [...path, "actions", a, "effects"],
541
- `action "${action.name}"`,
745
+ collectBindingSites({
746
+ effects: activity.effects,
747
+ path: [...path, "effects"],
748
+ label: `activity "${activity.name}"`,
749
+ sites
750
+ });
751
+ for (const [a, action] of (activity.actions ?? []).entries())
752
+ collectBindingSites({
753
+ effects: action.effects,
754
+ path: [...path, "actions", a, "effects"],
755
+ label: `action "${action.name}"`,
542
756
  sites
543
- );
544
- collectSubworkflowSites(task, path, sites);
545
- }
546
- function collectSubworkflowSites(task, path, sites) {
547
- const sub = task.subworkflows;
757
+ });
758
+ collectSubworkflowSites({ activity, path, sites });
759
+ }
760
+ function collectSubworkflowSites({
761
+ activity,
762
+ path,
763
+ sites
764
+ }) {
765
+ const sub = activity.subworkflows;
548
766
  if (sub === void 0) return;
549
767
  const subPath = [...path, "subworkflows"];
550
768
  sites.push({
551
769
  groq: sub.forEach,
552
770
  path: [...subPath, "forEach"],
553
- label: `task "${task.name}".subworkflows.forEach`
771
+ label: `activity "${activity.name}".subworkflows.forEach`
554
772
  });
555
773
  for (const [group, record] of [
556
774
  ["with", sub.with],
@@ -560,10 +778,15 @@ function collectSubworkflowSites(task, path, sites) {
560
778
  sites.push({
561
779
  groq: groq2,
562
780
  path: [...subPath, group, key],
563
- label: `task "${task.name}".subworkflows.${group} "${key}"`
781
+ label: `activity "${activity.name}".subworkflows.${group} "${key}"`
564
782
  });
565
783
  }
566
- function collectBindingSites(effects, path, label, sites) {
784
+ function collectBindingSites({
785
+ effects,
786
+ path,
787
+ label,
788
+ sites
789
+ }) {
567
790
  for (const [e, effect] of (effects ?? []).entries())
568
791
  for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
569
792
  sites.push({
@@ -579,12 +802,12 @@ function checkAssigneesEntries(def, issues) {
579
802
  message: "at most one assignees-kind field entry per scope \u2014 the inbox reads it by kind"
580
803
  });
581
804
  }
582
- function taskShape(task) {
805
+ function activityShape(activity) {
583
806
  return {
584
- hasActions: (task.actions ?? []).length > 0,
585
- hasEffects: (task.effects ?? []).length > 0,
586
- hasCompleteWhen: task.completeWhen !== void 0,
587
- hasSubworkflows: task.subworkflows !== void 0
807
+ hasActions: (activity.actions ?? []).length > 0,
808
+ hasEffects: (activity.effects ?? []).length > 0,
809
+ hasCompleteWhen: activity.completeWhen !== void 0,
810
+ hasSubworkflows: activity.subworkflows !== void 0
588
811
  };
589
812
  }
590
813
  const KIND_SHAPE_RULES = {
@@ -592,7 +815,7 @@ const KIND_SHAPE_RULES = {
592
815
  service: (s) => s.hasEffects ? [] : ["needs at least one effect \u2014 the automated work it performs"],
593
816
  manual: (s) => [
594
817
  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)",
595
- s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own task" : void 0
818
+ s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own activity" : void 0
596
819
  ].filter((m) => m !== void 0),
597
820
  receive: (s) => [
598
821
  s.hasCompleteWhen || s.hasSubworkflows ? void 0 : "needs a `completeWhen` (or `subworkflows`) condition to wait on",
@@ -604,53 +827,77 @@ const KIND_SHAPE_RULES = {
604
827
  s.hasSubworkflows ? "resolves on activation, so it cannot fan out with `subworkflows`" : void 0
605
828
  ].filter((m) => m !== void 0)
606
829
  };
607
- function checkTaskKinds(def, issues) {
830
+ function checkActivityKinds(def, issues) {
608
831
  for (const [i, stage] of def.stages.entries())
609
- for (const [j, task] of (stage.tasks ?? []).entries()) {
610
- const path = ["stages", i, "tasks", j];
611
- if (task.target !== void 0 && task.kind !== "manual" && issues.push({
832
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
833
+ const path = ["stages", i, "activities", j];
834
+ if (activity.target !== void 0 && activity.kind !== "manual" && issues.push({
612
835
  path: [...path, "target"],
613
- message: `task "${task.name}" has a \`target\` but is not \`kind: "manual"\` \u2014 a target is the deep-link for off-system manual work`
614
- }), task.kind !== void 0)
615
- for (const fault of KIND_SHAPE_RULES[task.kind](taskShape(task)))
836
+ message: `activity "${activity.name}" has a \`target\` but is not \`kind: "manual"\` \u2014 a target is the deep-link for off-system manual work`
837
+ }), activity.kind !== void 0)
838
+ for (const fault of KIND_SHAPE_RULES[activity.kind](activityShape(activity)))
616
839
  issues.push({
617
840
  path: [...path, "kind"],
618
- message: `task "${task.name}" declares kind "${task.kind}" but ${fault}`
841
+ message: `activity "${activity.name}" declares kind "${activity.kind}" but ${fault}`
619
842
  });
620
843
  }
621
844
  }
622
845
  function checkWorkflowInvariants(def) {
623
846
  const issues = [], stageNames = checkStages(def, issues);
624
- 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), checkTaskKinds(def, issues), issues;
847
+ 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;
625
848
  }
626
849
  function defineWorkflow(definition) {
627
- const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow(schema.AuthoringWorkflowSchema, definition, label), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
850
+ const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow({ schema: schema.AuthoringWorkflowSchema, input: definition, label }), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
628
851
  if (issues.length > 0) throw new Error(schema.formatValidationError(label, issues));
629
852
  return stored;
630
853
  }
631
854
  function defineStage(stage) {
632
- return parseOrThrow(schema.AuthoringStageSchema, stage, labelFor("defineStage", stage));
855
+ return parseOrThrow({
856
+ schema: schema.AuthoringStageSchema,
857
+ input: stage,
858
+ label: labelFor("defineStage", stage)
859
+ });
633
860
  }
634
- function defineTask(task) {
635
- return parseOrThrow(schema.AuthoringTaskSchema, task, labelFor("defineTask", task));
861
+ function defineActivity(activity) {
862
+ return parseOrThrow({
863
+ schema: schema.AuthoringActivitySchema,
864
+ input: activity,
865
+ label: labelFor("defineActivity", activity)
866
+ });
636
867
  }
637
868
  function defineAction(action) {
638
- return parseOrThrow(schema.AuthoringActionSchema, action, labelFor("defineAction", action));
869
+ return parseOrThrow({
870
+ schema: schema.AuthoringActionSchema,
871
+ input: action,
872
+ label: labelFor("defineAction", action)
873
+ });
639
874
  }
640
875
  function defineTransition(transition) {
641
- return parseOrThrow(schema.AuthoringTransitionSchema, transition, transitionLabel(transition));
876
+ return parseOrThrow({
877
+ schema: schema.AuthoringTransitionSchema,
878
+ input: transition,
879
+ label: transitionLabel(transition)
880
+ });
642
881
  }
643
882
  function defineField(entry) {
644
- return parseOrThrow(schema.AuthoringFieldEntrySchema, entry, labelFor("defineField", entry));
883
+ return parseOrThrow({
884
+ schema: schema.AuthoringFieldEntrySchema,
885
+ input: entry,
886
+ label: labelFor("defineField", entry)
887
+ });
645
888
  }
646
889
  function defineOp(op) {
647
- return parseOrThrow(schema.AuthoringOpSchema, op, "defineOp");
890
+ return parseOrThrow({ schema: schema.AuthoringOpSchema, input: op, label: "defineOp" });
648
891
  }
649
892
  function defineGuard(guard) {
650
- return parseOrThrow(schema.GuardSchema, guard, labelFor("defineGuard", guard));
893
+ return parseOrThrow({ schema: schema.GuardSchema, input: guard, label: labelFor("defineGuard", guard) });
651
894
  }
652
895
  function defineEffect(effect) {
653
- return parseOrThrow(schema.EffectSchema, effect, labelFor("defineEffect", effect));
896
+ return parseOrThrow({
897
+ schema: schema.EffectSchema,
898
+ input: effect,
899
+ label: labelFor("defineEffect", effect)
900
+ });
654
901
  }
655
902
  function transitionLabel(transition) {
656
903
  const { name, to } = transition;
@@ -660,7 +907,11 @@ function defineEffectDescriptor(descriptor) {
660
907
  if (!descriptor.name) throw new Error("EffectDescriptor missing name");
661
908
  return descriptor;
662
909
  }
663
- function parseOrThrow(schema$1, input, label) {
910
+ function parseOrThrow({
911
+ schema: schema$1,
912
+ input,
913
+ label
914
+ }) {
664
915
  const result = v__namespace.safeParse(schema$1, input);
665
916
  if (!result.success)
666
917
  throw new Error(schema.formatValidationError(label, schema.issuesFromValibot(result.issues)));
@@ -674,13 +925,13 @@ function labelFor(fn, value) {
674
925
  return fn;
675
926
  }
676
927
  exports.defineAction = defineAction;
928
+ exports.defineActivity = defineActivity;
677
929
  exports.defineEffect = defineEffect;
678
930
  exports.defineEffectDescriptor = defineEffectDescriptor;
679
931
  exports.defineField = defineField;
680
932
  exports.defineGuard = defineGuard;
681
933
  exports.defineOp = defineOp;
682
934
  exports.defineStage = defineStage;
683
- exports.defineTask = defineTask;
684
935
  exports.defineTransition = defineTransition;
685
936
  exports.defineWorkflow = defineWorkflow;
686
937
  exports.groq = groq;