@sanity/workflow-engine 0.9.0 → 0.11.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.
@@ -40,13 +40,13 @@ const TASK_STATUSES = ["pending", "active", "done", "skipped", "failed"], TERMIN
40
40
  function isTerminalTaskStatus(status) {
41
41
  return TERMINAL_TASK_STATUSES.includes(status);
42
42
  }
43
- const STATE_SCOPES = ["workflow", "stage", "task"], DOCUMENT_VALUE_PERMISSIONS = ["create", "read", "update"], MUTATION_GUARD_ACTIONS = [
43
+ const FIELD_SCOPES = ["workflow", "stage", "task"], DOCUMENT_VALUE_PERMISSIONS = ["create", "read", "update"], MUTATION_GUARD_ACTIONS = [
44
44
  "create",
45
45
  "update",
46
46
  "delete",
47
47
  "publish",
48
48
  "unpublish"
49
- ], NonEmpty = v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1, "must be a non-empty string")), PositiveInt = v__namespace.pipe(v__namespace.number(), v__namespace.integer(), v__namespace.minValue(1)), GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
49
+ ], TASK_KINDS = ["user", "service", "script", "manual", "receive"], DRIVER_KINDS = ["person", "agent", "service", "engine"], NonEmpty = v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1, "must be a non-empty string")), PositiveInt = v__namespace.pipe(v__namespace.number(), v__namespace.integer(), v__namespace.minValue(1)), GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
50
50
  function groqIdentifier(referencedAs) {
51
51
  return v__namespace.pipe(
52
52
  v__namespace.string(),
@@ -64,7 +64,7 @@ function picklist(options) {
64
64
  }
65
65
  const SourceSchema = v__namespace.lazy(
66
66
  () => v__namespace.union([
67
- // State-entry origins: who fills the entry, and when.
67
+ // Field-entry origins: who fills the entry, and when.
68
68
  v__namespace.strictObject({ type: v__namespace.literal("init") }),
69
69
  v__namespace.strictObject({ type: v__namespace.literal("write") }),
70
70
  v__namespace.strictObject({
@@ -79,9 +79,9 @@ const SourceSchema = v__namespace.lazy(
79
79
  v__namespace.strictObject({ type: v__namespace.literal("self") }),
80
80
  v__namespace.strictObject({ type: v__namespace.literal("stage") }),
81
81
  v__namespace.strictObject({
82
- type: v__namespace.literal("stateRead"),
82
+ type: v__namespace.literal("fieldRead"),
83
83
  scope: v__namespace.optional(v__namespace.union([v__namespace.literal("workflow"), v__namespace.literal("stage")])),
84
- state: NonEmpty,
84
+ field: NonEmpty,
85
85
  path: v__namespace.optional(v__namespace.string())
86
86
  }),
87
87
  v__namespace.strictObject({
@@ -89,13 +89,32 @@ const SourceSchema = v__namespace.lazy(
89
89
  fields: v__namespace.record(NonEmpty, SourceSchema)
90
90
  })
91
91
  ])
92
- ), StoredStateRefSchema = v__namespace.strictObject({
93
- scope: picklist(STATE_SCOPES),
94
- state: NonEmpty
95
- }), AuthoringStateRefSchema = v__namespace.strictObject({
96
- scope: v__namespace.optional(picklist(STATE_SCOPES)),
97
- state: NonEmpty
98
- }), OpPredicateSchema = v__namespace.lazy(
92
+ ), StoredFieldRefSchema = v__namespace.strictObject({
93
+ scope: picklist(FIELD_SCOPES),
94
+ field: NonEmpty
95
+ }), AuthoringFieldRefSchema = v__namespace.strictObject({
96
+ scope: v__namespace.optional(picklist(FIELD_SCOPES)),
97
+ field: NonEmpty
98
+ }), HREF_SCHEMES = ["http:", "https:"];
99
+ function isHttpUrl(value) {
100
+ try {
101
+ return HREF_SCHEMES.includes(new URL(value).protocol);
102
+ } catch {
103
+ return !1;
104
+ }
105
+ }
106
+ const UrlString = v__namespace.pipe(
107
+ v__namespace.string(),
108
+ v__namespace.url("must be a valid URL"),
109
+ v__namespace.check(isHttpUrl, "must be an http(s) URL")
110
+ );
111
+ function manualTargetSchema(ref) {
112
+ return v__namespace.variant("type", [
113
+ v__namespace.strictObject({ type: v__namespace.literal("url"), url: UrlString }),
114
+ v__namespace.strictObject({ type: v__namespace.literal("field"), field: ref })
115
+ ]);
116
+ }
117
+ const StoredManualTargetSchema = manualTargetSchema(StoredFieldRefSchema), AuthoringManualTargetSchema = manualTargetSchema(v__namespace.union([NonEmpty, AuthoringFieldRefSchema])), OpPredicateSchema = v__namespace.lazy(
99
118
  () => v__namespace.union([
100
119
  v__namespace.strictObject({
101
120
  type: v__namespace.literal("field"),
@@ -109,42 +128,42 @@ const SourceSchema = v__namespace.lazy(
109
128
  function opSchemas(targetSchema) {
110
129
  return [
111
130
  v__namespace.strictObject({
112
- type: v__namespace.literal("state.set"),
131
+ type: v__namespace.literal("field.set"),
113
132
  target: targetSchema,
114
133
  value: SourceSchema
115
134
  }),
116
135
  v__namespace.strictObject({
117
- type: v__namespace.literal("state.unset"),
136
+ type: v__namespace.literal("field.unset"),
118
137
  target: targetSchema
119
138
  }),
120
139
  v__namespace.strictObject({
121
- type: v__namespace.literal("state.append"),
140
+ type: v__namespace.literal("field.append"),
122
141
  target: targetSchema,
123
142
  value: SourceSchema
124
143
  }),
125
144
  v__namespace.strictObject({
126
- type: v__namespace.literal("state.updateWhere"),
145
+ type: v__namespace.literal("field.updateWhere"),
127
146
  target: targetSchema,
128
147
  where: OpPredicateSchema,
129
148
  value: SourceSchema
130
149
  }),
131
150
  v__namespace.strictObject({
132
- type: v__namespace.literal("state.removeWhere"),
151
+ type: v__namespace.literal("field.removeWhere"),
133
152
  target: targetSchema,
134
153
  where: OpPredicateSchema
135
154
  })
136
155
  ];
137
156
  }
138
157
  const StoredOpSchema = v__namespace.variant("type", [
139
- ...opSchemas(StoredStateRefSchema),
158
+ ...opSchemas(StoredFieldRefSchema),
140
159
  v__namespace.strictObject({
141
160
  type: v__namespace.literal("status.set"),
142
161
  task: NonEmpty,
143
162
  status: picklist(TASK_STATUSES)
144
163
  })
145
- ]), StoredTransitionOpSchema = v__namespace.variant("type", [...opSchemas(StoredStateRefSchema)]), AuditOpSchema = v__namespace.strictObject({
164
+ ]), StoredTransitionOpSchema = v__namespace.variant("type", [...opSchemas(StoredFieldRefSchema)]), AuditOpSchema = v__namespace.strictObject({
146
165
  type: v__namespace.literal("audit"),
147
- target: AuthoringStateRefSchema,
166
+ target: AuthoringFieldRefSchema,
148
167
  value: SourceSchema,
149
168
  stampFields: v__namespace.optional(
150
169
  v__namespace.strictObject({
@@ -153,14 +172,14 @@ const StoredOpSchema = v__namespace.variant("type", [
153
172
  })
154
173
  )
155
174
  }), AuthoringOpSchema = v__namespace.variant("type", [
156
- ...opSchemas(AuthoringStateRefSchema),
175
+ ...opSchemas(AuthoringFieldRefSchema),
157
176
  v__namespace.strictObject({
158
177
  type: v__namespace.literal("status.set"),
159
178
  task: v__namespace.optional(NonEmpty),
160
179
  status: picklist(TASK_STATUSES)
161
180
  }),
162
181
  AuditOpSchema
163
- ]), StateKindSchema = picklist([
182
+ ]), FieldKindSchema = picklist([
164
183
  "doc.ref",
165
184
  "doc.refs",
166
185
  // Release reference. A workflow declares this entry to say "I target a
@@ -179,16 +198,16 @@ const StoredOpSchema = v__namespace.variant("type", [
179
198
  // The WHO-FOR entry: the inbox reverse-query reads it by kind, and the
180
199
  // rendered `$assigned` gate matches the caller against it.
181
200
  "assignees"
182
- ]), StateEntryName = groqIdentifier("`$state.<name>`"), StoredEditableSchema = v__namespace.union([v__namespace.literal(!0), NonEmpty]), AuthoringEditableSchema = v__namespace.union([v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty]);
183
- function stateEntryFields(editable) {
201
+ ]), FieldEntryName = groqIdentifier("`$fields.<name>`"), StoredEditableSchema = v__namespace.union([v__namespace.literal(!0), NonEmpty]), AuthoringEditableSchema = v__namespace.union([v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty]);
202
+ function fieldEntryFields(editable) {
184
203
  return {
185
- type: StateKindSchema,
186
- name: StateEntryName,
204
+ type: FieldKindSchema,
205
+ name: FieldEntryName,
187
206
  title: v__namespace.optional(v__namespace.string()),
188
207
  description: v__namespace.optional(v__namespace.string()),
189
208
  /**
190
209
  * When true, the caller MUST supply this entry at start (via
191
- * `initialState`) or spawn (via the parent's `subworkflows.with`). A
210
+ * `initialFields`) or spawn (via the parent's `subworkflows.with`). A
192
211
  * missing required entry throws rather than silently defaulting to
193
212
  * `null`/`[]` — the same fail-fast an action's `required` param gets.
194
213
  * Valid only on a workflow-scope `init`-sourced entry (deploy invariant).
@@ -199,12 +218,12 @@ function stateEntryFields(editable) {
199
218
  editable: v__namespace.optional(editable)
200
219
  };
201
220
  }
202
- const StateEntrySchema = v__namespace.strictObject(stateEntryFields(StoredEditableSchema)), RawAuthoringStateEntrySchema = v__namespace.strictObject(stateEntryFields(AuthoringEditableSchema)), ClaimStateSchema = v__namespace.strictObject({
221
+ const FieldEntrySchema = v__namespace.strictObject(fieldEntryFields(StoredEditableSchema)), RawAuthoringFieldEntrySchema = v__namespace.strictObject(fieldEntryFields(AuthoringEditableSchema)), ClaimFieldSchema = v__namespace.strictObject({
203
222
  type: v__namespace.literal("claim"),
204
- name: StateEntryName,
223
+ name: FieldEntryName,
205
224
  title: v__namespace.optional(v__namespace.string()),
206
225
  description: v__namespace.optional(v__namespace.string())
207
- }), AuthoringStateEntrySchema = v__namespace.union([RawAuthoringStateEntrySchema, ClaimStateSchema]), ConditionSchema = NonEmpty, EffectSchema = v__namespace.strictObject({
226
+ }), AuthoringFieldEntrySchema = v__namespace.union([RawAuthoringFieldEntrySchema, ClaimFieldSchema]), ConditionSchema = NonEmpty, EffectSchema = v__namespace.strictObject({
208
227
  name: NonEmpty,
209
228
  title: v__namespace.optional(v__namespace.string()),
210
229
  description: v__namespace.optional(v__namespace.string()),
@@ -254,7 +273,7 @@ const StoredActionSchema = v__namespace.strictObject(actionFields(StoredOpSchema
254
273
  name: NonEmpty,
255
274
  title: v__namespace.optional(v__namespace.string()),
256
275
  description: v__namespace.optional(v__namespace.string()),
257
- state: v__namespace.union([NonEmpty, AuthoringStateRefSchema]),
276
+ field: v__namespace.union([NonEmpty, AuthoringFieldRefSchema]),
258
277
  roles: v__namespace.optional(v__namespace.array(NonEmpty)),
259
278
  filter: v__namespace.optional(ConditionSchema),
260
279
  params: v__namespace.optional(v__namespace.array(ActionParamSchema)),
@@ -266,7 +285,7 @@ const StoredActionSchema = v__namespace.strictObject(actionFields(StoredOpSchema
266
285
  /** GROQ producing one row per subworkflow; each row binds as `$row`. */
267
286
  forEach: NonEmpty,
268
287
  definition: DefinitionRefSchema,
269
- /** Initial state for each subworkflow — entry name → GROQ over `$row` + the parent scope. */
288
+ /** Initial fields for each subworkflow — entry name → GROQ over `$row` + the parent scope. */
270
289
  with: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
271
290
  /**
272
291
  * Extra values evaluated in the parent's rendered scope at spawn time and
@@ -275,11 +294,21 @@ const StoredActionSchema = v__namespace.strictObject(actionFields(StoredOpSchema
275
294
  */
276
295
  context: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema))
277
296
  });
278
- function taskFields(state, action, op) {
297
+ function taskFields(field, action, op, target) {
279
298
  return {
280
299
  name: NonEmpty,
281
300
  title: v__namespace.optional(v__namespace.string()),
282
301
  description: v__namespace.optional(v__namespace.string()),
302
+ /**
303
+ * Advisory BPMN-aligned classification of this task by its executor (see
304
+ * {@link TASK_KINDS}). Optional and derived from the task's shape when
305
+ * omitted; declaring it lets deploy check the shape matches the lane.
306
+ * Changes no gating or resolution — a label for tooling, like `assignees`.
307
+ */
308
+ kind: v__namespace.optional(picklist(TASK_KINDS)),
309
+ /** Deep-link target for a `kind: "manual"` task (off-system work). Render-only
310
+ * metadata; only valid on a manual task (deploy-checked). */
311
+ target: v__namespace.optional(target),
283
312
  activation: v__namespace.optional(picklist(["auto", "manual"])),
284
313
  filter: v__namespace.optional(ConditionSchema),
285
314
  /**
@@ -308,14 +337,19 @@ function taskFields(state, action, op) {
308
337
  effects: v__namespace.optional(v__namespace.array(EffectSchema)),
309
338
  actions: v__namespace.optional(v__namespace.array(action)),
310
339
  subworkflows: v__namespace.optional(SubworkflowsSchema),
311
- /** Task-scoped state entries. Resolved at task activation time. */
312
- state: v__namespace.optional(v__namespace.array(state))
340
+ /** Task-scoped field entries. Resolved at task activation time. */
341
+ fields: v__namespace.optional(v__namespace.array(field))
313
342
  };
314
343
  }
315
344
  const StoredTaskSchema = v__namespace.strictObject(
316
- taskFields(StateEntrySchema, StoredActionSchema, StoredOpSchema)
345
+ taskFields(FieldEntrySchema, StoredActionSchema, StoredOpSchema, StoredManualTargetSchema)
317
346
  ), AuthoringTaskSchema = v__namespace.strictObject(
318
- taskFields(AuthoringStateEntrySchema, AuthoringActionSchema, AuthoringOpSchema)
347
+ taskFields(
348
+ AuthoringFieldEntrySchema,
349
+ AuthoringActionSchema,
350
+ AuthoringOpSchema,
351
+ AuthoringManualTargetSchema
352
+ )
319
353
  );
320
354
  function transitionFields(op, filter) {
321
355
  return {
@@ -324,7 +358,7 @@ function transitionFields(op, filter) {
324
358
  description: v__namespace.optional(v__namespace.string()),
325
359
  to: NonEmpty,
326
360
  filter,
327
- /** The `state.*` subset — state-write-on-move, the stage's EXIT/ARRIVAL payload. */
361
+ /** The `field.*` subset — field-write-on-move, the stage's EXIT/ARRIVAL payload. */
328
362
  ops: v__namespace.optional(v__namespace.array(op)),
329
363
  effects: v__namespace.optional(v__namespace.array(EffectSchema))
330
364
  };
@@ -332,14 +366,14 @@ function transitionFields(op, filter) {
332
366
  const StoredTransitionSchema = v__namespace.strictObject(
333
367
  transitionFields(StoredTransitionOpSchema, ConditionSchema)
334
368
  ), AuthoringTransitionOpSchema = v__namespace.variant("type", [
335
- ...opSchemas(AuthoringStateRefSchema),
369
+ ...opSchemas(AuthoringFieldRefSchema),
336
370
  AuditOpSchema
337
371
  ]), AuthoringTransitionSchema = v__namespace.strictObject(
338
372
  transitionFields(AuthoringTransitionOpSchema, v__namespace.optional(ConditionSchema))
339
373
  ), GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS), GuardMatchSchema = v__namespace.strictObject({
340
374
  /** Subject `_type`(s); empty matches any type. */
341
375
  types: v__namespace.optional(v__namespace.array(NonEmpty)),
342
- /** Target docs as `$state` reads (or `"$self"`), resolved at deploy to bare ids + the resource. */
376
+ /** Target docs as `$fields` reads (or `"$self"`), resolved at deploy to bare ids + the resource. */
343
377
  idRefs: v__namespace.optional(v__namespace.array(NonEmpty)),
344
378
  /** Glob id patterns (bare, resource-local). */
345
379
  idPatterns: v__namespace.optional(v__namespace.array(NonEmpty)),
@@ -360,16 +394,16 @@ const StoredTransitionSchema = v__namespace.strictObject(
360
394
  */
361
395
  predicate: v__namespace.optional(v__namespace.string()),
362
396
  /**
363
- * Projected workflow state the predicate reads as `guard.metadata.*` —
364
- * the only bridge from the lake eval context (which cannot see `$state`)
365
- * to workflow state. Values are NOT GROQ: each is a deploy-time read in
397
+ * Projected workflow fields the predicate reads as `guard.metadata.*` —
398
+ * the only bridge from the lake eval context (which cannot see `$fields`)
399
+ * to workflow fields. Values are NOT GROQ: each is a deploy-time read in
366
400
  * the guard mini-language — `"$self"`, `"$now"`, or
367
- * `"$state.<name>[.path]"` — resolved into a bare value at deploy and
368
- * re-synced by the post-state-op guard refresh.
401
+ * `"$fields.<name>[.path]"` — resolved into a bare value at deploy and
402
+ * re-synced by the post-field-op guard refresh.
369
403
  */
370
404
  metadata: v__namespace.optional(v__namespace.record(NonEmpty, NonEmpty))
371
405
  });
372
- function stageFields(state, task, transition, editable) {
406
+ function stageFields(field, task, transition, editable) {
373
407
  return {
374
408
  name: NonEmpty,
375
409
  title: v__namespace.optional(v__namespace.string()),
@@ -381,8 +415,8 @@ function stageFields(state, task, transition, editable) {
381
415
  * `temp.system.guard` doc deployed on stage entry and retracted on exit.
382
416
  */
383
417
  guards: v__namespace.optional(v__namespace.array(GuardSchema)),
384
- /** Stage-scoped state entries. Resolved at stage entry. */
385
- state: v__namespace.optional(v__namespace.array(state)),
418
+ /** Stage-scoped field entries. Resolved at stage entry. */
419
+ fields: v__namespace.optional(v__namespace.array(field)),
386
420
  /**
387
421
  * Tighten-only editability overrides for the time this stage holds, keyed
388
422
  * by an in-scope slot name. The slot's own `editable` is the ceiling; a
@@ -390,14 +424,14 @@ function stageFields(state, task, transition, editable) {
390
424
  * (never open a slot the baseline left closed). An unlisted slot inherits
391
425
  * its baseline.
392
426
  */
393
- editable: v__namespace.optional(v__namespace.record(StateEntryName, editable))
427
+ editable: v__namespace.optional(v__namespace.record(FieldEntryName, editable))
394
428
  };
395
429
  }
396
430
  const StoredStageSchema = v__namespace.strictObject(
397
- stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema, StoredEditableSchema)
431
+ stageFields(FieldEntrySchema, StoredTaskSchema, StoredTransitionSchema, StoredEditableSchema)
398
432
  ), AuthoringStageSchema = v__namespace.strictObject(
399
433
  stageFields(
400
- AuthoringStateEntrySchema,
434
+ AuthoringFieldEntrySchema,
401
435
  AuthoringTaskSchema,
402
436
  AuthoringTransitionSchema,
403
437
  AuthoringEditableSchema
@@ -406,7 +440,7 @@ const StoredStageSchema = v__namespace.strictObject(
406
440
  NonEmpty,
407
441
  v__namespace.pipe(v__namespace.array(NonEmpty), v__namespace.minLength(1, "a role alias must list at least one fulfilling role"))
408
442
  ), WORKFLOW_ROLES = ["workflow", "child"];
409
- function workflowFields(state, stage) {
443
+ function workflowFields(field, stage) {
410
444
  return {
411
445
  name: NonEmpty,
412
446
  version: PositiveInt,
@@ -418,14 +452,14 @@ function workflowFields(state, stage) {
418
452
  * never started cold from a picker. Omitted ⇒ `'workflow'` (startable).
419
453
  * Advisory: consumers filter their start pickers on it (see
420
454
  * {@link isStartableDefinition}); the engine does NOT refuse a
421
- * `startInstance` on a `'child'` def — load-bearing `required` state is the
455
+ * `startInstance` on a `'child'` def — load-bearing `required` field is the
422
456
  * runtime backstop.
423
457
  */
424
458
  role: v__namespace.optional(picklist(WORKFLOW_ROLES)),
425
459
  /** Reference field: named for the target, holds the stage's `name`. */
426
460
  initialStage: NonEmpty,
427
- /** Workflow-scope state entries. Persist for the instance lifetime. */
428
- state: v__namespace.optional(v__namespace.array(state)),
461
+ /** Workflow-scope field entries. Persist for the instance lifetime. */
462
+ fields: v__namespace.optional(v__namespace.array(field)),
429
463
  stages: v__namespace.pipe(v__namespace.array(stage), v__namespace.minLength(1, "must declare at least one stage")),
430
464
  /**
431
465
  * Nullary named conditions — each `name: groq` entry is pre-evaluated
@@ -437,9 +471,9 @@ function workflowFields(state, stage) {
437
471
  roleAliases: v__namespace.optional(RoleAliasesSchema)
438
472
  };
439
473
  }
440
- v__namespace.strictObject(workflowFields(StateEntrySchema, StoredStageSchema));
474
+ v__namespace.strictObject(workflowFields(FieldEntrySchema, StoredStageSchema));
441
475
  const AuthoringWorkflowSchema = v__namespace.strictObject(
442
- workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema)
476
+ workflowFields(AuthoringFieldEntrySchema, AuthoringStageSchema)
443
477
  ), WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
444
478
  function isStartableDefinition(definition) {
445
479
  return definition.role !== "child";
@@ -463,16 +497,18 @@ function formatPath(path) {
463
497
  return out;
464
498
  }
465
499
  exports.AuthoringActionSchema = AuthoringActionSchema;
500
+ exports.AuthoringFieldEntrySchema = AuthoringFieldEntrySchema;
466
501
  exports.AuthoringOpSchema = AuthoringOpSchema;
467
502
  exports.AuthoringStageSchema = AuthoringStageSchema;
468
- exports.AuthoringStateEntrySchema = AuthoringStateEntrySchema;
469
503
  exports.AuthoringTaskSchema = AuthoringTaskSchema;
470
504
  exports.AuthoringTransitionSchema = AuthoringTransitionSchema;
471
505
  exports.AuthoringWorkflowSchema = AuthoringWorkflowSchema;
472
506
  exports.DOCUMENT_VALUE_PERMISSIONS = DOCUMENT_VALUE_PERMISSIONS;
507
+ exports.DRIVER_KINDS = DRIVER_KINDS;
473
508
  exports.EffectSchema = EffectSchema;
474
509
  exports.GROQ_IDENTIFIER = GROQ_IDENTIFIER;
475
510
  exports.GuardSchema = GuardSchema;
511
+ exports.TASK_KINDS = TASK_KINDS;
476
512
  exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
477
513
  exports.actorFulfillsRole = actorFulfillsRole;
478
514
  exports.andConditions = andConditions;