@sanity/workflow-engine 0.6.0 → 0.8.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 +33 -1
- package/dist/_chunks-cjs/schema.cjs.map +1 -1
- package/dist/_chunks-es/schema.js +33 -1
- package/dist/_chunks-es/schema.js.map +1 -1
- package/dist/define.cjs +19 -2
- package/dist/define.cjs.map +1 -1
- package/dist/define.d.cts +280 -0
- package/dist/define.d.ts +280 -0
- package/dist/define.js +19 -2
- package/dist/define.js.map +1 -1
- package/dist/index.cjs +467 -241
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +570 -24
- package/dist/index.d.ts +570 -24
- package/dist/index.js +468 -241
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -164,6 +164,14 @@ const StoredOpSchema = v__namespace.variant("type", [
|
|
|
164
164
|
name: StateEntryName,
|
|
165
165
|
title: v__namespace.optional(v__namespace.string()),
|
|
166
166
|
description: v__namespace.optional(v__namespace.string()),
|
|
167
|
+
/**
|
|
168
|
+
* When true, the caller MUST supply this entry at start (via
|
|
169
|
+
* `initialState`) or spawn (via the parent's `subworkflows.with`). A
|
|
170
|
+
* missing required entry throws rather than silently defaulting to
|
|
171
|
+
* `null`/`[]` — the same fail-fast an action's `required` param gets.
|
|
172
|
+
* Valid only on a workflow-scope `init`-sourced entry (deploy invariant).
|
|
173
|
+
*/
|
|
174
|
+
required: v__namespace.optional(v__namespace.boolean()),
|
|
167
175
|
source: SourceSchema
|
|
168
176
|
}), ClaimStateSchema = v__namespace.strictObject({
|
|
169
177
|
type: v__namespace.literal("claim"),
|
|
@@ -248,6 +256,16 @@ function taskFields(state, action, op) {
|
|
|
248
256
|
description: v__namespace.optional(v__namespace.string()),
|
|
249
257
|
activation: v__namespace.optional(picklist(["auto", "manual"])),
|
|
250
258
|
filter: v__namespace.optional(ConditionSchema),
|
|
259
|
+
/**
|
|
260
|
+
* Readiness gates, by name — conditions over the rendered scope that must
|
|
261
|
+
* hold for the task to be *executable*, orthogonal to `filter`
|
|
262
|
+
* (visibility). An unmet requirement keeps the task visible but disables
|
|
263
|
+
* its actions with a `requirements-unmet` verdict naming the unmet keys;
|
|
264
|
+
* all must hold (any-of lives inside one condition). Advisory like every
|
|
265
|
+
* engine gate — the lake still enforces. Distinct from ACL (authorization)
|
|
266
|
+
* and guards (content-write locks).
|
|
267
|
+
*/
|
|
268
|
+
requirements: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
|
|
251
269
|
/**
|
|
252
270
|
* Auto-completion condition — evaluated at activation and on every
|
|
253
271
|
* cascade; truthy flips the task to `done` with a system actor. On a
|
|
@@ -345,13 +363,23 @@ const StoredStageSchema = v__namespace.strictObject(
|
|
|
345
363
|
stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema)
|
|
346
364
|
), AuthoringStageSchema = v__namespace.strictObject(
|
|
347
365
|
stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema)
|
|
348
|
-
);
|
|
366
|
+
), WORKFLOW_ROLES = ["workflow", "child"];
|
|
349
367
|
function workflowFields(state, stage) {
|
|
350
368
|
return {
|
|
351
369
|
name: NonEmpty,
|
|
352
370
|
version: PositiveInt,
|
|
353
371
|
title: NonEmpty,
|
|
354
372
|
description: v__namespace.optional(v__namespace.string()),
|
|
373
|
+
/**
|
|
374
|
+
* Whether a human may start this workflow standalone. `'child'` marks a
|
|
375
|
+
* spawn-only definition — instantiated by a parent via `task.subworkflows`,
|
|
376
|
+
* never started cold from a picker. Omitted ⇒ `'workflow'` (startable).
|
|
377
|
+
* Advisory: consumers filter their start pickers on it (see
|
|
378
|
+
* {@link isStartableDefinition}); the engine does NOT refuse a
|
|
379
|
+
* `startInstance` on a `'child'` def — load-bearing `required` state is the
|
|
380
|
+
* runtime backstop.
|
|
381
|
+
*/
|
|
382
|
+
role: v__namespace.optional(picklist(WORKFLOW_ROLES)),
|
|
355
383
|
/** Reference field: named for the target, holds the stage's `name`. */
|
|
356
384
|
initialStage: NonEmpty,
|
|
357
385
|
/** Workflow-scope state entries. Persist for the instance lifetime. */
|
|
@@ -369,6 +397,9 @@ v__namespace.strictObject(workflowFields(StateEntrySchema, StoredStageSchema));
|
|
|
369
397
|
const AuthoringWorkflowSchema = v__namespace.strictObject(
|
|
370
398
|
workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema)
|
|
371
399
|
), WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
|
|
400
|
+
function isStartableDefinition(definition) {
|
|
401
|
+
return definition.role !== "child";
|
|
402
|
+
}
|
|
372
403
|
function formatValidationError(label, issues) {
|
|
373
404
|
const lines = issues.map((issue) => ` - ${issue.path.length === 0 ? "(root)" : formatPath(issue.path)}: ${issue.message}`);
|
|
374
405
|
return `${label} failed validation (${issues.length} issue${issues.length === 1 ? "" : "s"}):
|
|
@@ -400,6 +431,7 @@ exports.GROQ_IDENTIFIER = GROQ_IDENTIFIER;
|
|
|
400
431
|
exports.GuardSchema = GuardSchema;
|
|
401
432
|
exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
|
|
402
433
|
exports.formatValidationError = formatValidationError;
|
|
434
|
+
exports.isStartableDefinition = isStartableDefinition;
|
|
403
435
|
exports.isTerminalTaskStatus = isTerminalTaskStatus;
|
|
404
436
|
exports.issuesFromValibot = issuesFromValibot;
|
|
405
437
|
//# sourceMappingURL=schema.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.cjs","sources":["../../src/types/enums.ts","../../src/define/schema.ts"],"sourcesContent":["/**\n * Leaf enums — the const arrays (and their derived union types) that both\n * the authoring schema and the engine address by name.\n *\n * This module imports nothing. It is the schema-free foundation that\n * `../define/schema.ts` reads its value constants from, which is what keeps\n * the type model and the valibot schema free of an import cycle: the value edge\n * `schema.ts → enums.ts` terminates here.\n */\n\n// Task status — used by instance state. The authored action `status:` sugar\n// (and the `status.set` op it desugars to) is constrained to the terminal\n// subset below.\nexport const TASK_STATUSES = ['pending', 'active', 'done', 'skipped', 'failed'] as const\nexport type TaskStatus = (typeof TASK_STATUSES)[number]\n\n// The statuses a task can be resolved INTO — what `status.set` accepts and\n// what stops blocking the `$allTasksDone` gate family.\nexport const TERMINAL_TASK_STATUSES = ['done', 'skipped', 'failed'] as const\nexport type TerminalTaskStatus = (typeof TERMINAL_TASK_STATUSES)[number]\n\nexport function isTerminalTaskStatus(status: TaskStatus): status is TerminalTaskStatus {\n return (TERMINAL_TASK_STATUSES as readonly TaskStatus[]).includes(status)\n}\n\n// The three state scopes a state entry can live in. Authoring (`ScopeKey`,\n// `stateRead` sources) and the engine both address state entries by scope.\nexport const STATE_SCOPES = ['workflow', 'stage', 'task'] as const\nexport type StateScope = (typeof STATE_SCOPES)[number]\n\n// Document-value permissions. Grants (`Grant` in ./authorization.ts) compose\n// most-permissive-wins.\nexport const DOCUMENT_VALUE_PERMISSIONS = ['create', 'read', 'update'] as const\nexport type DocumentValuePermission = (typeof DOCUMENT_VALUE_PERMISSIONS)[number]\n\n// Mutation-guard actions — the lake operations a guard can gate. See the\n// guard types in ./authorization.ts.\nexport const MUTATION_GUARD_ACTIONS = [\n 'create',\n 'update',\n 'delete',\n 'publish',\n 'unpublish',\n] as const\nexport type MutationGuardAction = (typeof MUTATION_GUARD_ACTIONS)[number]\n","/**\n * Valibot schemas for the workflow authoring surface — the things a workflow\n * author writes by hand and feeds to `defineWorkflow`. Types in this\n * file are the **canonical** authoring types: they are inferred from\n * the schemas, so the runtime schema and the compile-time type cannot\n * drift.\n *\n * Two layers live here, mirroring the design model (generic stored data,\n * sugar that compiles away):\n *\n * - **Stored** schemas (`WorkflowDefinitionSchema`, `OpSchema`, …) describe\n * the primitives the engine persists. No sugar variants, every state\n * reference carries an explicit resolved `scope`.\n * - **Authoring** schemas (`AuthoringWorkflowSchema`, …) accept the same\n * primitives **plus** define-time sugar: the `claim` state/action pair,\n * the `audit` op, the `roles` and `status` action fields, omitted\n * transition filters, omitted reference scopes. `desugar.ts` expands\n * authoring input into the stored shape.\n *\n * Strictness: every object schema is `v.strictObject` so unknown keys\n * produce a parse error. That catches typos like `verison: 1` at deploy\n * time — and it is also what enforces each sugar contract's *reserved*\n * fields (an `ops:` on a `claim` action is an unknown key, fail loud).\n */\n\nimport * as v from 'valibot'\n\nimport {\n MUTATION_GUARD_ACTIONS,\n STATE_SCOPES,\n TASK_STATUSES,\n TERMINAL_TASK_STATUSES,\n} from '../types/enums.ts'\n\nconst NonEmpty = v.pipe(v.string(), v.minLength(1, 'must be a non-empty string'))\n\nconst PositiveInt = v.pipe(v.number(), v.integer(), v.minValue(1))\n\n/**\n * Names that get spliced into GROQ — state entries (`$state.<name>` in the\n * claim no-steal filter and every condition) and predicate keys (`$<name>`).\n * A name like `review-owner` would parse as subtraction inside GROQ and\n * silently change the expression's meaning, so these are constrained to\n * GROQ-identifier-safe names. See {@link GROQ_IDENTIFIER}.\n */\nexport const GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction groqIdentifier(referencedAs: string) {\n return v.pipe(\n v.string(),\n v.regex(\n GROQ_IDENTIFIER,\n `must be a GROQ-safe identifier (letters, digits, underscore; not starting with a digit) ` +\n `because it is referenced as ${referencedAs} in GROQ conditions`,\n ),\n )\n}\n\n/**\n * Picklist with a zod-compatible \"Invalid option\" message that lists every\n * allowed value, so a typo'd discriminator or enum lands with a message an\n * author can act on (e.g. `Invalid option: expected one of \"done\"|\"skipped\"`).\n */\nfunction picklist<const TOptions extends readonly [string, ...string[]]>(options: TOptions) {\n return v.picklist(\n options,\n `Invalid option: expected one of ${options.map((o) => `\"${o}\"`).join('|')}`,\n )\n}\n\n// Source — the single \"where a value comes from\" union, shared by state-entry\n// origins and op payloads. Conditions and effect bindings are NOT Sources —\n// they are GROQ strings over the rendered scope ($state, $actor, $row, …).\n// Each value variant has a rendered $-twin (actor ↔ $actor, now ↔ $now) so\n// learning one side teaches the other.\n\ntype SourceInternal =\n | {type: 'init'}\n | {type: 'write'}\n | {type: 'query'; query: string}\n | {type: 'literal'; value: unknown}\n | {type: 'param'; param: string}\n | {type: 'actor'}\n | {type: 'now'}\n | {type: 'self'}\n | {type: 'stage'}\n | {\n type: 'stateRead'\n scope?: 'workflow' | 'stage' | undefined\n state: string\n path?: string | undefined\n }\n | {type: 'object'; fields: Record<string, SourceInternal>}\n\nconst SourceSchema: v.GenericSchema<SourceInternal> = v.lazy(() =>\n v.union([\n // State-entry origins: who fills the entry, and when.\n v.strictObject({type: v.literal('init')}),\n v.strictObject({type: v.literal('write')}),\n v.strictObject({\n type: v.literal('query'),\n query: NonEmpty,\n }),\n // Value sources: resolved to concrete JSON when an op or seed applies.\n v.strictObject({type: v.literal('literal'), value: v.unknown()}),\n v.strictObject({type: v.literal('param'), param: NonEmpty}),\n v.strictObject({type: v.literal('actor')}),\n v.strictObject({type: v.literal('now')}),\n v.strictObject({type: v.literal('self')}),\n v.strictObject({type: v.literal('stage')}),\n v.strictObject({\n type: v.literal('stateRead'),\n scope: v.optional(v.union([v.literal('workflow'), v.literal('stage')])),\n state: NonEmpty,\n path: v.optional(v.string()),\n }),\n v.strictObject({\n type: v.literal('object'),\n fields: v.record(NonEmpty, SourceSchema),\n }),\n ]),\n)\nexport type Source = SourceInternal\n\n// State references — `{ scope?, state }` addressing a state entry by name.\n// Authoring may omit `scope`; desugar resolves it lexically (task → stage →\n// workflow), so the STORED form always carries an explicit scope.\n\nconst StoredStateRefSchema = v.strictObject({\n scope: picklist(STATE_SCOPES),\n state: NonEmpty,\n})\nexport type StoredStateRef = v.InferOutput<typeof StoredStateRefSchema>\n\nconst AuthoringStateRefSchema = v.strictObject({\n scope: v.optional(picklist(STATE_SCOPES)),\n state: NonEmpty,\n})\nexport type AuthoringStateRef = v.InferOutput<typeof AuthoringStateRefSchema>\n\n// Op predicates — small typed predicate for state.updateWhere /\n// state.removeWhere. Runs in the pure in-memory op path, so it stays a\n// typed structure rather than GROQ. Discriminated by `type` like every union.\n\ntype OpPredicateInternal =\n | {type: 'field'; field: string; equals: Source}\n | {type: 'all'; of: OpPredicateInternal[]}\n | {type: 'any'; of: OpPredicateInternal[]}\n\nconst OpPredicateSchema: v.GenericSchema<OpPredicateInternal> = v.lazy(() =>\n v.union([\n v.strictObject({\n type: v.literal('field'),\n field: NonEmpty,\n equals: SourceSchema,\n }),\n v.strictObject({type: v.literal('all'), of: v.array(OpPredicateSchema)}),\n v.strictObject({type: v.literal('any'), of: v.array(OpPredicateSchema)}),\n ]),\n)\nexport type OpPredicate = OpPredicateInternal\n\n// Ops — the six stored mutation primitives. `value` is the one payload key.\n// `status.set` may name a sibling task; desugar fills the firing task when\n// authoring omitted it, so the stored op always carries `task`.\n\nfunction opSchemas<T extends v.GenericSchema>(targetSchema: T) {\n return [\n v.strictObject({\n type: v.literal('state.set'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.unset'),\n target: targetSchema,\n }),\n v.strictObject({\n type: v.literal('state.append'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.updateWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.removeWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n }),\n ] as const\n}\n\nconst StoredOpSchema = v.variant('type', [\n ...opSchemas(StoredStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: NonEmpty,\n status: picklist(TASK_STATUSES),\n }),\n])\nexport type Op = v.InferOutput<typeof StoredOpSchema>\n\n/**\n * The `state.*` subset a transition may carry — `status.set` has no coherent\n * task target while the stage's tasks tear down, so the engine rejects it\n * at parse time rather than dropping it silently.\n */\nconst StoredTransitionOpSchema = v.variant('type', [...opSchemas(StoredStateRefSchema)])\nexport type TransitionOp = v.InferOutput<typeof StoredTransitionOpSchema>\n\n// Authoring ops: scope optional on targets, `task` optional on status.set\n// (defaults to the firing task), plus the `audit` sugar type — a stamped\n// append whose expansion merges `actor`/`at` Source fields into its own value.\n\nconst AuditOpSchema = v.strictObject({\n type: v.literal('audit'),\n target: AuthoringStateRefSchema,\n value: SourceSchema,\n stampFields: v.optional(\n v.strictObject({\n actor: v.optional(NonEmpty),\n at: v.optional(NonEmpty),\n }),\n ),\n})\n\nexport const AuthoringOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: v.optional(NonEmpty),\n status: picklist(TASK_STATUSES),\n }),\n AuditOpSchema,\n])\nexport type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>\n\n// State entries — the generic stored data. Kinds are bare: a discriminator is\n// unique within its union; namespaces live only on engine-owned lake document\n// `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the instance type).\n\nconst StateKindSchema = picklist([\n 'doc.ref',\n 'doc.refs',\n // Release reference. A workflow declares this entry to say \"I target a\n // Content Release\"; the runtime fills it at start time and auto-derives\n // the instance's read perspective from it.\n 'release.ref',\n 'query',\n 'value.string',\n 'value.url',\n 'value.number',\n 'value.boolean',\n 'value.dateTime',\n 'value.actor',\n 'checklist',\n 'notes',\n // The WHO-FOR entry: the inbox reverse-query reads it by kind, and the\n // rendered `$assigned` gate matches the caller against it.\n 'assignees',\n])\n\nconst StateEntryName = groqIdentifier('`$state.<name>`')\n\nconst StateEntrySchema = v.strictObject({\n type: StateKindSchema,\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n source: SourceSchema,\n})\nexport type StateEntry = v.InferOutput<typeof StateEntrySchema>\n\n/**\n * Authoring state accepts the raw entries plus the `claim` sugar type — the\n * state half of the mirrored claim pair. Expansion: `value.actor` with an\n * implied `write` source, strictly within this entry.\n */\nconst ClaimStateSchema = v.strictObject({\n type: v.literal('claim'),\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n})\n\nexport const AuthoringStateEntrySchema = v.union([StateEntrySchema, ClaimStateSchema])\nexport type AuthoringStateEntry = v.InferOutput<typeof AuthoringStateEntrySchema>\n\n// Conditions are raw GROQ strings over the rendered scope — built-in vars\n// ($state, $actor, $assigned, $can, $row, $effects, $subworkflows, $tasks,\n// $now, $allTasksDone, $anyTaskFailed) plus the author's nullary predicates.\n// There is no {ref, args} wrapper; parameterized reuse is a define-time\n// TypeScript function (see the `groq` tag in ./groq.ts).\n\nconst ConditionSchema = NonEmpty\nexport type Condition = string\n\n// Effects — the registry model. `name` is the effect's only identity; the\n// host app registers a handler against it (1:1) and the stored definition\n// never references code. Names are unique per definition (invariant) so\n// `$effects.<name>` is unambiguous.\n\nexport const EffectSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */\n bindings: v.optional(v.record(v.string(), ConditionSchema)),\n /** Static config, passed through to the handler verbatim. */\n input: v.optional(v.record(v.string(), v.unknown())),\n})\nexport type Effect = v.InferOutput<typeof EffectSchema>\n\n// Actions\n\n/**\n * Caller-supplied params declared on an action. The engine validates\n * incoming `params` against this list before running ops or queuing\n * effects: missing required params → ActionParamsInvalidError, action\n * does not commit. Resolved values feed `Source.param` lookups.\n */\nconst ActionParamSchema = v.strictObject({\n type: picklist([\n 'string',\n 'number',\n 'boolean',\n 'url',\n 'dateTime',\n 'actor',\n 'doc.ref',\n 'doc.refs',\n 'json',\n ]),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n required: v.optional(v.boolean()),\n})\nexport type ActionParam = v.InferOutput<typeof ActionParamSchema>\n\n/** Fields shared by the stored and authoring action shapes, parameterised\n * over the op schema (stored ops are fully resolved; authoring ops keep\n * their sugar). */\nfunction actionFields<Op extends v.GenericSchema>(op: Op) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * The one gate mechanism: a condition over the rendered scope. Hard\n * enforcement lives outside the engine entirely (the lake ACL on the\n * documents, and guards) — every engine-evaluated gate is authoring/UX.\n */\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredActionSchema = v.strictObject(actionFields(StoredOpSchema))\nexport type Action = v.InferOutput<typeof StoredActionSchema>\n\nconst TerminalTaskStatus = picklist(TERMINAL_TASK_STATUSES)\n\n/**\n * Authoring action — the stored fields plus two field sugars with one\n * defined expansion each:\n *\n * - `roles` → a `count($actor.roles[@ in [...]]) > 0` membership condition\n * ANDed with the authored `filter`.\n * - `status` → a `status.set` op on the firing task, appended **after**\n * the authored ops (deliberately never implied: a forgotten explicit\n * `status` is a visible stall, an implied default silently completes\n * claim-like actions).\n */\nconst RawAuthoringActionSchema = v.strictObject({\n ...actionFields(AuthoringOpSchema),\n roles: v.optional(v.array(NonEmpty)),\n status: v.optional(TerminalTaskStatus),\n})\n\n/**\n * The action half of the mirrored claim pair. `state` references an\n * author-declared actor-valued entry (the pair's other half), resolved\n * lexically. Expansion, strictly within this action: a no-steal\n * `!defined($state.<state>)` filter ANDed with `roles`/`filter`, plus a\n * `state.set` ← actor op. `ops` and `status` are reserved (the expansion\n * owns them) — strictObject rejects them as unknown keys.\n */\nconst ClaimActionSchema = v.strictObject({\n type: v.literal('claim'),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n state: v.union([NonEmpty, AuthoringStateRefSchema]),\n roles: v.optional(v.array(NonEmpty)),\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n effects: v.optional(v.array(EffectSchema)),\n})\n\nexport const AuthoringActionSchema = v.union([RawAuthoringActionSchema, ClaimActionSchema])\nexport type AuthoringAction = v.InferOutput<typeof AuthoringActionSchema>\n\n// Subworkflows — declare `subworkflows`, read `$subworkflows`. The spawning\n// task resolves like any task: `completeWhen` / `failWhen` over the rendered\n// `$subworkflows`; no `completeWhen` means all subworkflows done.\n\n/**\n * Logical reference to a deployed workflow definition, by its `name` (the\n * stable contract — the tag can be renamed, workflows redeployed). The engine\n * resolves it at spawn time, ordering by `version desc` unless an explicit\n * `version` pins one.\n */\nconst DefinitionRefSchema = v.strictObject({\n name: NonEmpty,\n version: v.optional(v.union([PositiveInt, v.literal('latest')])),\n})\n\nconst SubworkflowsSchema = v.strictObject({\n /** GROQ producing one row per subworkflow; each row binds as `$row`. */\n forEach: NonEmpty,\n definition: DefinitionRefSchema,\n /** Initial state for each subworkflow — entry name → GROQ over `$row` + the parent scope. */\n with: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Extra values evaluated in the parent's rendered scope at spawn time and\n * delivered into each subworkflow's `$effects` bag — the parent→child\n * handoff, read exactly like an effect output.\n */\n context: v.optional(v.record(NonEmpty, ConditionSchema)),\n})\nexport type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>\n\n// Tasks — tasks own the ENTER moment: `ops` + `effects` run at activation,\n// `filter` makes activation conditional on the stage's entry state, and\n// `activation` switches the stage-enter flip (default `manual`: a task never\n// activates silently; \"auto\" is the explicit opt-in). A task with no actions\n// and no `completeWhen` is a machine step — it runs its activation payload\n// and resolves `done` immediately, leaving an audit row.\n\nfunction taskFields<\n TState extends v.GenericSchema,\n TAction extends v.GenericSchema,\n TOp extends v.GenericSchema,\n>(state: TState, action: TAction, op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n activation: v.optional(picklist(['auto', 'manual'])),\n filter: v.optional(ConditionSchema),\n /**\n * Auto-completion condition — evaluated at activation and on every\n * cascade; truthy flips the task to `done` with a system actor. On a\n * spawning task it typically reads `$subworkflows`.\n */\n completeWhen: v.optional(ConditionSchema),\n /**\n * Auto-failure condition — symmetric to `completeWhen`, flips to\n * `failed`. When both are truthy on the same evaluation, `failWhen`\n * wins — failure is the more notable signal.\n */\n failWhen: v.optional(ConditionSchema),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n actions: v.optional(v.array(action)),\n subworkflows: v.optional(SubworkflowsSchema),\n /** Task-scoped state entries. Resolved at task activation time. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredTaskSchema = v.strictObject(\n taskFields(StateEntrySchema, StoredActionSchema, StoredOpSchema),\n)\nexport type Task = v.InferOutput<typeof StoredTaskSchema>\n\nexport const AuthoringTaskSchema = v.strictObject(\n taskFields(AuthoringStateEntrySchema, AuthoringActionSchema, AuthoringOpSchema),\n)\nexport type AuthoringTask = v.InferOutput<typeof AuthoringTaskSchema>\n\n// Transitions — purely a condition over the rendered scope. Selection rule:\n// every transition is evaluated on every commit and cascade; the first truthy\n// `filter` in declaration order fires. No action coupling: a routing\n// difference is written into state by the action and read by the filter.\n\nfunction transitionFields<TOp extends v.GenericSchema, TFilter extends v.GenericSchema>(\n op: TOp,\n filter: TFilter,\n) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n to: NonEmpty,\n filter,\n /** The `state.*` subset — state-write-on-move, the stage's EXIT/ARRIVAL payload. */\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredTransitionSchema = v.strictObject(\n transitionFields(StoredTransitionOpSchema, ConditionSchema),\n)\nexport type Transition = v.InferOutput<typeof StoredTransitionSchema>\n\n/**\n * Authoring transitions may omit `filter`; desugar fills the safe,\n * overwhelmingly-common gate `\"$allTasksDone\"`. \"Fire unconditionally\"\n * stays spellable as an explicit `filter: \"true\"`.\n */\nconst AuthoringTransitionOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n AuditOpSchema,\n])\nexport const AuthoringTransitionSchema = v.strictObject(\n transitionFields(AuthoringTransitionOpSchema, v.optional(ConditionSchema)),\n)\nexport type AuthoringTransition = v.InferOutput<typeof AuthoringTransitionSchema>\n\n// Guards — lake mutation guards. A FOREIGN CONTRACT mirrored 1:1: the\n// `temp.system.guard` doc's `match` / `predicate` / `metadata` fields are the\n// content lake's API, not engine surface, so authoring keeps the lake's\n// vocabulary verbatim. The engine adds exactly two things: `name` (authoring\n// identity — the lake `_id` derives from (instanceId, guard.name)) and\n// `$state`-read VALUES (`idRefs: [\"$state.subject\"]`, `metadata.outcome:\n// \"$state.outcome\"`), resolved at deploy into the bare values the contract\n// expects. Guards + the lake ACL are the only HARD gates in the system.\n\nconst GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS)\nexport type GuardAction = v.InferOutput<typeof GuardActionSchema>\n\nconst GuardMatchSchema = v.strictObject({\n /** Subject `_type`(s); empty matches any type. */\n types: v.optional(v.array(NonEmpty)),\n /** Target docs as `$state` reads (or `\"$self\"`), resolved at deploy to bare ids + the resource. */\n idRefs: v.optional(v.array(NonEmpty)),\n /** Glob id patterns (bare, resource-local). */\n idPatterns: v.optional(v.array(NonEmpty)),\n actions: v.pipe(\n v.array(GuardActionSchema),\n v.minLength(1, 'a guard must match at least one action'),\n ),\n})\nexport type GuardMatch = v.InferOutput<typeof GuardMatchSchema>\n\nexport const GuardSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n match: GuardMatchSchema,\n /**\n * Lake GROQ predicate — a distinct eval context reading\n * `document.before`/`document.after`, `mutation`, `guard`, and\n * `identity()`. Bare ids/fields only. Omitted or empty means\n * UNCONDITIONAL DENY.\n */\n predicate: v.optional(v.string()),\n /**\n * Projected workflow state the predicate reads as `guard.metadata.*` —\n * the only bridge from the lake eval context (which cannot see `$state`)\n * to workflow state. Values are NOT GROQ: each is a deploy-time read in\n * the guard mini-language — `\"$self\"`, `\"$now\"`, or\n * `\"$state.<name>[.path]\"` — resolved into a bare value at deploy and\n * re-synced by the post-state-op guard refresh.\n */\n metadata: v.optional(v.record(NonEmpty, NonEmpty)),\n})\nexport type Guard = v.InferOutput<typeof GuardSchema>\n\n// Stages — pure containers: name / state / guards / tasks / transitions, no\n// behaviour of their own. Tasks own enter, transitions own exit and arrival.\n// `initial` is whatever `initialStage` names; a stage with no transitions IS\n// terminal (structural, nothing to declare or mis-declare).\n\nfunction stageFields<\n TState extends v.GenericSchema,\n TTask extends v.GenericSchema,\n TTransition extends v.GenericSchema,\n>(state: TState, task: TTask, transition: TTransition) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n tasks: v.optional(v.array(task)),\n transitions: v.optional(v.array(transition)),\n /**\n * Lake mutation guards active while this stage holds. Each compiles to a\n * `temp.system.guard` doc deployed on stage entry and retracted on exit.\n */\n guards: v.optional(v.array(GuardSchema)),\n /** Stage-scoped state entries. Resolved at stage entry. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredStageSchema = v.strictObject(\n stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema),\n)\nexport type Stage = v.InferOutput<typeof StoredStageSchema>\n\nexport const AuthoringStageSchema = v.strictObject(\n stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema),\n)\nexport type AuthoringStage = v.InferOutput<typeof AuthoringStageSchema>\n\n// Workflow definition (the root)\n\nfunction workflowFields<TState extends v.GenericSchema, TStage extends v.GenericSchema>(\n state: TState,\n stage: TStage,\n) {\n return {\n name: NonEmpty,\n version: PositiveInt,\n title: NonEmpty,\n description: v.optional(v.string()),\n /** Reference field: named for the target, holds the stage's `name`. */\n initialStage: NonEmpty,\n /** Workflow-scope state entries. Persist for the instance lifetime. */\n state: v.optional(v.array(state)),\n stages: v.pipe(v.array(stage), v.minLength(1, 'must declare at least one stage')),\n /**\n * Nullary named conditions — each `name: groq` entry is pre-evaluated\n * and bound as the boolean `$name` var, composable with native GROQ.\n * Redefining a built-in var is a deploy error (never silently shadow).\n */\n predicates: v.optional(v.record(groqIdentifier('`$<name>`'), ConditionSchema)),\n }\n}\n\n/**\n * Structural schema for a STORED workflow definition — primitives only,\n * every reference scope resolved. Cross-field invariants (unique names,\n * transition targets, effect-name uniqueness, predicate shadowing) are\n * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.\n */\nconst WorkflowDefinitionSchema = v.strictObject(workflowFields(StateEntrySchema, StoredStageSchema))\nexport type WorkflowDefinition = v.InferOutput<typeof WorkflowDefinitionSchema>\n\n/** The authoring surface: stored primitives plus the define-time sugar. */\nexport const AuthoringWorkflowSchema = v.strictObject(\n workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema),\n)\nexport type AuthoringWorkflow = v.InferOutput<typeof AuthoringWorkflowSchema>\n\n/**\n * The lake document type for a deployed workflow definition. Engine-owned\n * standalone documents carry the platform namespace; in-array discriminators\n * stay bare. Mirrors {@link WORKFLOW_INSTANCE_TYPE}.\n */\nexport const WORKFLOW_DEFINITION_TYPE = 'sanity.workflow.definition'\n\n// Error formatting — turn validation issues into a multi-line,\n// path-prefixed message that points at the exact field the author got\n// wrong. Shared by structural parse errors (via {@link issuesFromValibot})\n// and cross-field invariant issues.\n\nexport interface ValidationIssue {\n path: ReadonlyArray<PropertyKey>\n message: string\n}\n\n/** The buildable path form desugar and the invariants accumulate issues under. */\nexport type IssuePath = (string | number)[]\n\nexport function formatValidationError(label: string, issues: readonly ValidationIssue[]): string {\n const lines = issues.map((issue) => {\n const path = issue.path.length === 0 ? '(root)' : formatPath(issue.path)\n return ` - ${path}: ${issue.message}`\n })\n return `${label} failed validation (${issues.length} issue${\n issues.length === 1 ? '' : 's'\n }):\\n${lines.join('\\n')}`\n}\n\nexport function issuesFromValibot(issues: readonly v.BaseIssue<unknown>[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? issue.path.map((item) => item.key as PropertyKey) : [],\n message: issue.message,\n }))\n}\n\nfunction formatPath(path: ReadonlyArray<PropertyKey>): string {\n let out = ''\n for (const seg of path) {\n if (typeof seg === 'number') out += `[${seg}]`\n else out += out.length === 0 ? String(seg) : `.${String(seg)}`\n }\n return out\n}\n"],"names":["v"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.cjs","sources":["../../src/types/enums.ts","../../src/define/schema.ts"],"sourcesContent":["/**\n * Leaf enums — the const arrays (and their derived union types) that both\n * the authoring schema and the engine address by name.\n *\n * This module imports nothing. It is the schema-free foundation that\n * `../define/schema.ts` reads its value constants from, which is what keeps\n * the type model and the valibot schema free of an import cycle: the value edge\n * `schema.ts → enums.ts` terminates here.\n */\n\n// Task status — used by instance state. The authored action `status:` sugar\n// (and the `status.set` op it desugars to) is constrained to the terminal\n// subset below.\nexport const TASK_STATUSES = ['pending', 'active', 'done', 'skipped', 'failed'] as const\nexport type TaskStatus = (typeof TASK_STATUSES)[number]\n\n// The statuses a task can be resolved INTO — what `status.set` accepts and\n// what stops blocking the `$allTasksDone` gate family.\nexport const TERMINAL_TASK_STATUSES = ['done', 'skipped', 'failed'] as const\nexport type TerminalTaskStatus = (typeof TERMINAL_TASK_STATUSES)[number]\n\nexport function isTerminalTaskStatus(status: TaskStatus): status is TerminalTaskStatus {\n return (TERMINAL_TASK_STATUSES as readonly TaskStatus[]).includes(status)\n}\n\n// The three state scopes a state entry can live in. Authoring (`ScopeKey`,\n// `stateRead` sources) and the engine both address state entries by scope.\nexport const STATE_SCOPES = ['workflow', 'stage', 'task'] as const\nexport type StateScope = (typeof STATE_SCOPES)[number]\n\n// Document-value permissions. Grants (`Grant` in ./authorization.ts) compose\n// most-permissive-wins.\nexport const DOCUMENT_VALUE_PERMISSIONS = ['create', 'read', 'update'] as const\nexport type DocumentValuePermission = (typeof DOCUMENT_VALUE_PERMISSIONS)[number]\n\n// Mutation-guard actions — the lake operations a guard can gate. See the\n// guard types in ./authorization.ts.\nexport const MUTATION_GUARD_ACTIONS = [\n 'create',\n 'update',\n 'delete',\n 'publish',\n 'unpublish',\n] as const\nexport type MutationGuardAction = (typeof MUTATION_GUARD_ACTIONS)[number]\n","/**\n * Valibot schemas for the workflow authoring surface — the things a workflow\n * author writes by hand and feeds to `defineWorkflow`. Types in this\n * file are the **canonical** authoring types: they are inferred from\n * the schemas, so the runtime schema and the compile-time type cannot\n * drift.\n *\n * Two layers live here, mirroring the design model (generic stored data,\n * sugar that compiles away):\n *\n * - **Stored** schemas (`WorkflowDefinitionSchema`, `OpSchema`, …) describe\n * the primitives the engine persists. No sugar variants, every state\n * reference carries an explicit resolved `scope`.\n * - **Authoring** schemas (`AuthoringWorkflowSchema`, …) accept the same\n * primitives **plus** define-time sugar: the `claim` state/action pair,\n * the `audit` op, the `roles` and `status` action fields, omitted\n * transition filters, omitted reference scopes. `desugar.ts` expands\n * authoring input into the stored shape.\n *\n * Strictness: every object schema is `v.strictObject` so unknown keys\n * produce a parse error. That catches typos like `verison: 1` at deploy\n * time — and it is also what enforces each sugar contract's *reserved*\n * fields (an `ops:` on a `claim` action is an unknown key, fail loud).\n */\n\nimport * as v from 'valibot'\n\nimport {\n MUTATION_GUARD_ACTIONS,\n STATE_SCOPES,\n TASK_STATUSES,\n TERMINAL_TASK_STATUSES,\n} from '../types/enums.ts'\n\nconst NonEmpty = v.pipe(v.string(), v.minLength(1, 'must be a non-empty string'))\n\nconst PositiveInt = v.pipe(v.number(), v.integer(), v.minValue(1))\n\n/**\n * Names that get spliced into GROQ — state entries (`$state.<name>` in the\n * claim no-steal filter and every condition) and predicate keys (`$<name>`).\n * A name like `review-owner` would parse as subtraction inside GROQ and\n * silently change the expression's meaning, so these are constrained to\n * GROQ-identifier-safe names. See {@link GROQ_IDENTIFIER}.\n */\nexport const GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction groqIdentifier(referencedAs: string) {\n return v.pipe(\n v.string(),\n v.regex(\n GROQ_IDENTIFIER,\n `must be a GROQ-safe identifier (letters, digits, underscore; not starting with a digit) ` +\n `because it is referenced as ${referencedAs} in GROQ conditions`,\n ),\n )\n}\n\n/**\n * Picklist with a zod-compatible \"Invalid option\" message that lists every\n * allowed value, so a typo'd discriminator or enum lands with a message an\n * author can act on (e.g. `Invalid option: expected one of \"done\"|\"skipped\"`).\n */\nfunction picklist<const TOptions extends readonly [string, ...string[]]>(options: TOptions) {\n return v.picklist(\n options,\n `Invalid option: expected one of ${options.map((o) => `\"${o}\"`).join('|')}`,\n )\n}\n\n// Source — the single \"where a value comes from\" union, shared by state-entry\n// origins and op payloads. Conditions and effect bindings are NOT Sources —\n// they are GROQ strings over the rendered scope ($state, $actor, $row, …).\n// Each value variant has a rendered $-twin (actor ↔ $actor, now ↔ $now) so\n// learning one side teaches the other.\n\ntype SourceInternal =\n | {type: 'init'}\n | {type: 'write'}\n | {type: 'query'; query: string}\n | {type: 'literal'; value: unknown}\n | {type: 'param'; param: string}\n | {type: 'actor'}\n | {type: 'now'}\n | {type: 'self'}\n | {type: 'stage'}\n | {\n type: 'stateRead'\n scope?: 'workflow' | 'stage' | undefined\n state: string\n path?: string | undefined\n }\n | {type: 'object'; fields: Record<string, SourceInternal>}\n\nconst SourceSchema: v.GenericSchema<SourceInternal> = v.lazy(() =>\n v.union([\n // State-entry origins: who fills the entry, and when.\n v.strictObject({type: v.literal('init')}),\n v.strictObject({type: v.literal('write')}),\n v.strictObject({\n type: v.literal('query'),\n query: NonEmpty,\n }),\n // Value sources: resolved to concrete JSON when an op or seed applies.\n v.strictObject({type: v.literal('literal'), value: v.unknown()}),\n v.strictObject({type: v.literal('param'), param: NonEmpty}),\n v.strictObject({type: v.literal('actor')}),\n v.strictObject({type: v.literal('now')}),\n v.strictObject({type: v.literal('self')}),\n v.strictObject({type: v.literal('stage')}),\n v.strictObject({\n type: v.literal('stateRead'),\n scope: v.optional(v.union([v.literal('workflow'), v.literal('stage')])),\n state: NonEmpty,\n path: v.optional(v.string()),\n }),\n v.strictObject({\n type: v.literal('object'),\n fields: v.record(NonEmpty, SourceSchema),\n }),\n ]),\n)\nexport type Source = SourceInternal\n\n// State references — `{ scope?, state }` addressing a state entry by name.\n// Authoring may omit `scope`; desugar resolves it lexically (task → stage →\n// workflow), so the STORED form always carries an explicit scope.\n\nconst StoredStateRefSchema = v.strictObject({\n scope: picklist(STATE_SCOPES),\n state: NonEmpty,\n})\nexport type StoredStateRef = v.InferOutput<typeof StoredStateRefSchema>\n\nconst AuthoringStateRefSchema = v.strictObject({\n scope: v.optional(picklist(STATE_SCOPES)),\n state: NonEmpty,\n})\nexport type AuthoringStateRef = v.InferOutput<typeof AuthoringStateRefSchema>\n\n// Op predicates — small typed predicate for state.updateWhere /\n// state.removeWhere. Runs in the pure in-memory op path, so it stays a\n// typed structure rather than GROQ. Discriminated by `type` like every union.\n\ntype OpPredicateInternal =\n | {type: 'field'; field: string; equals: Source}\n | {type: 'all'; of: OpPredicateInternal[]}\n | {type: 'any'; of: OpPredicateInternal[]}\n\nconst OpPredicateSchema: v.GenericSchema<OpPredicateInternal> = v.lazy(() =>\n v.union([\n v.strictObject({\n type: v.literal('field'),\n field: NonEmpty,\n equals: SourceSchema,\n }),\n v.strictObject({type: v.literal('all'), of: v.array(OpPredicateSchema)}),\n v.strictObject({type: v.literal('any'), of: v.array(OpPredicateSchema)}),\n ]),\n)\nexport type OpPredicate = OpPredicateInternal\n\n// Ops — the six stored mutation primitives. `value` is the one payload key.\n// `status.set` may name a sibling task; desugar fills the firing task when\n// authoring omitted it, so the stored op always carries `task`.\n\nfunction opSchemas<T extends v.GenericSchema>(targetSchema: T) {\n return [\n v.strictObject({\n type: v.literal('state.set'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.unset'),\n target: targetSchema,\n }),\n v.strictObject({\n type: v.literal('state.append'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.updateWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.removeWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n }),\n ] as const\n}\n\nconst StoredOpSchema = v.variant('type', [\n ...opSchemas(StoredStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: NonEmpty,\n status: picklist(TASK_STATUSES),\n }),\n])\nexport type Op = v.InferOutput<typeof StoredOpSchema>\n\n/**\n * The `state.*` subset a transition may carry — `status.set` has no coherent\n * task target while the stage's tasks tear down, so the engine rejects it\n * at parse time rather than dropping it silently.\n */\nconst StoredTransitionOpSchema = v.variant('type', [...opSchemas(StoredStateRefSchema)])\nexport type TransitionOp = v.InferOutput<typeof StoredTransitionOpSchema>\n\n// Authoring ops: scope optional on targets, `task` optional on status.set\n// (defaults to the firing task), plus the `audit` sugar type — a stamped\n// append whose expansion merges `actor`/`at` Source fields into its own value.\n\nconst AuditOpSchema = v.strictObject({\n type: v.literal('audit'),\n target: AuthoringStateRefSchema,\n value: SourceSchema,\n stampFields: v.optional(\n v.strictObject({\n actor: v.optional(NonEmpty),\n at: v.optional(NonEmpty),\n }),\n ),\n})\n\nexport const AuthoringOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: v.optional(NonEmpty),\n status: picklist(TASK_STATUSES),\n }),\n AuditOpSchema,\n])\nexport type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>\n\n// State entries — the generic stored data. Kinds are bare: a discriminator is\n// unique within its union; namespaces live only on engine-owned lake document\n// `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the instance type).\n\nconst StateKindSchema = picklist([\n 'doc.ref',\n 'doc.refs',\n // Release reference. A workflow declares this entry to say \"I target a\n // Content Release\"; the runtime fills it at start time and auto-derives\n // the instance's read perspective from it.\n 'release.ref',\n 'query',\n 'value.string',\n 'value.url',\n 'value.number',\n 'value.boolean',\n 'value.dateTime',\n 'value.actor',\n 'checklist',\n 'notes',\n // The WHO-FOR entry: the inbox reverse-query reads it by kind, and the\n // rendered `$assigned` gate matches the caller against it.\n 'assignees',\n])\n\nconst StateEntryName = groqIdentifier('`$state.<name>`')\n\nconst StateEntrySchema = v.strictObject({\n type: StateKindSchema,\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * When true, the caller MUST supply this entry at start (via\n * `initialState`) or spawn (via the parent's `subworkflows.with`). A\n * missing required entry throws rather than silently defaulting to\n * `null`/`[]` — the same fail-fast an action's `required` param gets.\n * Valid only on a workflow-scope `init`-sourced entry (deploy invariant).\n */\n required: v.optional(v.boolean()),\n source: SourceSchema,\n})\nexport type StateEntry = v.InferOutput<typeof StateEntrySchema>\n\n/**\n * Authoring state accepts the raw entries plus the `claim` sugar type — the\n * state half of the mirrored claim pair. Expansion: `value.actor` with an\n * implied `write` source, strictly within this entry.\n */\nconst ClaimStateSchema = v.strictObject({\n type: v.literal('claim'),\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n})\n\nexport const AuthoringStateEntrySchema = v.union([StateEntrySchema, ClaimStateSchema])\nexport type AuthoringStateEntry = v.InferOutput<typeof AuthoringStateEntrySchema>\n\n// Conditions are raw GROQ strings over the rendered scope — built-in vars\n// ($state, $actor, $assigned, $can, $row, $effects, $subworkflows, $tasks,\n// $now, $allTasksDone, $anyTaskFailed) plus the author's nullary predicates.\n// There is no {ref, args} wrapper; parameterized reuse is a define-time\n// TypeScript function (see the `groq` tag in ./groq.ts).\n\nconst ConditionSchema = NonEmpty\nexport type Condition = string\n\n// Effects — the registry model. `name` is the effect's only identity; the\n// host app registers a handler against it (1:1) and the stored definition\n// never references code. Names are unique per definition (invariant) so\n// `$effects.<name>` is unambiguous.\n\nexport const EffectSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */\n bindings: v.optional(v.record(v.string(), ConditionSchema)),\n /** Static config, passed through to the handler verbatim. */\n input: v.optional(v.record(v.string(), v.unknown())),\n})\nexport type Effect = v.InferOutput<typeof EffectSchema>\n\n// Actions\n\n/**\n * Caller-supplied params declared on an action. The engine validates\n * incoming `params` against this list before running ops or queuing\n * effects: missing required params → ActionParamsInvalidError, action\n * does not commit. Resolved values feed `Source.param` lookups.\n */\nconst ActionParamSchema = v.strictObject({\n type: picklist([\n 'string',\n 'number',\n 'boolean',\n 'url',\n 'dateTime',\n 'actor',\n 'doc.ref',\n 'doc.refs',\n 'json',\n ]),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n required: v.optional(v.boolean()),\n})\nexport type ActionParam = v.InferOutput<typeof ActionParamSchema>\n\n/** Fields shared by the stored and authoring action shapes, parameterised\n * over the op schema (stored ops are fully resolved; authoring ops keep\n * their sugar). */\nfunction actionFields<TOp extends v.GenericSchema>(op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * The one gate mechanism: a condition over the rendered scope. Hard\n * enforcement lives outside the engine entirely (the lake ACL on the\n * documents, and guards) — every engine-evaluated gate is authoring/UX.\n */\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredActionSchema = v.strictObject(actionFields(StoredOpSchema))\nexport type Action = v.InferOutput<typeof StoredActionSchema>\n\nconst TerminalTaskStatus = picklist(TERMINAL_TASK_STATUSES)\n\n/**\n * Authoring action — the stored fields plus two field sugars with one\n * defined expansion each:\n *\n * - `roles` → a `count($actor.roles[@ in [...]]) > 0` membership condition\n * ANDed with the authored `filter`.\n * - `status` → a `status.set` op on the firing task, appended **after**\n * the authored ops (deliberately never implied: a forgotten explicit\n * `status` is a visible stall, an implied default silently completes\n * claim-like actions).\n */\nconst RawAuthoringActionSchema = v.strictObject({\n ...actionFields(AuthoringOpSchema),\n roles: v.optional(v.array(NonEmpty)),\n status: v.optional(TerminalTaskStatus),\n})\n\n/**\n * The action half of the mirrored claim pair. `state` references an\n * author-declared actor-valued entry (the pair's other half), resolved\n * lexically. Expansion, strictly within this action: a no-steal\n * `!defined($state.<state>)` filter ANDed with `roles`/`filter`, plus a\n * `state.set` ← actor op. `ops` and `status` are reserved (the expansion\n * owns them) — strictObject rejects them as unknown keys.\n */\nconst ClaimActionSchema = v.strictObject({\n type: v.literal('claim'),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n state: v.union([NonEmpty, AuthoringStateRefSchema]),\n roles: v.optional(v.array(NonEmpty)),\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n effects: v.optional(v.array(EffectSchema)),\n})\n\nexport const AuthoringActionSchema = v.union([RawAuthoringActionSchema, ClaimActionSchema])\nexport type AuthoringAction = v.InferOutput<typeof AuthoringActionSchema>\n\n// Subworkflows — declare `subworkflows`, read `$subworkflows`. The spawning\n// task resolves like any task: `completeWhen` / `failWhen` over the rendered\n// `$subworkflows`; no `completeWhen` means all subworkflows done.\n\n/**\n * Logical reference to a deployed workflow definition, by its `name` (the\n * stable contract — the tag can be renamed, workflows redeployed). The engine\n * resolves it at spawn time, ordering by `version desc` unless an explicit\n * `version` pins one.\n */\nconst DefinitionRefSchema = v.strictObject({\n name: NonEmpty,\n version: v.optional(v.union([PositiveInt, v.literal('latest')])),\n})\n\nconst SubworkflowsSchema = v.strictObject({\n /** GROQ producing one row per subworkflow; each row binds as `$row`. */\n forEach: NonEmpty,\n definition: DefinitionRefSchema,\n /** Initial state for each subworkflow — entry name → GROQ over `$row` + the parent scope. */\n with: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Extra values evaluated in the parent's rendered scope at spawn time and\n * delivered into each subworkflow's `$effects` bag — the parent→child\n * handoff, read exactly like an effect output.\n */\n context: v.optional(v.record(NonEmpty, ConditionSchema)),\n})\nexport type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>\n\n// Tasks — tasks own the ENTER moment: `ops` + `effects` run at activation,\n// `filter` makes activation conditional on the stage's entry state, and\n// `activation` switches the stage-enter flip (default `manual`: a task never\n// activates silently; \"auto\" is the explicit opt-in). A task with no actions\n// and no `completeWhen` is a machine step — it runs its activation payload\n// and resolves `done` immediately, leaving an audit row.\n\nfunction taskFields<\n TState extends v.GenericSchema,\n TAction extends v.GenericSchema,\n TOp extends v.GenericSchema,\n>(state: TState, action: TAction, op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n activation: v.optional(picklist(['auto', 'manual'])),\n filter: v.optional(ConditionSchema),\n /**\n * Readiness gates, by name — conditions over the rendered scope that must\n * hold for the task to be *executable*, orthogonal to `filter`\n * (visibility). An unmet requirement keeps the task visible but disables\n * its actions with a `requirements-unmet` verdict naming the unmet keys;\n * all must hold (any-of lives inside one condition). Advisory like every\n * engine gate — the lake still enforces. Distinct from ACL (authorization)\n * and guards (content-write locks).\n */\n requirements: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Auto-completion condition — evaluated at activation and on every\n * cascade; truthy flips the task to `done` with a system actor. On a\n * spawning task it typically reads `$subworkflows`.\n */\n completeWhen: v.optional(ConditionSchema),\n /**\n * Auto-failure condition — symmetric to `completeWhen`, flips to\n * `failed`. When both are truthy on the same evaluation, `failWhen`\n * wins — failure is the more notable signal.\n */\n failWhen: v.optional(ConditionSchema),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n actions: v.optional(v.array(action)),\n subworkflows: v.optional(SubworkflowsSchema),\n /** Task-scoped state entries. Resolved at task activation time. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredTaskSchema = v.strictObject(\n taskFields(StateEntrySchema, StoredActionSchema, StoredOpSchema),\n)\nexport type Task = v.InferOutput<typeof StoredTaskSchema>\n\nexport const AuthoringTaskSchema = v.strictObject(\n taskFields(AuthoringStateEntrySchema, AuthoringActionSchema, AuthoringOpSchema),\n)\nexport type AuthoringTask = v.InferOutput<typeof AuthoringTaskSchema>\n\n// Transitions — purely a condition over the rendered scope. Selection rule:\n// every transition is evaluated on every commit and cascade; the first truthy\n// `filter` in declaration order fires. No action coupling: a routing\n// difference is written into state by the action and read by the filter.\n\nfunction transitionFields<TOp extends v.GenericSchema, TFilter extends v.GenericSchema>(\n op: TOp,\n filter: TFilter,\n) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n to: NonEmpty,\n filter,\n /** The `state.*` subset — state-write-on-move, the stage's EXIT/ARRIVAL payload. */\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredTransitionSchema = v.strictObject(\n transitionFields(StoredTransitionOpSchema, ConditionSchema),\n)\nexport type Transition = v.InferOutput<typeof StoredTransitionSchema>\n\n/**\n * Authoring transitions may omit `filter`; desugar fills the safe,\n * overwhelmingly-common gate `\"$allTasksDone\"`. \"Fire unconditionally\"\n * stays spellable as an explicit `filter: \"true\"`.\n */\nconst AuthoringTransitionOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n AuditOpSchema,\n])\nexport const AuthoringTransitionSchema = v.strictObject(\n transitionFields(AuthoringTransitionOpSchema, v.optional(ConditionSchema)),\n)\nexport type AuthoringTransition = v.InferOutput<typeof AuthoringTransitionSchema>\n\n// Guards — lake mutation guards. A FOREIGN CONTRACT mirrored 1:1: the\n// `temp.system.guard` doc's `match` / `predicate` / `metadata` fields are the\n// content lake's API, not engine surface, so authoring keeps the lake's\n// vocabulary verbatim. The engine adds exactly two things: `name` (authoring\n// identity — the lake `_id` derives from (instanceId, guard.name)) and\n// `$state`-read VALUES (`idRefs: [\"$state.subject\"]`, `metadata.outcome:\n// \"$state.outcome\"`), resolved at deploy into the bare values the contract\n// expects. Guards + the lake ACL are the only HARD gates in the system.\n\nconst GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS)\nexport type GuardAction = v.InferOutput<typeof GuardActionSchema>\n\nconst GuardMatchSchema = v.strictObject({\n /** Subject `_type`(s); empty matches any type. */\n types: v.optional(v.array(NonEmpty)),\n /** Target docs as `$state` reads (or `\"$self\"`), resolved at deploy to bare ids + the resource. */\n idRefs: v.optional(v.array(NonEmpty)),\n /** Glob id patterns (bare, resource-local). */\n idPatterns: v.optional(v.array(NonEmpty)),\n actions: v.pipe(\n v.array(GuardActionSchema),\n v.minLength(1, 'a guard must match at least one action'),\n ),\n})\nexport type GuardMatch = v.InferOutput<typeof GuardMatchSchema>\n\nexport const GuardSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n match: GuardMatchSchema,\n /**\n * Lake GROQ predicate — a distinct eval context reading\n * `document.before`/`document.after`, `mutation`, `guard`, and\n * `identity()`. Bare ids/fields only. Omitted or empty means\n * UNCONDITIONAL DENY.\n */\n predicate: v.optional(v.string()),\n /**\n * Projected workflow state the predicate reads as `guard.metadata.*` —\n * the only bridge from the lake eval context (which cannot see `$state`)\n * to workflow state. Values are NOT GROQ: each is a deploy-time read in\n * the guard mini-language — `\"$self\"`, `\"$now\"`, or\n * `\"$state.<name>[.path]\"` — resolved into a bare value at deploy and\n * re-synced by the post-state-op guard refresh.\n */\n metadata: v.optional(v.record(NonEmpty, NonEmpty)),\n})\nexport type Guard = v.InferOutput<typeof GuardSchema>\n\n// Stages — pure containers: name / state / guards / tasks / transitions, no\n// behaviour of their own. Tasks own enter, transitions own exit and arrival.\n// `initial` is whatever `initialStage` names; a stage with no transitions IS\n// terminal (structural, nothing to declare or mis-declare).\n\nfunction stageFields<\n TState extends v.GenericSchema,\n TTask extends v.GenericSchema,\n TTransition extends v.GenericSchema,\n>(state: TState, task: TTask, transition: TTransition) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n tasks: v.optional(v.array(task)),\n transitions: v.optional(v.array(transition)),\n /**\n * Lake mutation guards active while this stage holds. Each compiles to a\n * `temp.system.guard` doc deployed on stage entry and retracted on exit.\n */\n guards: v.optional(v.array(GuardSchema)),\n /** Stage-scoped state entries. Resolved at stage entry. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredStageSchema = v.strictObject(\n stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema),\n)\nexport type Stage = v.InferOutput<typeof StoredStageSchema>\n\nexport const AuthoringStageSchema = v.strictObject(\n stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema),\n)\nexport type AuthoringStage = v.InferOutput<typeof AuthoringStageSchema>\n\n// Workflow definition (the root)\n\nconst WORKFLOW_ROLES = ['workflow', 'child'] as const\n/** A definition's lifecycle role. `'child'` is spawn-only — see {@link isStartableDefinition}. */\nexport type WorkflowRole = (typeof WORKFLOW_ROLES)[number]\n\nfunction workflowFields<TState extends v.GenericSchema, TStage extends v.GenericSchema>(\n state: TState,\n stage: TStage,\n) {\n return {\n name: NonEmpty,\n version: PositiveInt,\n title: NonEmpty,\n description: v.optional(v.string()),\n /**\n * Whether a human may start this workflow standalone. `'child'` marks a\n * spawn-only definition — instantiated by a parent via `task.subworkflows`,\n * never started cold from a picker. Omitted ⇒ `'workflow'` (startable).\n * Advisory: consumers filter their start pickers on it (see\n * {@link isStartableDefinition}); the engine does NOT refuse a\n * `startInstance` on a `'child'` def — load-bearing `required` state is the\n * runtime backstop.\n */\n role: v.optional(picklist(WORKFLOW_ROLES)),\n /** Reference field: named for the target, holds the stage's `name`. */\n initialStage: NonEmpty,\n /** Workflow-scope state entries. Persist for the instance lifetime. */\n state: v.optional(v.array(state)),\n stages: v.pipe(v.array(stage), v.minLength(1, 'must declare at least one stage')),\n /**\n * Nullary named conditions — each `name: groq` entry is pre-evaluated\n * and bound as the boolean `$name` var, composable with native GROQ.\n * Redefining a built-in var is a deploy error (never silently shadow).\n */\n predicates: v.optional(v.record(groqIdentifier('`$<name>`'), ConditionSchema)),\n }\n}\n\n/**\n * Structural schema for a STORED workflow definition — primitives only,\n * every reference scope resolved. Cross-field invariants (unique names,\n * transition targets, effect-name uniqueness, predicate shadowing) are\n * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.\n */\nconst WorkflowDefinitionSchema = v.strictObject(workflowFields(StateEntrySchema, StoredStageSchema))\nexport type WorkflowDefinition = v.InferOutput<typeof WorkflowDefinitionSchema>\n\n/** The authoring surface: stored primitives plus the define-time sugar. */\nexport const AuthoringWorkflowSchema = v.strictObject(\n workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema),\n)\nexport type AuthoringWorkflow = v.InferOutput<typeof AuthoringWorkflowSchema>\n\n/**\n * The lake document type for a deployed workflow definition. Engine-owned\n * standalone documents carry the platform namespace; in-array discriminators\n * stay bare. Mirrors {@link WORKFLOW_INSTANCE_TYPE}.\n */\nexport const WORKFLOW_DEFINITION_TYPE = 'sanity.workflow.definition'\n\n/**\n * Whether a human may start this definition standalone (the default). A\n * `role: 'child'` definition is spawn-only — instantiated by a parent via\n * `task.subworkflows`, so consumers exclude it from top-level start pickers.\n * Advisory: the engine does not enforce it (see the `required`-state backstop\n * for load-bearing init slots). Accepts any definition-shaped value (authored,\n * stored, deployed, or a projected list row).\n */\nexport function isStartableDefinition(definition: {role?: WorkflowRole | undefined}): boolean {\n return definition.role !== 'child'\n}\n\n// Error formatting — turn validation issues into a multi-line,\n// path-prefixed message that points at the exact field the author got\n// wrong. Shared by structural parse errors (via {@link issuesFromValibot})\n// and cross-field invariant issues.\n\nexport interface ValidationIssue {\n path: ReadonlyArray<PropertyKey>\n message: string\n}\n\n/** The buildable path form desugar and the invariants accumulate issues under. */\nexport type IssuePath = (string | number)[]\n\nexport function formatValidationError(label: string, issues: readonly ValidationIssue[]): string {\n const lines = issues.map((issue) => {\n const path = issue.path.length === 0 ? '(root)' : formatPath(issue.path)\n return ` - ${path}: ${issue.message}`\n })\n return `${label} failed validation (${issues.length} issue${\n issues.length === 1 ? '' : 's'\n }):\\n${lines.join('\\n')}`\n}\n\nexport function issuesFromValibot(issues: readonly v.BaseIssue<unknown>[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? issue.path.map((item) => item.key as PropertyKey) : [],\n message: issue.message,\n }))\n}\n\nfunction formatPath(path: ReadonlyArray<PropertyKey>): string {\n let out = ''\n for (const seg of path) {\n if (typeof seg === 'number') out += `[${seg}]`\n else out += out.length === 0 ? String(seg) : `.${String(seg)}`\n }\n return out\n}\n"],"names":["v"],"mappings":"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"}
|
|
@@ -147,6 +147,14 @@ const StoredOpSchema = v.variant("type", [
|
|
|
147
147
|
name: StateEntryName,
|
|
148
148
|
title: v.optional(v.string()),
|
|
149
149
|
description: v.optional(v.string()),
|
|
150
|
+
/**
|
|
151
|
+
* When true, the caller MUST supply this entry at start (via
|
|
152
|
+
* `initialState`) or spawn (via the parent's `subworkflows.with`). A
|
|
153
|
+
* missing required entry throws rather than silently defaulting to
|
|
154
|
+
* `null`/`[]` — the same fail-fast an action's `required` param gets.
|
|
155
|
+
* Valid only on a workflow-scope `init`-sourced entry (deploy invariant).
|
|
156
|
+
*/
|
|
157
|
+
required: v.optional(v.boolean()),
|
|
150
158
|
source: SourceSchema
|
|
151
159
|
}), ClaimStateSchema = v.strictObject({
|
|
152
160
|
type: v.literal("claim"),
|
|
@@ -231,6 +239,16 @@ function taskFields(state, action, op) {
|
|
|
231
239
|
description: v.optional(v.string()),
|
|
232
240
|
activation: v.optional(picklist(["auto", "manual"])),
|
|
233
241
|
filter: v.optional(ConditionSchema),
|
|
242
|
+
/**
|
|
243
|
+
* Readiness gates, by name — conditions over the rendered scope that must
|
|
244
|
+
* hold for the task to be *executable*, orthogonal to `filter`
|
|
245
|
+
* (visibility). An unmet requirement keeps the task visible but disables
|
|
246
|
+
* its actions with a `requirements-unmet` verdict naming the unmet keys;
|
|
247
|
+
* all must hold (any-of lives inside one condition). Advisory like every
|
|
248
|
+
* engine gate — the lake still enforces. Distinct from ACL (authorization)
|
|
249
|
+
* and guards (content-write locks).
|
|
250
|
+
*/
|
|
251
|
+
requirements: v.optional(v.record(NonEmpty, ConditionSchema)),
|
|
234
252
|
/**
|
|
235
253
|
* Auto-completion condition — evaluated at activation and on every
|
|
236
254
|
* cascade; truthy flips the task to `done` with a system actor. On a
|
|
@@ -328,13 +346,23 @@ const StoredStageSchema = v.strictObject(
|
|
|
328
346
|
stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema)
|
|
329
347
|
), AuthoringStageSchema = v.strictObject(
|
|
330
348
|
stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema)
|
|
331
|
-
);
|
|
349
|
+
), WORKFLOW_ROLES = ["workflow", "child"];
|
|
332
350
|
function workflowFields(state, stage) {
|
|
333
351
|
return {
|
|
334
352
|
name: NonEmpty,
|
|
335
353
|
version: PositiveInt,
|
|
336
354
|
title: NonEmpty,
|
|
337
355
|
description: v.optional(v.string()),
|
|
356
|
+
/**
|
|
357
|
+
* Whether a human may start this workflow standalone. `'child'` marks a
|
|
358
|
+
* spawn-only definition — instantiated by a parent via `task.subworkflows`,
|
|
359
|
+
* never started cold from a picker. Omitted ⇒ `'workflow'` (startable).
|
|
360
|
+
* Advisory: consumers filter their start pickers on it (see
|
|
361
|
+
* {@link isStartableDefinition}); the engine does NOT refuse a
|
|
362
|
+
* `startInstance` on a `'child'` def — load-bearing `required` state is the
|
|
363
|
+
* runtime backstop.
|
|
364
|
+
*/
|
|
365
|
+
role: v.optional(picklist(WORKFLOW_ROLES)),
|
|
338
366
|
/** Reference field: named for the target, holds the stage's `name`. */
|
|
339
367
|
initialStage: NonEmpty,
|
|
340
368
|
/** Workflow-scope state entries. Persist for the instance lifetime. */
|
|
@@ -352,6 +380,9 @@ v.strictObject(workflowFields(StateEntrySchema, StoredStageSchema));
|
|
|
352
380
|
const AuthoringWorkflowSchema = v.strictObject(
|
|
353
381
|
workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema)
|
|
354
382
|
), WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
|
|
383
|
+
function isStartableDefinition(definition) {
|
|
384
|
+
return definition.role !== "child";
|
|
385
|
+
}
|
|
355
386
|
function formatValidationError(label, issues) {
|
|
356
387
|
const lines = issues.map((issue) => ` - ${issue.path.length === 0 ? "(root)" : formatPath(issue.path)}: ${issue.message}`);
|
|
357
388
|
return `${label} failed validation (${issues.length} issue${issues.length === 1 ? "" : "s"}):
|
|
@@ -384,6 +415,7 @@ export {
|
|
|
384
415
|
GuardSchema,
|
|
385
416
|
WORKFLOW_DEFINITION_TYPE,
|
|
386
417
|
formatValidationError,
|
|
418
|
+
isStartableDefinition,
|
|
387
419
|
isTerminalTaskStatus,
|
|
388
420
|
issuesFromValibot
|
|
389
421
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sources":["../../src/types/enums.ts","../../src/define/schema.ts"],"sourcesContent":["/**\n * Leaf enums — the const arrays (and their derived union types) that both\n * the authoring schema and the engine address by name.\n *\n * This module imports nothing. It is the schema-free foundation that\n * `../define/schema.ts` reads its value constants from, which is what keeps\n * the type model and the valibot schema free of an import cycle: the value edge\n * `schema.ts → enums.ts` terminates here.\n */\n\n// Task status — used by instance state. The authored action `status:` sugar\n// (and the `status.set` op it desugars to) is constrained to the terminal\n// subset below.\nexport const TASK_STATUSES = ['pending', 'active', 'done', 'skipped', 'failed'] as const\nexport type TaskStatus = (typeof TASK_STATUSES)[number]\n\n// The statuses a task can be resolved INTO — what `status.set` accepts and\n// what stops blocking the `$allTasksDone` gate family.\nexport const TERMINAL_TASK_STATUSES = ['done', 'skipped', 'failed'] as const\nexport type TerminalTaskStatus = (typeof TERMINAL_TASK_STATUSES)[number]\n\nexport function isTerminalTaskStatus(status: TaskStatus): status is TerminalTaskStatus {\n return (TERMINAL_TASK_STATUSES as readonly TaskStatus[]).includes(status)\n}\n\n// The three state scopes a state entry can live in. Authoring (`ScopeKey`,\n// `stateRead` sources) and the engine both address state entries by scope.\nexport const STATE_SCOPES = ['workflow', 'stage', 'task'] as const\nexport type StateScope = (typeof STATE_SCOPES)[number]\n\n// Document-value permissions. Grants (`Grant` in ./authorization.ts) compose\n// most-permissive-wins.\nexport const DOCUMENT_VALUE_PERMISSIONS = ['create', 'read', 'update'] as const\nexport type DocumentValuePermission = (typeof DOCUMENT_VALUE_PERMISSIONS)[number]\n\n// Mutation-guard actions — the lake operations a guard can gate. See the\n// guard types in ./authorization.ts.\nexport const MUTATION_GUARD_ACTIONS = [\n 'create',\n 'update',\n 'delete',\n 'publish',\n 'unpublish',\n] as const\nexport type MutationGuardAction = (typeof MUTATION_GUARD_ACTIONS)[number]\n","/**\n * Valibot schemas for the workflow authoring surface — the things a workflow\n * author writes by hand and feeds to `defineWorkflow`. Types in this\n * file are the **canonical** authoring types: they are inferred from\n * the schemas, so the runtime schema and the compile-time type cannot\n * drift.\n *\n * Two layers live here, mirroring the design model (generic stored data,\n * sugar that compiles away):\n *\n * - **Stored** schemas (`WorkflowDefinitionSchema`, `OpSchema`, …) describe\n * the primitives the engine persists. No sugar variants, every state\n * reference carries an explicit resolved `scope`.\n * - **Authoring** schemas (`AuthoringWorkflowSchema`, …) accept the same\n * primitives **plus** define-time sugar: the `claim` state/action pair,\n * the `audit` op, the `roles` and `status` action fields, omitted\n * transition filters, omitted reference scopes. `desugar.ts` expands\n * authoring input into the stored shape.\n *\n * Strictness: every object schema is `v.strictObject` so unknown keys\n * produce a parse error. That catches typos like `verison: 1` at deploy\n * time — and it is also what enforces each sugar contract's *reserved*\n * fields (an `ops:` on a `claim` action is an unknown key, fail loud).\n */\n\nimport * as v from 'valibot'\n\nimport {\n MUTATION_GUARD_ACTIONS,\n STATE_SCOPES,\n TASK_STATUSES,\n TERMINAL_TASK_STATUSES,\n} from '../types/enums.ts'\n\nconst NonEmpty = v.pipe(v.string(), v.minLength(1, 'must be a non-empty string'))\n\nconst PositiveInt = v.pipe(v.number(), v.integer(), v.minValue(1))\n\n/**\n * Names that get spliced into GROQ — state entries (`$state.<name>` in the\n * claim no-steal filter and every condition) and predicate keys (`$<name>`).\n * A name like `review-owner` would parse as subtraction inside GROQ and\n * silently change the expression's meaning, so these are constrained to\n * GROQ-identifier-safe names. See {@link GROQ_IDENTIFIER}.\n */\nexport const GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction groqIdentifier(referencedAs: string) {\n return v.pipe(\n v.string(),\n v.regex(\n GROQ_IDENTIFIER,\n `must be a GROQ-safe identifier (letters, digits, underscore; not starting with a digit) ` +\n `because it is referenced as ${referencedAs} in GROQ conditions`,\n ),\n )\n}\n\n/**\n * Picklist with a zod-compatible \"Invalid option\" message that lists every\n * allowed value, so a typo'd discriminator or enum lands with a message an\n * author can act on (e.g. `Invalid option: expected one of \"done\"|\"skipped\"`).\n */\nfunction picklist<const TOptions extends readonly [string, ...string[]]>(options: TOptions) {\n return v.picklist(\n options,\n `Invalid option: expected one of ${options.map((o) => `\"${o}\"`).join('|')}`,\n )\n}\n\n// Source — the single \"where a value comes from\" union, shared by state-entry\n// origins and op payloads. Conditions and effect bindings are NOT Sources —\n// they are GROQ strings over the rendered scope ($state, $actor, $row, …).\n// Each value variant has a rendered $-twin (actor ↔ $actor, now ↔ $now) so\n// learning one side teaches the other.\n\ntype SourceInternal =\n | {type: 'init'}\n | {type: 'write'}\n | {type: 'query'; query: string}\n | {type: 'literal'; value: unknown}\n | {type: 'param'; param: string}\n | {type: 'actor'}\n | {type: 'now'}\n | {type: 'self'}\n | {type: 'stage'}\n | {\n type: 'stateRead'\n scope?: 'workflow' | 'stage' | undefined\n state: string\n path?: string | undefined\n }\n | {type: 'object'; fields: Record<string, SourceInternal>}\n\nconst SourceSchema: v.GenericSchema<SourceInternal> = v.lazy(() =>\n v.union([\n // State-entry origins: who fills the entry, and when.\n v.strictObject({type: v.literal('init')}),\n v.strictObject({type: v.literal('write')}),\n v.strictObject({\n type: v.literal('query'),\n query: NonEmpty,\n }),\n // Value sources: resolved to concrete JSON when an op or seed applies.\n v.strictObject({type: v.literal('literal'), value: v.unknown()}),\n v.strictObject({type: v.literal('param'), param: NonEmpty}),\n v.strictObject({type: v.literal('actor')}),\n v.strictObject({type: v.literal('now')}),\n v.strictObject({type: v.literal('self')}),\n v.strictObject({type: v.literal('stage')}),\n v.strictObject({\n type: v.literal('stateRead'),\n scope: v.optional(v.union([v.literal('workflow'), v.literal('stage')])),\n state: NonEmpty,\n path: v.optional(v.string()),\n }),\n v.strictObject({\n type: v.literal('object'),\n fields: v.record(NonEmpty, SourceSchema),\n }),\n ]),\n)\nexport type Source = SourceInternal\n\n// State references — `{ scope?, state }` addressing a state entry by name.\n// Authoring may omit `scope`; desugar resolves it lexically (task → stage →\n// workflow), so the STORED form always carries an explicit scope.\n\nconst StoredStateRefSchema = v.strictObject({\n scope: picklist(STATE_SCOPES),\n state: NonEmpty,\n})\nexport type StoredStateRef = v.InferOutput<typeof StoredStateRefSchema>\n\nconst AuthoringStateRefSchema = v.strictObject({\n scope: v.optional(picklist(STATE_SCOPES)),\n state: NonEmpty,\n})\nexport type AuthoringStateRef = v.InferOutput<typeof AuthoringStateRefSchema>\n\n// Op predicates — small typed predicate for state.updateWhere /\n// state.removeWhere. Runs in the pure in-memory op path, so it stays a\n// typed structure rather than GROQ. Discriminated by `type` like every union.\n\ntype OpPredicateInternal =\n | {type: 'field'; field: string; equals: Source}\n | {type: 'all'; of: OpPredicateInternal[]}\n | {type: 'any'; of: OpPredicateInternal[]}\n\nconst OpPredicateSchema: v.GenericSchema<OpPredicateInternal> = v.lazy(() =>\n v.union([\n v.strictObject({\n type: v.literal('field'),\n field: NonEmpty,\n equals: SourceSchema,\n }),\n v.strictObject({type: v.literal('all'), of: v.array(OpPredicateSchema)}),\n v.strictObject({type: v.literal('any'), of: v.array(OpPredicateSchema)}),\n ]),\n)\nexport type OpPredicate = OpPredicateInternal\n\n// Ops — the six stored mutation primitives. `value` is the one payload key.\n// `status.set` may name a sibling task; desugar fills the firing task when\n// authoring omitted it, so the stored op always carries `task`.\n\nfunction opSchemas<T extends v.GenericSchema>(targetSchema: T) {\n return [\n v.strictObject({\n type: v.literal('state.set'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.unset'),\n target: targetSchema,\n }),\n v.strictObject({\n type: v.literal('state.append'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.updateWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.removeWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n }),\n ] as const\n}\n\nconst StoredOpSchema = v.variant('type', [\n ...opSchemas(StoredStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: NonEmpty,\n status: picklist(TASK_STATUSES),\n }),\n])\nexport type Op = v.InferOutput<typeof StoredOpSchema>\n\n/**\n * The `state.*` subset a transition may carry — `status.set` has no coherent\n * task target while the stage's tasks tear down, so the engine rejects it\n * at parse time rather than dropping it silently.\n */\nconst StoredTransitionOpSchema = v.variant('type', [...opSchemas(StoredStateRefSchema)])\nexport type TransitionOp = v.InferOutput<typeof StoredTransitionOpSchema>\n\n// Authoring ops: scope optional on targets, `task` optional on status.set\n// (defaults to the firing task), plus the `audit` sugar type — a stamped\n// append whose expansion merges `actor`/`at` Source fields into its own value.\n\nconst AuditOpSchema = v.strictObject({\n type: v.literal('audit'),\n target: AuthoringStateRefSchema,\n value: SourceSchema,\n stampFields: v.optional(\n v.strictObject({\n actor: v.optional(NonEmpty),\n at: v.optional(NonEmpty),\n }),\n ),\n})\n\nexport const AuthoringOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: v.optional(NonEmpty),\n status: picklist(TASK_STATUSES),\n }),\n AuditOpSchema,\n])\nexport type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>\n\n// State entries — the generic stored data. Kinds are bare: a discriminator is\n// unique within its union; namespaces live only on engine-owned lake document\n// `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the instance type).\n\nconst StateKindSchema = picklist([\n 'doc.ref',\n 'doc.refs',\n // Release reference. A workflow declares this entry to say \"I target a\n // Content Release\"; the runtime fills it at start time and auto-derives\n // the instance's read perspective from it.\n 'release.ref',\n 'query',\n 'value.string',\n 'value.url',\n 'value.number',\n 'value.boolean',\n 'value.dateTime',\n 'value.actor',\n 'checklist',\n 'notes',\n // The WHO-FOR entry: the inbox reverse-query reads it by kind, and the\n // rendered `$assigned` gate matches the caller against it.\n 'assignees',\n])\n\nconst StateEntryName = groqIdentifier('`$state.<name>`')\n\nconst StateEntrySchema = v.strictObject({\n type: StateKindSchema,\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n source: SourceSchema,\n})\nexport type StateEntry = v.InferOutput<typeof StateEntrySchema>\n\n/**\n * Authoring state accepts the raw entries plus the `claim` sugar type — the\n * state half of the mirrored claim pair. Expansion: `value.actor` with an\n * implied `write` source, strictly within this entry.\n */\nconst ClaimStateSchema = v.strictObject({\n type: v.literal('claim'),\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n})\n\nexport const AuthoringStateEntrySchema = v.union([StateEntrySchema, ClaimStateSchema])\nexport type AuthoringStateEntry = v.InferOutput<typeof AuthoringStateEntrySchema>\n\n// Conditions are raw GROQ strings over the rendered scope — built-in vars\n// ($state, $actor, $assigned, $can, $row, $effects, $subworkflows, $tasks,\n// $now, $allTasksDone, $anyTaskFailed) plus the author's nullary predicates.\n// There is no {ref, args} wrapper; parameterized reuse is a define-time\n// TypeScript function (see the `groq` tag in ./groq.ts).\n\nconst ConditionSchema = NonEmpty\nexport type Condition = string\n\n// Effects — the registry model. `name` is the effect's only identity; the\n// host app registers a handler against it (1:1) and the stored definition\n// never references code. Names are unique per definition (invariant) so\n// `$effects.<name>` is unambiguous.\n\nexport const EffectSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */\n bindings: v.optional(v.record(v.string(), ConditionSchema)),\n /** Static config, passed through to the handler verbatim. */\n input: v.optional(v.record(v.string(), v.unknown())),\n})\nexport type Effect = v.InferOutput<typeof EffectSchema>\n\n// Actions\n\n/**\n * Caller-supplied params declared on an action. The engine validates\n * incoming `params` against this list before running ops or queuing\n * effects: missing required params → ActionParamsInvalidError, action\n * does not commit. Resolved values feed `Source.param` lookups.\n */\nconst ActionParamSchema = v.strictObject({\n type: picklist([\n 'string',\n 'number',\n 'boolean',\n 'url',\n 'dateTime',\n 'actor',\n 'doc.ref',\n 'doc.refs',\n 'json',\n ]),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n required: v.optional(v.boolean()),\n})\nexport type ActionParam = v.InferOutput<typeof ActionParamSchema>\n\n/** Fields shared by the stored and authoring action shapes, parameterised\n * over the op schema (stored ops are fully resolved; authoring ops keep\n * their sugar). */\nfunction actionFields<Op extends v.GenericSchema>(op: Op) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * The one gate mechanism: a condition over the rendered scope. Hard\n * enforcement lives outside the engine entirely (the lake ACL on the\n * documents, and guards) — every engine-evaluated gate is authoring/UX.\n */\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredActionSchema = v.strictObject(actionFields(StoredOpSchema))\nexport type Action = v.InferOutput<typeof StoredActionSchema>\n\nconst TerminalTaskStatus = picklist(TERMINAL_TASK_STATUSES)\n\n/**\n * Authoring action — the stored fields plus two field sugars with one\n * defined expansion each:\n *\n * - `roles` → a `count($actor.roles[@ in [...]]) > 0` membership condition\n * ANDed with the authored `filter`.\n * - `status` → a `status.set` op on the firing task, appended **after**\n * the authored ops (deliberately never implied: a forgotten explicit\n * `status` is a visible stall, an implied default silently completes\n * claim-like actions).\n */\nconst RawAuthoringActionSchema = v.strictObject({\n ...actionFields(AuthoringOpSchema),\n roles: v.optional(v.array(NonEmpty)),\n status: v.optional(TerminalTaskStatus),\n})\n\n/**\n * The action half of the mirrored claim pair. `state` references an\n * author-declared actor-valued entry (the pair's other half), resolved\n * lexically. Expansion, strictly within this action: a no-steal\n * `!defined($state.<state>)` filter ANDed with `roles`/`filter`, plus a\n * `state.set` ← actor op. `ops` and `status` are reserved (the expansion\n * owns them) — strictObject rejects them as unknown keys.\n */\nconst ClaimActionSchema = v.strictObject({\n type: v.literal('claim'),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n state: v.union([NonEmpty, AuthoringStateRefSchema]),\n roles: v.optional(v.array(NonEmpty)),\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n effects: v.optional(v.array(EffectSchema)),\n})\n\nexport const AuthoringActionSchema = v.union([RawAuthoringActionSchema, ClaimActionSchema])\nexport type AuthoringAction = v.InferOutput<typeof AuthoringActionSchema>\n\n// Subworkflows — declare `subworkflows`, read `$subworkflows`. The spawning\n// task resolves like any task: `completeWhen` / `failWhen` over the rendered\n// `$subworkflows`; no `completeWhen` means all subworkflows done.\n\n/**\n * Logical reference to a deployed workflow definition, by its `name` (the\n * stable contract — the tag can be renamed, workflows redeployed). The engine\n * resolves it at spawn time, ordering by `version desc` unless an explicit\n * `version` pins one.\n */\nconst DefinitionRefSchema = v.strictObject({\n name: NonEmpty,\n version: v.optional(v.union([PositiveInt, v.literal('latest')])),\n})\n\nconst SubworkflowsSchema = v.strictObject({\n /** GROQ producing one row per subworkflow; each row binds as `$row`. */\n forEach: NonEmpty,\n definition: DefinitionRefSchema,\n /** Initial state for each subworkflow — entry name → GROQ over `$row` + the parent scope. */\n with: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Extra values evaluated in the parent's rendered scope at spawn time and\n * delivered into each subworkflow's `$effects` bag — the parent→child\n * handoff, read exactly like an effect output.\n */\n context: v.optional(v.record(NonEmpty, ConditionSchema)),\n})\nexport type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>\n\n// Tasks — tasks own the ENTER moment: `ops` + `effects` run at activation,\n// `filter` makes activation conditional on the stage's entry state, and\n// `activation` switches the stage-enter flip (default `manual`: a task never\n// activates silently; \"auto\" is the explicit opt-in). A task with no actions\n// and no `completeWhen` is a machine step — it runs its activation payload\n// and resolves `done` immediately, leaving an audit row.\n\nfunction taskFields<\n TState extends v.GenericSchema,\n TAction extends v.GenericSchema,\n TOp extends v.GenericSchema,\n>(state: TState, action: TAction, op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n activation: v.optional(picklist(['auto', 'manual'])),\n filter: v.optional(ConditionSchema),\n /**\n * Auto-completion condition — evaluated at activation and on every\n * cascade; truthy flips the task to `done` with a system actor. On a\n * spawning task it typically reads `$subworkflows`.\n */\n completeWhen: v.optional(ConditionSchema),\n /**\n * Auto-failure condition — symmetric to `completeWhen`, flips to\n * `failed`. When both are truthy on the same evaluation, `failWhen`\n * wins — failure is the more notable signal.\n */\n failWhen: v.optional(ConditionSchema),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n actions: v.optional(v.array(action)),\n subworkflows: v.optional(SubworkflowsSchema),\n /** Task-scoped state entries. Resolved at task activation time. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredTaskSchema = v.strictObject(\n taskFields(StateEntrySchema, StoredActionSchema, StoredOpSchema),\n)\nexport type Task = v.InferOutput<typeof StoredTaskSchema>\n\nexport const AuthoringTaskSchema = v.strictObject(\n taskFields(AuthoringStateEntrySchema, AuthoringActionSchema, AuthoringOpSchema),\n)\nexport type AuthoringTask = v.InferOutput<typeof AuthoringTaskSchema>\n\n// Transitions — purely a condition over the rendered scope. Selection rule:\n// every transition is evaluated on every commit and cascade; the first truthy\n// `filter` in declaration order fires. No action coupling: a routing\n// difference is written into state by the action and read by the filter.\n\nfunction transitionFields<TOp extends v.GenericSchema, TFilter extends v.GenericSchema>(\n op: TOp,\n filter: TFilter,\n) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n to: NonEmpty,\n filter,\n /** The `state.*` subset — state-write-on-move, the stage's EXIT/ARRIVAL payload. */\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredTransitionSchema = v.strictObject(\n transitionFields(StoredTransitionOpSchema, ConditionSchema),\n)\nexport type Transition = v.InferOutput<typeof StoredTransitionSchema>\n\n/**\n * Authoring transitions may omit `filter`; desugar fills the safe,\n * overwhelmingly-common gate `\"$allTasksDone\"`. \"Fire unconditionally\"\n * stays spellable as an explicit `filter: \"true\"`.\n */\nconst AuthoringTransitionOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n AuditOpSchema,\n])\nexport const AuthoringTransitionSchema = v.strictObject(\n transitionFields(AuthoringTransitionOpSchema, v.optional(ConditionSchema)),\n)\nexport type AuthoringTransition = v.InferOutput<typeof AuthoringTransitionSchema>\n\n// Guards — lake mutation guards. A FOREIGN CONTRACT mirrored 1:1: the\n// `temp.system.guard` doc's `match` / `predicate` / `metadata` fields are the\n// content lake's API, not engine surface, so authoring keeps the lake's\n// vocabulary verbatim. The engine adds exactly two things: `name` (authoring\n// identity — the lake `_id` derives from (instanceId, guard.name)) and\n// `$state`-read VALUES (`idRefs: [\"$state.subject\"]`, `metadata.outcome:\n// \"$state.outcome\"`), resolved at deploy into the bare values the contract\n// expects. Guards + the lake ACL are the only HARD gates in the system.\n\nconst GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS)\nexport type GuardAction = v.InferOutput<typeof GuardActionSchema>\n\nconst GuardMatchSchema = v.strictObject({\n /** Subject `_type`(s); empty matches any type. */\n types: v.optional(v.array(NonEmpty)),\n /** Target docs as `$state` reads (or `\"$self\"`), resolved at deploy to bare ids + the resource. */\n idRefs: v.optional(v.array(NonEmpty)),\n /** Glob id patterns (bare, resource-local). */\n idPatterns: v.optional(v.array(NonEmpty)),\n actions: v.pipe(\n v.array(GuardActionSchema),\n v.minLength(1, 'a guard must match at least one action'),\n ),\n})\nexport type GuardMatch = v.InferOutput<typeof GuardMatchSchema>\n\nexport const GuardSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n match: GuardMatchSchema,\n /**\n * Lake GROQ predicate — a distinct eval context reading\n * `document.before`/`document.after`, `mutation`, `guard`, and\n * `identity()`. Bare ids/fields only. Omitted or empty means\n * UNCONDITIONAL DENY.\n */\n predicate: v.optional(v.string()),\n /**\n * Projected workflow state the predicate reads as `guard.metadata.*` —\n * the only bridge from the lake eval context (which cannot see `$state`)\n * to workflow state. Values are NOT GROQ: each is a deploy-time read in\n * the guard mini-language — `\"$self\"`, `\"$now\"`, or\n * `\"$state.<name>[.path]\"` — resolved into a bare value at deploy and\n * re-synced by the post-state-op guard refresh.\n */\n metadata: v.optional(v.record(NonEmpty, NonEmpty)),\n})\nexport type Guard = v.InferOutput<typeof GuardSchema>\n\n// Stages — pure containers: name / state / guards / tasks / transitions, no\n// behaviour of their own. Tasks own enter, transitions own exit and arrival.\n// `initial` is whatever `initialStage` names; a stage with no transitions IS\n// terminal (structural, nothing to declare or mis-declare).\n\nfunction stageFields<\n TState extends v.GenericSchema,\n TTask extends v.GenericSchema,\n TTransition extends v.GenericSchema,\n>(state: TState, task: TTask, transition: TTransition) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n tasks: v.optional(v.array(task)),\n transitions: v.optional(v.array(transition)),\n /**\n * Lake mutation guards active while this stage holds. Each compiles to a\n * `temp.system.guard` doc deployed on stage entry and retracted on exit.\n */\n guards: v.optional(v.array(GuardSchema)),\n /** Stage-scoped state entries. Resolved at stage entry. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredStageSchema = v.strictObject(\n stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema),\n)\nexport type Stage = v.InferOutput<typeof StoredStageSchema>\n\nexport const AuthoringStageSchema = v.strictObject(\n stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema),\n)\nexport type AuthoringStage = v.InferOutput<typeof AuthoringStageSchema>\n\n// Workflow definition (the root)\n\nfunction workflowFields<TState extends v.GenericSchema, TStage extends v.GenericSchema>(\n state: TState,\n stage: TStage,\n) {\n return {\n name: NonEmpty,\n version: PositiveInt,\n title: NonEmpty,\n description: v.optional(v.string()),\n /** Reference field: named for the target, holds the stage's `name`. */\n initialStage: NonEmpty,\n /** Workflow-scope state entries. Persist for the instance lifetime. */\n state: v.optional(v.array(state)),\n stages: v.pipe(v.array(stage), v.minLength(1, 'must declare at least one stage')),\n /**\n * Nullary named conditions — each `name: groq` entry is pre-evaluated\n * and bound as the boolean `$name` var, composable with native GROQ.\n * Redefining a built-in var is a deploy error (never silently shadow).\n */\n predicates: v.optional(v.record(groqIdentifier('`$<name>`'), ConditionSchema)),\n }\n}\n\n/**\n * Structural schema for a STORED workflow definition — primitives only,\n * every reference scope resolved. Cross-field invariants (unique names,\n * transition targets, effect-name uniqueness, predicate shadowing) are\n * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.\n */\nconst WorkflowDefinitionSchema = v.strictObject(workflowFields(StateEntrySchema, StoredStageSchema))\nexport type WorkflowDefinition = v.InferOutput<typeof WorkflowDefinitionSchema>\n\n/** The authoring surface: stored primitives plus the define-time sugar. */\nexport const AuthoringWorkflowSchema = v.strictObject(\n workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema),\n)\nexport type AuthoringWorkflow = v.InferOutput<typeof AuthoringWorkflowSchema>\n\n/**\n * The lake document type for a deployed workflow definition. Engine-owned\n * standalone documents carry the platform namespace; in-array discriminators\n * stay bare. Mirrors {@link WORKFLOW_INSTANCE_TYPE}.\n */\nexport const WORKFLOW_DEFINITION_TYPE = 'sanity.workflow.definition'\n\n// Error formatting — turn validation issues into a multi-line,\n// path-prefixed message that points at the exact field the author got\n// wrong. Shared by structural parse errors (via {@link issuesFromValibot})\n// and cross-field invariant issues.\n\nexport interface ValidationIssue {\n path: ReadonlyArray<PropertyKey>\n message: string\n}\n\n/** The buildable path form desugar and the invariants accumulate issues under. */\nexport type IssuePath = (string | number)[]\n\nexport function formatValidationError(label: string, issues: readonly ValidationIssue[]): string {\n const lines = issues.map((issue) => {\n const path = issue.path.length === 0 ? '(root)' : formatPath(issue.path)\n return ` - ${path}: ${issue.message}`\n })\n return `${label} failed validation (${issues.length} issue${\n issues.length === 1 ? '' : 's'\n }):\\n${lines.join('\\n')}`\n}\n\nexport function issuesFromValibot(issues: readonly v.BaseIssue<unknown>[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? issue.path.map((item) => item.key as PropertyKey) : [],\n message: issue.message,\n }))\n}\n\nfunction formatPath(path: ReadonlyArray<PropertyKey>): string {\n let out = ''\n for (const seg of path) {\n if (typeof seg === 'number') out += `[${seg}]`\n else out += out.length === 0 ? String(seg) : `.${String(seg)}`\n }\n return out\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../src/types/enums.ts","../../src/define/schema.ts"],"sourcesContent":["/**\n * Leaf enums — the const arrays (and their derived union types) that both\n * the authoring schema and the engine address by name.\n *\n * This module imports nothing. It is the schema-free foundation that\n * `../define/schema.ts` reads its value constants from, which is what keeps\n * the type model and the valibot schema free of an import cycle: the value edge\n * `schema.ts → enums.ts` terminates here.\n */\n\n// Task status — used by instance state. The authored action `status:` sugar\n// (and the `status.set` op it desugars to) is constrained to the terminal\n// subset below.\nexport const TASK_STATUSES = ['pending', 'active', 'done', 'skipped', 'failed'] as const\nexport type TaskStatus = (typeof TASK_STATUSES)[number]\n\n// The statuses a task can be resolved INTO — what `status.set` accepts and\n// what stops blocking the `$allTasksDone` gate family.\nexport const TERMINAL_TASK_STATUSES = ['done', 'skipped', 'failed'] as const\nexport type TerminalTaskStatus = (typeof TERMINAL_TASK_STATUSES)[number]\n\nexport function isTerminalTaskStatus(status: TaskStatus): status is TerminalTaskStatus {\n return (TERMINAL_TASK_STATUSES as readonly TaskStatus[]).includes(status)\n}\n\n// The three state scopes a state entry can live in. Authoring (`ScopeKey`,\n// `stateRead` sources) and the engine both address state entries by scope.\nexport const STATE_SCOPES = ['workflow', 'stage', 'task'] as const\nexport type StateScope = (typeof STATE_SCOPES)[number]\n\n// Document-value permissions. Grants (`Grant` in ./authorization.ts) compose\n// most-permissive-wins.\nexport const DOCUMENT_VALUE_PERMISSIONS = ['create', 'read', 'update'] as const\nexport type DocumentValuePermission = (typeof DOCUMENT_VALUE_PERMISSIONS)[number]\n\n// Mutation-guard actions — the lake operations a guard can gate. See the\n// guard types in ./authorization.ts.\nexport const MUTATION_GUARD_ACTIONS = [\n 'create',\n 'update',\n 'delete',\n 'publish',\n 'unpublish',\n] as const\nexport type MutationGuardAction = (typeof MUTATION_GUARD_ACTIONS)[number]\n","/**\n * Valibot schemas for the workflow authoring surface — the things a workflow\n * author writes by hand and feeds to `defineWorkflow`. Types in this\n * file are the **canonical** authoring types: they are inferred from\n * the schemas, so the runtime schema and the compile-time type cannot\n * drift.\n *\n * Two layers live here, mirroring the design model (generic stored data,\n * sugar that compiles away):\n *\n * - **Stored** schemas (`WorkflowDefinitionSchema`, `OpSchema`, …) describe\n * the primitives the engine persists. No sugar variants, every state\n * reference carries an explicit resolved `scope`.\n * - **Authoring** schemas (`AuthoringWorkflowSchema`, …) accept the same\n * primitives **plus** define-time sugar: the `claim` state/action pair,\n * the `audit` op, the `roles` and `status` action fields, omitted\n * transition filters, omitted reference scopes. `desugar.ts` expands\n * authoring input into the stored shape.\n *\n * Strictness: every object schema is `v.strictObject` so unknown keys\n * produce a parse error. That catches typos like `verison: 1` at deploy\n * time — and it is also what enforces each sugar contract's *reserved*\n * fields (an `ops:` on a `claim` action is an unknown key, fail loud).\n */\n\nimport * as v from 'valibot'\n\nimport {\n MUTATION_GUARD_ACTIONS,\n STATE_SCOPES,\n TASK_STATUSES,\n TERMINAL_TASK_STATUSES,\n} from '../types/enums.ts'\n\nconst NonEmpty = v.pipe(v.string(), v.minLength(1, 'must be a non-empty string'))\n\nconst PositiveInt = v.pipe(v.number(), v.integer(), v.minValue(1))\n\n/**\n * Names that get spliced into GROQ — state entries (`$state.<name>` in the\n * claim no-steal filter and every condition) and predicate keys (`$<name>`).\n * A name like `review-owner` would parse as subtraction inside GROQ and\n * silently change the expression's meaning, so these are constrained to\n * GROQ-identifier-safe names. See {@link GROQ_IDENTIFIER}.\n */\nexport const GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction groqIdentifier(referencedAs: string) {\n return v.pipe(\n v.string(),\n v.regex(\n GROQ_IDENTIFIER,\n `must be a GROQ-safe identifier (letters, digits, underscore; not starting with a digit) ` +\n `because it is referenced as ${referencedAs} in GROQ conditions`,\n ),\n )\n}\n\n/**\n * Picklist with a zod-compatible \"Invalid option\" message that lists every\n * allowed value, so a typo'd discriminator or enum lands with a message an\n * author can act on (e.g. `Invalid option: expected one of \"done\"|\"skipped\"`).\n */\nfunction picklist<const TOptions extends readonly [string, ...string[]]>(options: TOptions) {\n return v.picklist(\n options,\n `Invalid option: expected one of ${options.map((o) => `\"${o}\"`).join('|')}`,\n )\n}\n\n// Source — the single \"where a value comes from\" union, shared by state-entry\n// origins and op payloads. Conditions and effect bindings are NOT Sources —\n// they are GROQ strings over the rendered scope ($state, $actor, $row, …).\n// Each value variant has a rendered $-twin (actor ↔ $actor, now ↔ $now) so\n// learning one side teaches the other.\n\ntype SourceInternal =\n | {type: 'init'}\n | {type: 'write'}\n | {type: 'query'; query: string}\n | {type: 'literal'; value: unknown}\n | {type: 'param'; param: string}\n | {type: 'actor'}\n | {type: 'now'}\n | {type: 'self'}\n | {type: 'stage'}\n | {\n type: 'stateRead'\n scope?: 'workflow' | 'stage' | undefined\n state: string\n path?: string | undefined\n }\n | {type: 'object'; fields: Record<string, SourceInternal>}\n\nconst SourceSchema: v.GenericSchema<SourceInternal> = v.lazy(() =>\n v.union([\n // State-entry origins: who fills the entry, and when.\n v.strictObject({type: v.literal('init')}),\n v.strictObject({type: v.literal('write')}),\n v.strictObject({\n type: v.literal('query'),\n query: NonEmpty,\n }),\n // Value sources: resolved to concrete JSON when an op or seed applies.\n v.strictObject({type: v.literal('literal'), value: v.unknown()}),\n v.strictObject({type: v.literal('param'), param: NonEmpty}),\n v.strictObject({type: v.literal('actor')}),\n v.strictObject({type: v.literal('now')}),\n v.strictObject({type: v.literal('self')}),\n v.strictObject({type: v.literal('stage')}),\n v.strictObject({\n type: v.literal('stateRead'),\n scope: v.optional(v.union([v.literal('workflow'), v.literal('stage')])),\n state: NonEmpty,\n path: v.optional(v.string()),\n }),\n v.strictObject({\n type: v.literal('object'),\n fields: v.record(NonEmpty, SourceSchema),\n }),\n ]),\n)\nexport type Source = SourceInternal\n\n// State references — `{ scope?, state }` addressing a state entry by name.\n// Authoring may omit `scope`; desugar resolves it lexically (task → stage →\n// workflow), so the STORED form always carries an explicit scope.\n\nconst StoredStateRefSchema = v.strictObject({\n scope: picklist(STATE_SCOPES),\n state: NonEmpty,\n})\nexport type StoredStateRef = v.InferOutput<typeof StoredStateRefSchema>\n\nconst AuthoringStateRefSchema = v.strictObject({\n scope: v.optional(picklist(STATE_SCOPES)),\n state: NonEmpty,\n})\nexport type AuthoringStateRef = v.InferOutput<typeof AuthoringStateRefSchema>\n\n// Op predicates — small typed predicate for state.updateWhere /\n// state.removeWhere. Runs in the pure in-memory op path, so it stays a\n// typed structure rather than GROQ. Discriminated by `type` like every union.\n\ntype OpPredicateInternal =\n | {type: 'field'; field: string; equals: Source}\n | {type: 'all'; of: OpPredicateInternal[]}\n | {type: 'any'; of: OpPredicateInternal[]}\n\nconst OpPredicateSchema: v.GenericSchema<OpPredicateInternal> = v.lazy(() =>\n v.union([\n v.strictObject({\n type: v.literal('field'),\n field: NonEmpty,\n equals: SourceSchema,\n }),\n v.strictObject({type: v.literal('all'), of: v.array(OpPredicateSchema)}),\n v.strictObject({type: v.literal('any'), of: v.array(OpPredicateSchema)}),\n ]),\n)\nexport type OpPredicate = OpPredicateInternal\n\n// Ops — the six stored mutation primitives. `value` is the one payload key.\n// `status.set` may name a sibling task; desugar fills the firing task when\n// authoring omitted it, so the stored op always carries `task`.\n\nfunction opSchemas<T extends v.GenericSchema>(targetSchema: T) {\n return [\n v.strictObject({\n type: v.literal('state.set'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.unset'),\n target: targetSchema,\n }),\n v.strictObject({\n type: v.literal('state.append'),\n target: targetSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.updateWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n value: SourceSchema,\n }),\n v.strictObject({\n type: v.literal('state.removeWhere'),\n target: targetSchema,\n where: OpPredicateSchema,\n }),\n ] as const\n}\n\nconst StoredOpSchema = v.variant('type', [\n ...opSchemas(StoredStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: NonEmpty,\n status: picklist(TASK_STATUSES),\n }),\n])\nexport type Op = v.InferOutput<typeof StoredOpSchema>\n\n/**\n * The `state.*` subset a transition may carry — `status.set` has no coherent\n * task target while the stage's tasks tear down, so the engine rejects it\n * at parse time rather than dropping it silently.\n */\nconst StoredTransitionOpSchema = v.variant('type', [...opSchemas(StoredStateRefSchema)])\nexport type TransitionOp = v.InferOutput<typeof StoredTransitionOpSchema>\n\n// Authoring ops: scope optional on targets, `task` optional on status.set\n// (defaults to the firing task), plus the `audit` sugar type — a stamped\n// append whose expansion merges `actor`/`at` Source fields into its own value.\n\nconst AuditOpSchema = v.strictObject({\n type: v.literal('audit'),\n target: AuthoringStateRefSchema,\n value: SourceSchema,\n stampFields: v.optional(\n v.strictObject({\n actor: v.optional(NonEmpty),\n at: v.optional(NonEmpty),\n }),\n ),\n})\n\nexport const AuthoringOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n v.strictObject({\n type: v.literal('status.set'),\n task: v.optional(NonEmpty),\n status: picklist(TASK_STATUSES),\n }),\n AuditOpSchema,\n])\nexport type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>\n\n// State entries — the generic stored data. Kinds are bare: a discriminator is\n// unique within its union; namespaces live only on engine-owned lake document\n// `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the instance type).\n\nconst StateKindSchema = picklist([\n 'doc.ref',\n 'doc.refs',\n // Release reference. A workflow declares this entry to say \"I target a\n // Content Release\"; the runtime fills it at start time and auto-derives\n // the instance's read perspective from it.\n 'release.ref',\n 'query',\n 'value.string',\n 'value.url',\n 'value.number',\n 'value.boolean',\n 'value.dateTime',\n 'value.actor',\n 'checklist',\n 'notes',\n // The WHO-FOR entry: the inbox reverse-query reads it by kind, and the\n // rendered `$assigned` gate matches the caller against it.\n 'assignees',\n])\n\nconst StateEntryName = groqIdentifier('`$state.<name>`')\n\nconst StateEntrySchema = v.strictObject({\n type: StateKindSchema,\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * When true, the caller MUST supply this entry at start (via\n * `initialState`) or spawn (via the parent's `subworkflows.with`). A\n * missing required entry throws rather than silently defaulting to\n * `null`/`[]` — the same fail-fast an action's `required` param gets.\n * Valid only on a workflow-scope `init`-sourced entry (deploy invariant).\n */\n required: v.optional(v.boolean()),\n source: SourceSchema,\n})\nexport type StateEntry = v.InferOutput<typeof StateEntrySchema>\n\n/**\n * Authoring state accepts the raw entries plus the `claim` sugar type — the\n * state half of the mirrored claim pair. Expansion: `value.actor` with an\n * implied `write` source, strictly within this entry.\n */\nconst ClaimStateSchema = v.strictObject({\n type: v.literal('claim'),\n name: StateEntryName,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n})\n\nexport const AuthoringStateEntrySchema = v.union([StateEntrySchema, ClaimStateSchema])\nexport type AuthoringStateEntry = v.InferOutput<typeof AuthoringStateEntrySchema>\n\n// Conditions are raw GROQ strings over the rendered scope — built-in vars\n// ($state, $actor, $assigned, $can, $row, $effects, $subworkflows, $tasks,\n// $now, $allTasksDone, $anyTaskFailed) plus the author's nullary predicates.\n// There is no {ref, args} wrapper; parameterized reuse is a define-time\n// TypeScript function (see the `groq` tag in ./groq.ts).\n\nconst ConditionSchema = NonEmpty\nexport type Condition = string\n\n// Effects — the registry model. `name` is the effect's only identity; the\n// host app registers a handler against it (1:1) and the stored definition\n// never references code. Names are unique per definition (invariant) so\n// `$effects.<name>` is unambiguous.\n\nexport const EffectSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */\n bindings: v.optional(v.record(v.string(), ConditionSchema)),\n /** Static config, passed through to the handler verbatim. */\n input: v.optional(v.record(v.string(), v.unknown())),\n})\nexport type Effect = v.InferOutput<typeof EffectSchema>\n\n// Actions\n\n/**\n * Caller-supplied params declared on an action. The engine validates\n * incoming `params` against this list before running ops or queuing\n * effects: missing required params → ActionParamsInvalidError, action\n * does not commit. Resolved values feed `Source.param` lookups.\n */\nconst ActionParamSchema = v.strictObject({\n type: picklist([\n 'string',\n 'number',\n 'boolean',\n 'url',\n 'dateTime',\n 'actor',\n 'doc.ref',\n 'doc.refs',\n 'json',\n ]),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n required: v.optional(v.boolean()),\n})\nexport type ActionParam = v.InferOutput<typeof ActionParamSchema>\n\n/** Fields shared by the stored and authoring action shapes, parameterised\n * over the op schema (stored ops are fully resolved; authoring ops keep\n * their sugar). */\nfunction actionFields<TOp extends v.GenericSchema>(op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n /**\n * The one gate mechanism: a condition over the rendered scope. Hard\n * enforcement lives outside the engine entirely (the lake ACL on the\n * documents, and guards) — every engine-evaluated gate is authoring/UX.\n */\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredActionSchema = v.strictObject(actionFields(StoredOpSchema))\nexport type Action = v.InferOutput<typeof StoredActionSchema>\n\nconst TerminalTaskStatus = picklist(TERMINAL_TASK_STATUSES)\n\n/**\n * Authoring action — the stored fields plus two field sugars with one\n * defined expansion each:\n *\n * - `roles` → a `count($actor.roles[@ in [...]]) > 0` membership condition\n * ANDed with the authored `filter`.\n * - `status` → a `status.set` op on the firing task, appended **after**\n * the authored ops (deliberately never implied: a forgotten explicit\n * `status` is a visible stall, an implied default silently completes\n * claim-like actions).\n */\nconst RawAuthoringActionSchema = v.strictObject({\n ...actionFields(AuthoringOpSchema),\n roles: v.optional(v.array(NonEmpty)),\n status: v.optional(TerminalTaskStatus),\n})\n\n/**\n * The action half of the mirrored claim pair. `state` references an\n * author-declared actor-valued entry (the pair's other half), resolved\n * lexically. Expansion, strictly within this action: a no-steal\n * `!defined($state.<state>)` filter ANDed with `roles`/`filter`, plus a\n * `state.set` ← actor op. `ops` and `status` are reserved (the expansion\n * owns them) — strictObject rejects them as unknown keys.\n */\nconst ClaimActionSchema = v.strictObject({\n type: v.literal('claim'),\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n state: v.union([NonEmpty, AuthoringStateRefSchema]),\n roles: v.optional(v.array(NonEmpty)),\n filter: v.optional(ConditionSchema),\n params: v.optional(v.array(ActionParamSchema)),\n effects: v.optional(v.array(EffectSchema)),\n})\n\nexport const AuthoringActionSchema = v.union([RawAuthoringActionSchema, ClaimActionSchema])\nexport type AuthoringAction = v.InferOutput<typeof AuthoringActionSchema>\n\n// Subworkflows — declare `subworkflows`, read `$subworkflows`. The spawning\n// task resolves like any task: `completeWhen` / `failWhen` over the rendered\n// `$subworkflows`; no `completeWhen` means all subworkflows done.\n\n/**\n * Logical reference to a deployed workflow definition, by its `name` (the\n * stable contract — the tag can be renamed, workflows redeployed). The engine\n * resolves it at spawn time, ordering by `version desc` unless an explicit\n * `version` pins one.\n */\nconst DefinitionRefSchema = v.strictObject({\n name: NonEmpty,\n version: v.optional(v.union([PositiveInt, v.literal('latest')])),\n})\n\nconst SubworkflowsSchema = v.strictObject({\n /** GROQ producing one row per subworkflow; each row binds as `$row`. */\n forEach: NonEmpty,\n definition: DefinitionRefSchema,\n /** Initial state for each subworkflow — entry name → GROQ over `$row` + the parent scope. */\n with: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Extra values evaluated in the parent's rendered scope at spawn time and\n * delivered into each subworkflow's `$effects` bag — the parent→child\n * handoff, read exactly like an effect output.\n */\n context: v.optional(v.record(NonEmpty, ConditionSchema)),\n})\nexport type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>\n\n// Tasks — tasks own the ENTER moment: `ops` + `effects` run at activation,\n// `filter` makes activation conditional on the stage's entry state, and\n// `activation` switches the stage-enter flip (default `manual`: a task never\n// activates silently; \"auto\" is the explicit opt-in). A task with no actions\n// and no `completeWhen` is a machine step — it runs its activation payload\n// and resolves `done` immediately, leaving an audit row.\n\nfunction taskFields<\n TState extends v.GenericSchema,\n TAction extends v.GenericSchema,\n TOp extends v.GenericSchema,\n>(state: TState, action: TAction, op: TOp) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n activation: v.optional(picklist(['auto', 'manual'])),\n filter: v.optional(ConditionSchema),\n /**\n * Readiness gates, by name — conditions over the rendered scope that must\n * hold for the task to be *executable*, orthogonal to `filter`\n * (visibility). An unmet requirement keeps the task visible but disables\n * its actions with a `requirements-unmet` verdict naming the unmet keys;\n * all must hold (any-of lives inside one condition). Advisory like every\n * engine gate — the lake still enforces. Distinct from ACL (authorization)\n * and guards (content-write locks).\n */\n requirements: v.optional(v.record(NonEmpty, ConditionSchema)),\n /**\n * Auto-completion condition — evaluated at activation and on every\n * cascade; truthy flips the task to `done` with a system actor. On a\n * spawning task it typically reads `$subworkflows`.\n */\n completeWhen: v.optional(ConditionSchema),\n /**\n * Auto-failure condition — symmetric to `completeWhen`, flips to\n * `failed`. When both are truthy on the same evaluation, `failWhen`\n * wins — failure is the more notable signal.\n */\n failWhen: v.optional(ConditionSchema),\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n actions: v.optional(v.array(action)),\n subworkflows: v.optional(SubworkflowsSchema),\n /** Task-scoped state entries. Resolved at task activation time. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredTaskSchema = v.strictObject(\n taskFields(StateEntrySchema, StoredActionSchema, StoredOpSchema),\n)\nexport type Task = v.InferOutput<typeof StoredTaskSchema>\n\nexport const AuthoringTaskSchema = v.strictObject(\n taskFields(AuthoringStateEntrySchema, AuthoringActionSchema, AuthoringOpSchema),\n)\nexport type AuthoringTask = v.InferOutput<typeof AuthoringTaskSchema>\n\n// Transitions — purely a condition over the rendered scope. Selection rule:\n// every transition is evaluated on every commit and cascade; the first truthy\n// `filter` in declaration order fires. No action coupling: a routing\n// difference is written into state by the action and read by the filter.\n\nfunction transitionFields<TOp extends v.GenericSchema, TFilter extends v.GenericSchema>(\n op: TOp,\n filter: TFilter,\n) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n to: NonEmpty,\n filter,\n /** The `state.*` subset — state-write-on-move, the stage's EXIT/ARRIVAL payload. */\n ops: v.optional(v.array(op)),\n effects: v.optional(v.array(EffectSchema)),\n }\n}\n\nconst StoredTransitionSchema = v.strictObject(\n transitionFields(StoredTransitionOpSchema, ConditionSchema),\n)\nexport type Transition = v.InferOutput<typeof StoredTransitionSchema>\n\n/**\n * Authoring transitions may omit `filter`; desugar fills the safe,\n * overwhelmingly-common gate `\"$allTasksDone\"`. \"Fire unconditionally\"\n * stays spellable as an explicit `filter: \"true\"`.\n */\nconst AuthoringTransitionOpSchema = v.variant('type', [\n ...opSchemas(AuthoringStateRefSchema),\n AuditOpSchema,\n])\nexport const AuthoringTransitionSchema = v.strictObject(\n transitionFields(AuthoringTransitionOpSchema, v.optional(ConditionSchema)),\n)\nexport type AuthoringTransition = v.InferOutput<typeof AuthoringTransitionSchema>\n\n// Guards — lake mutation guards. A FOREIGN CONTRACT mirrored 1:1: the\n// `temp.system.guard` doc's `match` / `predicate` / `metadata` fields are the\n// content lake's API, not engine surface, so authoring keeps the lake's\n// vocabulary verbatim. The engine adds exactly two things: `name` (authoring\n// identity — the lake `_id` derives from (instanceId, guard.name)) and\n// `$state`-read VALUES (`idRefs: [\"$state.subject\"]`, `metadata.outcome:\n// \"$state.outcome\"`), resolved at deploy into the bare values the contract\n// expects. Guards + the lake ACL are the only HARD gates in the system.\n\nconst GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS)\nexport type GuardAction = v.InferOutput<typeof GuardActionSchema>\n\nconst GuardMatchSchema = v.strictObject({\n /** Subject `_type`(s); empty matches any type. */\n types: v.optional(v.array(NonEmpty)),\n /** Target docs as `$state` reads (or `\"$self\"`), resolved at deploy to bare ids + the resource. */\n idRefs: v.optional(v.array(NonEmpty)),\n /** Glob id patterns (bare, resource-local). */\n idPatterns: v.optional(v.array(NonEmpty)),\n actions: v.pipe(\n v.array(GuardActionSchema),\n v.minLength(1, 'a guard must match at least one action'),\n ),\n})\nexport type GuardMatch = v.InferOutput<typeof GuardMatchSchema>\n\nexport const GuardSchema = v.strictObject({\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n match: GuardMatchSchema,\n /**\n * Lake GROQ predicate — a distinct eval context reading\n * `document.before`/`document.after`, `mutation`, `guard`, and\n * `identity()`. Bare ids/fields only. Omitted or empty means\n * UNCONDITIONAL DENY.\n */\n predicate: v.optional(v.string()),\n /**\n * Projected workflow state the predicate reads as `guard.metadata.*` —\n * the only bridge from the lake eval context (which cannot see `$state`)\n * to workflow state. Values are NOT GROQ: each is a deploy-time read in\n * the guard mini-language — `\"$self\"`, `\"$now\"`, or\n * `\"$state.<name>[.path]\"` — resolved into a bare value at deploy and\n * re-synced by the post-state-op guard refresh.\n */\n metadata: v.optional(v.record(NonEmpty, NonEmpty)),\n})\nexport type Guard = v.InferOutput<typeof GuardSchema>\n\n// Stages — pure containers: name / state / guards / tasks / transitions, no\n// behaviour of their own. Tasks own enter, transitions own exit and arrival.\n// `initial` is whatever `initialStage` names; a stage with no transitions IS\n// terminal (structural, nothing to declare or mis-declare).\n\nfunction stageFields<\n TState extends v.GenericSchema,\n TTask extends v.GenericSchema,\n TTransition extends v.GenericSchema,\n>(state: TState, task: TTask, transition: TTransition) {\n return {\n name: NonEmpty,\n title: v.optional(v.string()),\n description: v.optional(v.string()),\n tasks: v.optional(v.array(task)),\n transitions: v.optional(v.array(transition)),\n /**\n * Lake mutation guards active while this stage holds. Each compiles to a\n * `temp.system.guard` doc deployed on stage entry and retracted on exit.\n */\n guards: v.optional(v.array(GuardSchema)),\n /** Stage-scoped state entries. Resolved at stage entry. */\n state: v.optional(v.array(state)),\n }\n}\n\nconst StoredStageSchema = v.strictObject(\n stageFields(StateEntrySchema, StoredTaskSchema, StoredTransitionSchema),\n)\nexport type Stage = v.InferOutput<typeof StoredStageSchema>\n\nexport const AuthoringStageSchema = v.strictObject(\n stageFields(AuthoringStateEntrySchema, AuthoringTaskSchema, AuthoringTransitionSchema),\n)\nexport type AuthoringStage = v.InferOutput<typeof AuthoringStageSchema>\n\n// Workflow definition (the root)\n\nconst WORKFLOW_ROLES = ['workflow', 'child'] as const\n/** A definition's lifecycle role. `'child'` is spawn-only — see {@link isStartableDefinition}. */\nexport type WorkflowRole = (typeof WORKFLOW_ROLES)[number]\n\nfunction workflowFields<TState extends v.GenericSchema, TStage extends v.GenericSchema>(\n state: TState,\n stage: TStage,\n) {\n return {\n name: NonEmpty,\n version: PositiveInt,\n title: NonEmpty,\n description: v.optional(v.string()),\n /**\n * Whether a human may start this workflow standalone. `'child'` marks a\n * spawn-only definition — instantiated by a parent via `task.subworkflows`,\n * never started cold from a picker. Omitted ⇒ `'workflow'` (startable).\n * Advisory: consumers filter their start pickers on it (see\n * {@link isStartableDefinition}); the engine does NOT refuse a\n * `startInstance` on a `'child'` def — load-bearing `required` state is the\n * runtime backstop.\n */\n role: v.optional(picklist(WORKFLOW_ROLES)),\n /** Reference field: named for the target, holds the stage's `name`. */\n initialStage: NonEmpty,\n /** Workflow-scope state entries. Persist for the instance lifetime. */\n state: v.optional(v.array(state)),\n stages: v.pipe(v.array(stage), v.minLength(1, 'must declare at least one stage')),\n /**\n * Nullary named conditions — each `name: groq` entry is pre-evaluated\n * and bound as the boolean `$name` var, composable with native GROQ.\n * Redefining a built-in var is a deploy error (never silently shadow).\n */\n predicates: v.optional(v.record(groqIdentifier('`$<name>`'), ConditionSchema)),\n }\n}\n\n/**\n * Structural schema for a STORED workflow definition — primitives only,\n * every reference scope resolved. Cross-field invariants (unique names,\n * transition targets, effect-name uniqueness, predicate shadowing) are\n * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.\n */\nconst WorkflowDefinitionSchema = v.strictObject(workflowFields(StateEntrySchema, StoredStageSchema))\nexport type WorkflowDefinition = v.InferOutput<typeof WorkflowDefinitionSchema>\n\n/** The authoring surface: stored primitives plus the define-time sugar. */\nexport const AuthoringWorkflowSchema = v.strictObject(\n workflowFields(AuthoringStateEntrySchema, AuthoringStageSchema),\n)\nexport type AuthoringWorkflow = v.InferOutput<typeof AuthoringWorkflowSchema>\n\n/**\n * The lake document type for a deployed workflow definition. Engine-owned\n * standalone documents carry the platform namespace; in-array discriminators\n * stay bare. Mirrors {@link WORKFLOW_INSTANCE_TYPE}.\n */\nexport const WORKFLOW_DEFINITION_TYPE = 'sanity.workflow.definition'\n\n/**\n * Whether a human may start this definition standalone (the default). A\n * `role: 'child'` definition is spawn-only — instantiated by a parent via\n * `task.subworkflows`, so consumers exclude it from top-level start pickers.\n * Advisory: the engine does not enforce it (see the `required`-state backstop\n * for load-bearing init slots). Accepts any definition-shaped value (authored,\n * stored, deployed, or a projected list row).\n */\nexport function isStartableDefinition(definition: {role?: WorkflowRole | undefined}): boolean {\n return definition.role !== 'child'\n}\n\n// Error formatting — turn validation issues into a multi-line,\n// path-prefixed message that points at the exact field the author got\n// wrong. Shared by structural parse errors (via {@link issuesFromValibot})\n// and cross-field invariant issues.\n\nexport interface ValidationIssue {\n path: ReadonlyArray<PropertyKey>\n message: string\n}\n\n/** The buildable path form desugar and the invariants accumulate issues under. */\nexport type IssuePath = (string | number)[]\n\nexport function formatValidationError(label: string, issues: readonly ValidationIssue[]): string {\n const lines = issues.map((issue) => {\n const path = issue.path.length === 0 ? '(root)' : formatPath(issue.path)\n return ` - ${path}: ${issue.message}`\n })\n return `${label} failed validation (${issues.length} issue${\n issues.length === 1 ? '' : 's'\n }):\\n${lines.join('\\n')}`\n}\n\nexport function issuesFromValibot(issues: readonly v.BaseIssue<unknown>[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? issue.path.map((item) => item.key as PropertyKey) : [],\n message: issue.message,\n }))\n}\n\nfunction formatPath(path: ReadonlyArray<PropertyKey>): string {\n let out = ''\n for (const seg of path) {\n if (typeof seg === 'number') out += `[${seg}]`\n else out += out.length === 0 ? String(seg) : `.${String(seg)}`\n }\n return out\n}\n"],"names":[],"mappings":"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"}
|
package/dist/define.cjs
CHANGED
|
@@ -58,6 +58,7 @@ function desugarWorkflow(authoring) {
|
|
|
58
58
|
version: authoring.version,
|
|
59
59
|
title: authoring.title,
|
|
60
60
|
description: authoring.description,
|
|
61
|
+
role: authoring.role,
|
|
61
62
|
initialStage: authoring.initialStage,
|
|
62
63
|
predicates: authoring.predicates
|
|
63
64
|
}),
|
|
@@ -91,6 +92,7 @@ function desugarTask(task, path, stageEnv, ctx) {
|
|
|
91
92
|
title: task.title,
|
|
92
93
|
description: task.description,
|
|
93
94
|
filter: task.filter,
|
|
95
|
+
requirements: task.requirements,
|
|
94
96
|
completeWhen: task.completeWhen,
|
|
95
97
|
failWhen: task.failWhen,
|
|
96
98
|
effects: task.effects,
|
|
@@ -362,22 +364,37 @@ function checkGuardNames(def, issues) {
|
|
|
362
364
|
);
|
|
363
365
|
}
|
|
364
366
|
function stateScopes(def) {
|
|
365
|
-
const scopes = [
|
|
367
|
+
const scopes = [
|
|
368
|
+
{ entries: def.state, scope: "workflow", path: ["state"], label: "workflow state" }
|
|
369
|
+
];
|
|
366
370
|
for (const [i, stage] of def.stages.entries()) {
|
|
367
371
|
scopes.push({
|
|
368
372
|
entries: stage.state,
|
|
373
|
+
scope: "stage",
|
|
369
374
|
path: ["stages", i, "state"],
|
|
370
375
|
label: `stage "${stage.name}" state`
|
|
371
376
|
});
|
|
372
377
|
for (const [j, task] of (stage.tasks ?? []).entries())
|
|
373
378
|
scopes.push({
|
|
374
379
|
entries: task.state,
|
|
380
|
+
scope: "task",
|
|
375
381
|
path: ["stages", i, "tasks", j, "state"],
|
|
376
382
|
label: `task "${task.name}" state`
|
|
377
383
|
});
|
|
378
384
|
}
|
|
379
385
|
return scopes;
|
|
380
386
|
}
|
|
387
|
+
function checkRequiredState(def, issues) {
|
|
388
|
+
for (const { entries, scope, path, label } of stateScopes(def))
|
|
389
|
+
for (const [n, entry] of (entries ?? []).entries())
|
|
390
|
+
entry.required === !0 && (scope !== "workflow" ? issues.push({
|
|
391
|
+
path: [...path, n, "required"],
|
|
392
|
+
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`
|
|
393
|
+
}) : entry.source.type !== "init" && issues.push({
|
|
394
|
+
path: [...path, n, "required"],
|
|
395
|
+
message: `state 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)`
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
381
398
|
function checkStateEntryNames(def, issues) {
|
|
382
399
|
for (const { entries, path, label } of stateScopes(def))
|
|
383
400
|
checkDuplicates(
|
|
@@ -490,7 +507,7 @@ function checkAssigneesEntries(def, issues) {
|
|
|
490
507
|
}
|
|
491
508
|
function checkWorkflowInvariants(def) {
|
|
492
509
|
const issues = [], stageNames = checkStages(def, issues);
|
|
493
|
-
return checkInitialStage(def, stageNames, issues), checkTransitionTargets(def, stageNames, issues), checkEffectNames(def, issues), checkGuardNames(def, issues), checkStateEntryNames(def, issues), checkPredicates(def, issues), checkCanOutsideActionFilters(def, issues), checkAssigneesEntries(def, issues), issues;
|
|
510
|
+
return checkInitialStage(def, stageNames, issues), checkTransitionTargets(def, stageNames, issues), checkEffectNames(def, issues), checkGuardNames(def, issues), checkStateEntryNames(def, issues), checkRequiredState(def, issues), checkPredicates(def, issues), checkCanOutsideActionFilters(def, issues), checkAssigneesEntries(def, issues), issues;
|
|
494
511
|
}
|
|
495
512
|
function defineWorkflow(definition) {
|
|
496
513
|
const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow(schema.AuthoringWorkflowSchema, definition, label), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
|