@sanity/workflow-engine 0.8.0 → 0.10.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/_chunks-cjs/schema.cjs +112 -65
- package/dist/_chunks-cjs/schema.cjs.map +1 -1
- package/dist/_chunks-es/schema.js +112 -65
- package/dist/_chunks-es/schema.js.map +1 -1
- package/dist/define.cjs +128 -65
- package/dist/define.cjs.map +1 -1
- package/dist/define.d.cts +886 -431
- package/dist/define.d.ts +886 -431
- package/dist/define.js +129 -66
- package/dist/define.js.map +1 -1
- package/dist/index.cjs +620 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1649 -808
- package/dist/index.d.ts +1649 -808
- package/dist/index.js +621 -245
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/define.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
|
-
import { GROQ_IDENTIFIER, formatValidationError, issuesFromValibot, AuthoringWorkflowSchema, AuthoringStageSchema, AuthoringTaskSchema, AuthoringActionSchema, AuthoringTransitionSchema,
|
|
2
|
+
import { andConditions, expandRequiredRoles, GROQ_IDENTIFIER, formatValidationError, issuesFromValibot, AuthoringWorkflowSchema, AuthoringStageSchema, AuthoringTaskSchema, AuthoringActionSchema, AuthoringTransitionSchema, AuthoringFieldEntrySchema, AuthoringOpSchema, GuardSchema, EffectSchema } from "./_chunks-es/schema.js";
|
|
3
3
|
function groq(strings, ...values) {
|
|
4
4
|
return strings.reduce((out, part, i) => i === 0 ? part : `${out}${serializeGroqValue(values[i - 1])}${part}`, "");
|
|
5
5
|
}
|
|
@@ -12,16 +12,26 @@ function serializeGroqValue(value) {
|
|
|
12
12
|
return serialized;
|
|
13
13
|
}
|
|
14
14
|
function desugarWorkflow(authoring) {
|
|
15
|
-
const ctx = {
|
|
16
|
-
|
|
15
|
+
const ctx = {
|
|
16
|
+
issues: [],
|
|
17
|
+
claimFields: /* @__PURE__ */ new Map(),
|
|
18
|
+
claimedFields: /* @__PURE__ */ new Set(),
|
|
19
|
+
roleAliases: authoring.roleAliases
|
|
20
|
+
}, workflowFields = desugarFieldEntries(authoring.fields, ["fields"], ctx), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
|
|
21
|
+
const path = ["stages", i], stageFields = desugarFieldEntries(stage.fields, [...path, "fields"], ctx), stageEnv = {
|
|
17
22
|
layers: [
|
|
18
|
-
{ scope: "stage", entries: layerOf(
|
|
23
|
+
{ scope: "stage", entries: layerOf(stageFields) },
|
|
19
24
|
{ scope: "workflow", entries: workflowLayer }
|
|
20
25
|
]
|
|
21
26
|
}, tasks = (stage.tasks ?? []).map(
|
|
22
27
|
(task, j) => desugarTask(task, [...path, "tasks", j], stageEnv, ctx)
|
|
23
28
|
), transitions = (stage.transitions ?? []).map(
|
|
24
29
|
(transition, k) => desugarTransition(transition, [...path, "transitions", k], stageEnv, ctx)
|
|
30
|
+
), editable = desugarStageEditable(
|
|
31
|
+
stage.editable,
|
|
32
|
+
editableSlotNames(workflowFields, stageFields, tasks),
|
|
33
|
+
[...path, "editable"],
|
|
34
|
+
ctx
|
|
25
35
|
);
|
|
26
36
|
return {
|
|
27
37
|
...stripUndefined({
|
|
@@ -30,12 +40,13 @@ function desugarWorkflow(authoring) {
|
|
|
30
40
|
description: stage.description,
|
|
31
41
|
guards: stage.guards
|
|
32
42
|
}),
|
|
33
|
-
...
|
|
43
|
+
...stageFields ? { fields: stageFields } : {},
|
|
34
44
|
...tasks.length > 0 ? { tasks } : {},
|
|
35
|
-
...transitions.length > 0 ? { transitions } : {}
|
|
45
|
+
...transitions.length > 0 ? { transitions } : {},
|
|
46
|
+
...editable ? { editable } : {}
|
|
36
47
|
};
|
|
37
48
|
});
|
|
38
|
-
return
|
|
49
|
+
return checkUnclaimedClaimFields(ctx), { definition: {
|
|
39
50
|
...stripUndefined({
|
|
40
51
|
name: authoring.name,
|
|
41
52
|
version: authoring.version,
|
|
@@ -43,29 +54,82 @@ function desugarWorkflow(authoring) {
|
|
|
43
54
|
description: authoring.description,
|
|
44
55
|
role: authoring.role,
|
|
45
56
|
initialStage: authoring.initialStage,
|
|
46
|
-
predicates: authoring.predicates
|
|
57
|
+
predicates: authoring.predicates,
|
|
58
|
+
roleAliases: authoring.roleAliases
|
|
47
59
|
}),
|
|
48
|
-
...
|
|
60
|
+
...workflowFields ? { fields: workflowFields } : {},
|
|
49
61
|
stages
|
|
50
62
|
}, issues: ctx.issues };
|
|
51
63
|
}
|
|
52
|
-
function
|
|
64
|
+
function desugarFieldEntries(entries, path, ctx) {
|
|
53
65
|
return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => {
|
|
54
|
-
if (entry.type
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
if (entry.type === "claim") {
|
|
67
|
+
const desugared = {
|
|
68
|
+
...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
|
|
69
|
+
type: "value.actor",
|
|
70
|
+
source: { type: "write" }
|
|
71
|
+
};
|
|
72
|
+
return ctx.claimFields.set(desugared, { name: entry.name, path: [...path, i] }), desugared;
|
|
73
|
+
}
|
|
74
|
+
const editable = normalizeEditable(entry.editable, [...path, i, "editable"], ctx);
|
|
75
|
+
return {
|
|
76
|
+
...stripUndefined({
|
|
77
|
+
type: entry.type,
|
|
78
|
+
name: entry.name,
|
|
79
|
+
title: entry.title,
|
|
80
|
+
description: entry.description,
|
|
81
|
+
required: entry.required,
|
|
82
|
+
editable
|
|
83
|
+
}),
|
|
84
|
+
source: entry.source
|
|
59
85
|
};
|
|
60
|
-
return ctx.claimStates.set(desugared, { name: entry.name, path: [...path, i] }), desugared;
|
|
61
86
|
});
|
|
62
87
|
}
|
|
88
|
+
function normalizeEditable(editable, path, ctx) {
|
|
89
|
+
if (editable === void 0 || editable === !0) return editable;
|
|
90
|
+
if (Array.isArray(editable)) {
|
|
91
|
+
const condition = rolesCondition(editable, ctx.roleAliases);
|
|
92
|
+
if (condition === void 0) {
|
|
93
|
+
ctx.issues.push({
|
|
94
|
+
path,
|
|
95
|
+
message: "editable: [] names no roles \u2014 use `true` to open the slot to anyone in its scope, or list at least one role"
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
return condition;
|
|
100
|
+
}
|
|
101
|
+
return editable;
|
|
102
|
+
}
|
|
103
|
+
function editableSlotNames(workflowFields, stageFields, tasks) {
|
|
104
|
+
const names = /* @__PURE__ */ new Set(), collect = (entries) => {
|
|
105
|
+
for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
|
|
106
|
+
};
|
|
107
|
+
collect(workflowFields), collect(stageFields);
|
|
108
|
+
for (const task of tasks) collect(task.fields);
|
|
109
|
+
return names;
|
|
110
|
+
}
|
|
111
|
+
function desugarStageEditable(overrides, inScope, path, ctx) {
|
|
112
|
+
if (overrides === void 0) return;
|
|
113
|
+
const out = {};
|
|
114
|
+
for (const [name, value] of Object.entries(overrides)) {
|
|
115
|
+
if (!inScope.has(name)) {
|
|
116
|
+
ctx.issues.push({
|
|
117
|
+
path: [...path, name],
|
|
118
|
+
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\``
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const normalized = normalizeEditable(value, [...path, name], ctx);
|
|
123
|
+
normalized !== void 0 && (out[name] = normalized);
|
|
124
|
+
}
|
|
125
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
126
|
+
}
|
|
63
127
|
function layerOf(entries) {
|
|
64
128
|
return new Map((entries ?? []).map((entry) => [entry.name, entry]));
|
|
65
129
|
}
|
|
66
130
|
function desugarTask(task, path, stageEnv, ctx) {
|
|
67
|
-
const
|
|
68
|
-
layers: [{ scope: "task", entries: layerOf(
|
|
131
|
+
const taskFields = desugarFieldEntries(task.fields, [...path, "fields"], ctx), env = {
|
|
132
|
+
layers: [{ scope: "task", entries: layerOf(taskFields) }, ...stageEnv.layers]
|
|
69
133
|
}, ops = desugarOps(task.ops, [...path, "ops"], env, task.name, ctx), actions = (task.actions ?? []).map(
|
|
70
134
|
(action, a) => desugarAction(action, [...path, "actions", a], env, task.name, ctx)
|
|
71
135
|
);
|
|
@@ -82,7 +146,7 @@ function desugarTask(task, path, stageEnv, ctx) {
|
|
|
82
146
|
subworkflows: task.subworkflows
|
|
83
147
|
}),
|
|
84
148
|
activation: task.activation ?? "manual",
|
|
85
|
-
...
|
|
149
|
+
...taskFields ? { fields: taskFields } : {},
|
|
86
150
|
...ops ? { ops } : {},
|
|
87
151
|
...actions.length > 0 ? { actions } : {}
|
|
88
152
|
};
|
|
@@ -90,7 +154,7 @@ function desugarTask(task, path, stageEnv, ctx) {
|
|
|
90
154
|
function desugarAction(action, path, env, taskName, ctx) {
|
|
91
155
|
if ("type" in action)
|
|
92
156
|
return desugarClaimAction(action, path, env, ctx);
|
|
93
|
-
const filter =
|
|
157
|
+
const filter = andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps(action.ops, [...path, "ops"], env, taskName, ctx) ?? [];
|
|
94
158
|
return action.status !== void 0 && ops.push({ type: "status.set", task: taskName, status: action.status }), {
|
|
95
159
|
...stripUndefined({
|
|
96
160
|
name: action.name,
|
|
@@ -104,15 +168,19 @@ function desugarAction(action, path, env, taskName, ctx) {
|
|
|
104
168
|
};
|
|
105
169
|
}
|
|
106
170
|
function desugarClaimAction(action, path, env, ctx) {
|
|
107
|
-
const ref = typeof action.
|
|
171
|
+
const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef(ref, env, [...path, "field"], ctx);
|
|
108
172
|
if (resolved) {
|
|
109
173
|
const entry = entryAt(env, resolved);
|
|
110
174
|
entry && entry.type !== "value.actor" && ctx.issues.push({
|
|
111
|
-
path: [...path, "
|
|
112
|
-
message: `claim action "${action.name}" references "${resolved.
|
|
113
|
-
}), checkShadowedClaimTarget(action.name, ref.
|
|
175
|
+
path: [...path, "field"],
|
|
176
|
+
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)`
|
|
177
|
+
}), checkShadowedClaimTarget(action.name, ref.field, resolved, env, [...path, "field"], ctx), entry && ctx.claimedFields.add(entry);
|
|
114
178
|
}
|
|
115
|
-
const noSteal = `!defined($
|
|
179
|
+
const noSteal = `!defined($fields.${ref.field})`, filter = andConditions([
|
|
180
|
+
noSteal,
|
|
181
|
+
rolesCondition(action.roles, ctx.roleAliases),
|
|
182
|
+
action.filter
|
|
183
|
+
]), ops = resolved ? [{ type: "field.set", target: resolved, value: { type: "actor" } }] : [];
|
|
116
184
|
return {
|
|
117
185
|
...stripUndefined({
|
|
118
186
|
name: action.name,
|
|
@@ -125,18 +193,18 @@ function desugarClaimAction(action, path, env, ctx) {
|
|
|
125
193
|
...ops.length > 0 ? { ops } : {}
|
|
126
194
|
};
|
|
127
195
|
}
|
|
128
|
-
function checkShadowedClaimTarget(actionName,
|
|
129
|
-
const nearest = env.layers.find((l) => l.entries.has(
|
|
196
|
+
function checkShadowedClaimTarget(actionName, field, resolved, env, path, ctx) {
|
|
197
|
+
const nearest = env.layers.find((l) => l.entries.has(field));
|
|
130
198
|
nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
|
|
131
199
|
path,
|
|
132
|
-
message: `claim action "${actionName}" targets "${
|
|
200
|
+
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`
|
|
133
201
|
});
|
|
134
202
|
}
|
|
135
|
-
function
|
|
136
|
-
for (const [entry, { name, path }] of ctx.
|
|
137
|
-
ctx.
|
|
203
|
+
function checkUnclaimedClaimFields(ctx) {
|
|
204
|
+
for (const [entry, { name, path }] of ctx.claimFields)
|
|
205
|
+
ctx.claimedFields.has(entry) || ctx.issues.push({
|
|
138
206
|
path,
|
|
139
|
-
message: `claim
|
|
207
|
+
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`
|
|
140
208
|
});
|
|
141
209
|
}
|
|
142
210
|
function desugarTransition(transition, path, stageEnv, ctx) {
|
|
@@ -176,7 +244,7 @@ function desugarAuditOp(op, path, env, ctx) {
|
|
|
176
244
|
return ctx.issues.push({
|
|
177
245
|
path: [...path, "value"],
|
|
178
246
|
message: `audit value must be an object source carrying the domain fields (got "${op.value.type}")`
|
|
179
|
-
}), { type: "
|
|
247
|
+
}), { type: "field.append", target, value: op.value };
|
|
180
248
|
const actorField = op.stampFields?.actor ?? "actor", atField = op.stampFields?.at ?? "at", fields = { ...op.value.fields };
|
|
181
249
|
for (const [stamp, source] of [
|
|
182
250
|
[actorField, AUDIT_STAMPS.actor],
|
|
@@ -191,32 +259,27 @@ function desugarAuditOp(op, path, env, ctx) {
|
|
|
191
259
|
}
|
|
192
260
|
fields[stamp] = source;
|
|
193
261
|
}
|
|
194
|
-
return { type: "
|
|
262
|
+
return { type: "field.append", target, value: { type: "object", fields } };
|
|
195
263
|
}
|
|
196
264
|
function resolveRef(ref, env, path, ctx) {
|
|
197
265
|
const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
|
|
198
266
|
for (const layer of layers)
|
|
199
|
-
if (layer.entries.has(ref.
|
|
267
|
+
if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
|
|
200
268
|
const reachable = env.layers.flatMap((l) => [...l.entries.keys()].map((n) => `${l.scope}:${n}`));
|
|
201
269
|
ctx.issues.push({
|
|
202
270
|
path,
|
|
203
|
-
message: `
|
|
271
|
+
message: `field reference "${ref.field}"${ref.scope ? ` (scope "${ref.scope}")` : ""} does not resolve to a declared entry. Reachable: ${reachable.join(", ") || "(none)"}`
|
|
204
272
|
});
|
|
205
273
|
}
|
|
206
274
|
function entryAt(env, ref) {
|
|
207
|
-
return env.layers.find((l) => l.scope === ref.scope)?.entries.get(ref.
|
|
275
|
+
return env.layers.find((l) => l.scope === ref.scope)?.entries.get(ref.field);
|
|
208
276
|
}
|
|
209
277
|
function fallbackRef(ref) {
|
|
210
|
-
return { scope: ref.scope ?? "workflow",
|
|
278
|
+
return { scope: ref.scope ?? "workflow", field: ref.field };
|
|
211
279
|
}
|
|
212
|
-
function rolesCondition(roles) {
|
|
280
|
+
function rolesCondition(roles, aliases) {
|
|
213
281
|
if (!(!roles || roles.length === 0))
|
|
214
|
-
return groq`count($actor.roles[@ in ${roles}]) > 0`;
|
|
215
|
-
}
|
|
216
|
-
function composeFilter(parts) {
|
|
217
|
-
const present = parts.filter((p) => p !== void 0);
|
|
218
|
-
if (present.length !== 0)
|
|
219
|
-
return present.length === 1 ? present[0] : present.map((p) => `(${p})`).join(" && ");
|
|
282
|
+
return groq`count($actor.roles[@ in ${expandRequiredRoles(roles, aliases)}]) > 0`;
|
|
220
283
|
}
|
|
221
284
|
function stripUndefined(obj) {
|
|
222
285
|
const out = {};
|
|
@@ -225,7 +288,7 @@ function stripUndefined(obj) {
|
|
|
225
288
|
return out;
|
|
226
289
|
}
|
|
227
290
|
const RESERVED_CONDITION_VARS = [
|
|
228
|
-
"
|
|
291
|
+
"fields",
|
|
229
292
|
"actor",
|
|
230
293
|
"assigned",
|
|
231
294
|
"can",
|
|
@@ -346,43 +409,43 @@ function checkGuardNames(def, issues) {
|
|
|
346
409
|
issues
|
|
347
410
|
);
|
|
348
411
|
}
|
|
349
|
-
function
|
|
412
|
+
function fieldScopes(def) {
|
|
350
413
|
const scopes = [
|
|
351
|
-
{ entries: def.
|
|
414
|
+
{ entries: def.fields, scope: "workflow", path: ["fields"], label: "workflow fields" }
|
|
352
415
|
];
|
|
353
416
|
for (const [i, stage] of def.stages.entries()) {
|
|
354
417
|
scopes.push({
|
|
355
|
-
entries: stage.
|
|
418
|
+
entries: stage.fields,
|
|
356
419
|
scope: "stage",
|
|
357
|
-
path: ["stages", i, "
|
|
358
|
-
label: `stage "${stage.name}"
|
|
420
|
+
path: ["stages", i, "fields"],
|
|
421
|
+
label: `stage "${stage.name}" fields`
|
|
359
422
|
});
|
|
360
423
|
for (const [j, task] of (stage.tasks ?? []).entries())
|
|
361
424
|
scopes.push({
|
|
362
|
-
entries: task.
|
|
425
|
+
entries: task.fields,
|
|
363
426
|
scope: "task",
|
|
364
|
-
path: ["stages", i, "tasks", j, "
|
|
365
|
-
label: `task "${task.name}"
|
|
427
|
+
path: ["stages", i, "tasks", j, "fields"],
|
|
428
|
+
label: `task "${task.name}" fields`
|
|
366
429
|
});
|
|
367
430
|
}
|
|
368
431
|
return scopes;
|
|
369
432
|
}
|
|
370
|
-
function
|
|
371
|
-
for (const { entries, scope, path, label } of
|
|
433
|
+
function checkRequiredField(def, issues) {
|
|
434
|
+
for (const { entries, scope, path, label } of fieldScopes(def))
|
|
372
435
|
for (const [n, entry] of (entries ?? []).entries())
|
|
373
436
|
entry.required === !0 && (scope !== "workflow" ? issues.push({
|
|
374
437
|
path: [...path, n, "required"],
|
|
375
438
|
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`
|
|
376
439
|
}) : entry.source.type !== "init" && issues.push({
|
|
377
440
|
path: [...path, n, "required"],
|
|
378
|
-
message: `
|
|
441
|
+
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)`
|
|
379
442
|
}));
|
|
380
443
|
}
|
|
381
|
-
function
|
|
382
|
-
for (const { entries, path, label } of
|
|
444
|
+
function checkFieldEntryNames(def, issues) {
|
|
445
|
+
for (const { entries, path, label } of fieldScopes(def))
|
|
383
446
|
checkDuplicates(
|
|
384
447
|
(entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
|
|
385
|
-
`
|
|
448
|
+
`field entry name in ${label}`,
|
|
386
449
|
issues
|
|
387
450
|
);
|
|
388
451
|
}
|
|
@@ -482,15 +545,15 @@ function collectBindingSites(effects, path, label, sites) {
|
|
|
482
545
|
});
|
|
483
546
|
}
|
|
484
547
|
function checkAssigneesEntries(def, issues) {
|
|
485
|
-
for (const { entries, path } of
|
|
548
|
+
for (const { entries, path } of fieldScopes(def))
|
|
486
549
|
(entries ?? []).filter((e) => e.type === "assignees").length <= 1 || issues.push({
|
|
487
550
|
path,
|
|
488
|
-
message: "at most one assignees-kind
|
|
551
|
+
message: "at most one assignees-kind field entry per scope \u2014 the inbox reads it by kind"
|
|
489
552
|
});
|
|
490
553
|
}
|
|
491
554
|
function checkWorkflowInvariants(def) {
|
|
492
555
|
const issues = [], stageNames = checkStages(def, issues);
|
|
493
|
-
return checkInitialStage(def, stageNames, issues), checkTransitionTargets(def, stageNames, issues), checkEffectNames(def, issues), checkGuardNames(def, issues),
|
|
556
|
+
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), issues;
|
|
494
557
|
}
|
|
495
558
|
function defineWorkflow(definition) {
|
|
496
559
|
const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow(AuthoringWorkflowSchema, definition, label), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
|
|
@@ -509,8 +572,8 @@ function defineAction(action) {
|
|
|
509
572
|
function defineTransition(transition) {
|
|
510
573
|
return parseOrThrow(AuthoringTransitionSchema, transition, transitionLabel(transition));
|
|
511
574
|
}
|
|
512
|
-
function
|
|
513
|
-
return parseOrThrow(
|
|
575
|
+
function defineField(entry) {
|
|
576
|
+
return parseOrThrow(AuthoringFieldEntrySchema, entry, labelFor("defineField", entry));
|
|
514
577
|
}
|
|
515
578
|
function defineOp(op) {
|
|
516
579
|
return parseOrThrow(AuthoringOpSchema, op, "defineOp");
|
|
@@ -546,10 +609,10 @@ export {
|
|
|
546
609
|
defineAction,
|
|
547
610
|
defineEffect,
|
|
548
611
|
defineEffectDescriptor,
|
|
612
|
+
defineField,
|
|
549
613
|
defineGuard,
|
|
550
614
|
defineOp,
|
|
551
615
|
defineStage,
|
|
552
|
-
defineState,
|
|
553
616
|
defineTask,
|
|
554
617
|
defineTransition,
|
|
555
618
|
defineWorkflow,
|