@hatua/model 0.0.0 → 0.1.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/tree.d.ts ADDED
@@ -0,0 +1,311 @@
1
+ import { Block, Branch, Step, Variable, WorkflowDefinition } from '@hatua/schema';
2
+ /**
3
+ * Pure domain rules over the step tree. No state, no I/O, no YAML — those live
4
+ * in @hatua/document. Everything here is a function of the typed projection.
5
+ */
6
+ /**
7
+ * Which Board a Step sits on: a Block's id, or `null` for the root Board.
8
+ *
9
+ * `null` rather than a sentinel string because the root Board is not a Block and
10
+ * has no id to borrow — a string would have to be one no Block could ever be
11
+ * called, which is a reserved word this design spent ADR-0014 getting rid of.
12
+ */
13
+ export type BoardId = string | null;
14
+ /**
15
+ * One drawable Step tree and the root that gives it its parameters.
16
+ *
17
+ * A document holds the root Board, whose root is `triggers:`, plus one per
18
+ * Block, whose root is its declared contract. Scope is computed against a Board
19
+ * and never across two, which is what keeps a call a cross-link with a contract
20
+ * rather than a jump (ADR-0013).
21
+ */
22
+ export interface Board {
23
+ readonly id: BoardId;
24
+ /** The Block this Board belongs to. Absent on the root Board. */
25
+ readonly block?: Block;
26
+ readonly steps: readonly Step[];
27
+ }
28
+ /**
29
+ * Read one key of a document-supplied map.
30
+ *
31
+ * `Object.hasOwn` is the whole guarantee, and it is the same one `resolve.ts`
32
+ * gives for `{{ steps.s2.constructor }}`. A Workflow Definition is user-editable
33
+ * YAML and the schema's identifier rule permits underscores, so `__proto__` is a
34
+ * legal field key, a legal declaration key and a legal var key — and a bare
35
+ * `values[k]` there reads `Object.prototype` rather than nothing, which makes a
36
+ * missing value look present. Go has no prototype to find, so this is also what
37
+ * keeps the two languages saying the same thing about the same document.
38
+ */
39
+ export declare const own: (values: Record<string, unknown> | undefined, key: string) => unknown;
40
+ /** A Step, and the Board it is on. Neither half identifies one alone. */
41
+ export interface StepRef {
42
+ readonly board: BoardId;
43
+ readonly id: string;
44
+ }
45
+ /** A position among a list of sibling Steps, named in domain terms rather than YAML paths. */
46
+ export interface InsertPoint {
47
+ /**
48
+ * Which Board the position is on: a Block's id, or absent for the root.
49
+ *
50
+ * Every path below is rooted here rather than at `['steps']`. That single
51
+ * parameter is what makes an edit on a Block's Board the same command as an
52
+ * edit on the root's — which is the property the extract-into-a-block gesture
53
+ * needs, and what keeps a Block built on the canvas and one hand-written in
54
+ * Text Mode the same document.
55
+ */
56
+ board?: BoardId;
57
+ /**
58
+ * The container Step whose children receive it. Absent for the Board's
59
+ * root sequence.
60
+ */
61
+ parentId?: string;
62
+ /**
63
+ * Which of a `core.fork`'s branches, by index. Absent for a `core.for_each`'s
64
+ * own nested `steps`, and absent at the root.
65
+ */
66
+ branchIndex?: number;
67
+ /**
68
+ * Which of a `core.try`'s two regions. Absent means the body under `steps:`,
69
+ * which is the same key a loop's children sit under.
70
+ *
71
+ * A named region rather than a second index, because the two are not a list:
72
+ * a try has exactly one body and exactly one handler, and an index would let
73
+ * a caller ask for the third one.
74
+ */
75
+ region?: 'handler';
76
+ /** Position among the siblings. The list's length appends. */
77
+ index: number;
78
+ }
79
+ /**
80
+ * Every Board in the document, root first.
81
+ *
82
+ * This is the traversal that cannot forget a Block. A validator walking
83
+ * `doc.steps` sees a document with three Blocks in it and reports nothing about
84
+ * any of them, silently — so nothing here walks `doc.steps` directly.
85
+ */
86
+ export declare function boards(doc: WorkflowDefinition): Generator<Board>;
87
+ /** One Board by id, or undefined when nothing declares it. */
88
+ export declare function boardOf(doc: WorkflowDefinition, id: BoardId): Board | undefined;
89
+ /**
90
+ * The verb that protects a region and falls back to a handler.
91
+ *
92
+ * The one container with two child regions: a body under `steps:` and a handler
93
+ * under `handler:`. Wrapping one Step is retry, wrapping a region is fallback,
94
+ * so one verb serves both (ADR-0013).
95
+ *
96
+ * Its retry policy — how many attempts, how long to wait — sits in `with:` as
97
+ * ordinary manifest fields, and deliberately NOT in a structural key. `until`
98
+ * had to leave `with:` because `FIELD_KIND_TYPES` has no mappable boolean, so a
99
+ * condition there would have type-checked as text. An attempt count is a number
100
+ * and `number` IS a mappable field kind, so the argument that moved `until` does
101
+ * not reach here at all — following it anyway would be copying a conclusion
102
+ * without its reason, and would cost a structural key, a diagnostic and a form
103
+ * control that the manifest already gives for nothing.
104
+ *
105
+ * It sits beside the region vocabulary rather than beside the other verbs
106
+ * because the only question anything asks it is which word goes over a region:
107
+ * `steps:` is one key holding a loop's children and a try's protected body
108
+ * alike, and this is what tells them apart.
109
+ */
110
+ export declare const TRY_VERB = "core.try";
111
+ /**
112
+ * The verb that repeats its children until a condition holds.
113
+ *
114
+ * It sits beside `TRY_VERB` and the region vocabulary because the only question
115
+ * anything asks it here is whether a region always runs: a `core.repeat` tests
116
+ * its `until` AFTER the body, so the body runs at least once, while a
117
+ * `core.for_each`'s list may be empty and its body may never run. `steps:` is
118
+ * one key holding both, so the verb is what tells them apart.
119
+ */
120
+ export declare const REPEAT_VERB = "core.repeat";
121
+ /** Which of a container's child regions a step list is. */
122
+ export type RegionKind = 'branch' | 'body' | 'handler';
123
+ /**
124
+ * One child region a container Step owns, and which region it is.
125
+ *
126
+ * A Fork contributes one per Branch, a `core.for_each` and a `core.repeat` one
127
+ * body each, and a `core.try` two — a body under `steps:` and a handler under
128
+ * `handler:` (ADR-0013).
129
+ */
130
+ export interface Region {
131
+ readonly kind: RegionKind;
132
+ readonly steps: readonly Step[];
133
+ /**
134
+ * The word that goes over this region — `if` / `else if` / `else` / `and`
135
+ * over a Branch, `attempt` or `loop` over a body, `on failure` over a
136
+ * handler.
137
+ *
138
+ * Here rather than at each surface, because two surfaces draw every region:
139
+ * `<StepList>` puts it in a chip over the region and the canvas puts it in
140
+ * the band above it, and a word each works out for itself is a word they can
141
+ * disagree about. `kind` says which region this is and this says what it is
142
+ * called, so a reader gains both by construction.
143
+ *
144
+ * The verb decides the word and never whether the region exists. A `handler:`
145
+ * on a `core.fork` is meaningless and no runner reads it, but `walkSteps`
146
+ * still yields the Steps inside it, so a surface refusing to draw it makes
147
+ * those Steps unreachable rather than absent.
148
+ */
149
+ readonly keyword: string;
150
+ /**
151
+ * Whether this region runs every time its Step does.
152
+ *
153
+ * A Branch does not — its `when` is answered at run time. A `core.try`'s body
154
+ * does, because it always starts; its handler does not, because it needs a
155
+ * failure. A `core.repeat`'s body does, because `until` is tested after it; a
156
+ * `core.for_each`'s does not, because the list may be empty.
157
+ *
158
+ * That is the same line `alwaysReturns` in validity.ts draws to decide whether
159
+ * a region discharges a Block's obligation to return — one question, "is this
160
+ * region guaranteed to run at all", asked here of geometry and there of
161
+ * validity. Two readings of it are two answers waiting to disagree.
162
+ */
163
+ readonly always: boolean;
164
+ /** The Branch this region is. Absent on a body and on a handler. */
165
+ readonly branch?: Branch;
166
+ }
167
+ /**
168
+ * The regions one Step owns, in document order.
169
+ *
170
+ * The single answer to "what does this Step nest". Every traversal of the tree
171
+ * asks that question, and one that answers it for itself is one that can forget
172
+ * a region — a region no rule then sees, reported by nothing, in silence. That
173
+ * has to be spelled out once so a reader gains coverage of a new region by
174
+ * construction rather than by remembering to ask for it.
175
+ *
176
+ * The region is named rather than yielded as a bare list because a reader that
177
+ * says something different about each — the word over it, whether it always
178
+ * runs — still has to get its regions from here.
179
+ */
180
+ export declare function regionsOf(step: Step): Generator<Region>;
181
+ /**
182
+ * Whether a Step owns child regions at all.
183
+ *
184
+ * Asked of `regionsOf` rather than of the three keys, so "container" and "what a
185
+ * container nests" cannot come apart — a fourth region would otherwise be
186
+ * walked by every reader while still reading as a leaf to whichever surface
187
+ * decides how tall a card is or whether it collapses.
188
+ */
189
+ export declare const isContainer: (step: Step) => boolean;
190
+ /**
191
+ * What a Step is called on screen: its name, falling back to its id.
192
+ *
193
+ * An id is the one thing a Step always has, and it is what a user typed if they
194
+ * hand-wrote the file. Here rather than at each surface because the list, the
195
+ * canvas and every sentence a screen reader hears have to name one Step one
196
+ * way — two spellings is a card and a row that look like two Steps.
197
+ */
198
+ export declare const nameOf: (step: Step) => string;
199
+ /**
200
+ * What makes a Step structural, in words: `core.fork · 2 branches`,
201
+ * `core.try · 1 step · handler`.
202
+ *
203
+ * Enumerated off `regionsOf` rather than off the three step keys, so a region
204
+ * added to the walk shows up in the summary by construction. A summary read off
205
+ * `steps:` alone says `core.try` on a try carrying only a handler — a card with
206
+ * a chevron and an `on failure` region under it, describing itself as a leaf.
207
+ *
208
+ * A leaf's summary is its verb and nothing else, which is why the canvas shows
209
+ * this only on the cards `isContainer` makes taller: `LAYOUT.nodeHeight` is "a
210
+ * card with a name and nothing else", so a leaf card has nowhere to put a row.
211
+ * One predicate decides the height and the content, and they cannot come apart.
212
+ */
213
+ export declare function summaryOf(step: Step): string;
214
+ /**
215
+ * Depth-first walk of every step in one tree, parents before children.
216
+ *
217
+ * Every region a container owns is walked here and nowhere else. A region
218
+ * `regionsOf` forgets is a region no rule ever sees — the validator reports
219
+ * nothing about it, silently, which is the same failure as a validator that
220
+ * only ever looked at the root Board.
221
+ */
222
+ export declare function walkSteps(steps: readonly Step[]): Generator<Step>;
223
+ /**
224
+ * Every Step in the document, tagged with the Board it is on.
225
+ *
226
+ * `walkSteps` is the primitive — "walk this list" — and this is what supplies it
227
+ * every list there is. A rule written against this one gains Block coverage by
228
+ * construction rather than by remembering to ask for it.
229
+ */
230
+ export declare function walkDocument(doc: WorkflowDefinition): Generator<StepRef & {
231
+ step: Step;
232
+ }>;
233
+ /**
234
+ * One string naming one Step, for the places that need a flat key — a `Map`, a
235
+ * React key, a `data-` attribute.
236
+ *
237
+ * Minted here rather than concatenated at each call site: five hand-rolled
238
+ * spellings are five chances to pick a different separator, and two of them
239
+ * disagreeing is a diagnostic filed under a key nothing looks up. `/` is safe
240
+ * because the schema holds every id to an identifier, which cannot contain one.
241
+ */
242
+ export declare const stepKey: ({ board, id }: StepRef) => string;
243
+ /**
244
+ * One Board as a string, for a reader that holds something per Board.
245
+ *
246
+ * Prefixed rather than the bare id, because the root Board is `null` and a
247
+ * Block whose id is the empty string would key the same — so the two would
248
+ * share whatever is held, and opening that Block would find the root's.
249
+ *
250
+ * Minted here for the reason `stepKey` is: a viewport keyed one way and a
251
+ * selection keyed another are two maps that disagree about which Board is which.
252
+ */
253
+ export declare const boardKey: (id: BoardId) => string;
254
+ /**
255
+ * One child region, and the Step it hangs under.
256
+ *
257
+ * A `StepRef` widened by which of that Step's regions this is, because a
258
+ * `core.try` owns two and a Fork owns *n* — so a Step alone does not name one.
259
+ * The shape composes with what a `Band` already carries, so the canvas can name
260
+ * the region it is drawing without a second enumeration.
261
+ *
262
+ * Named by `kind` rather than by an ordinal into `regionsOf`, because anything
263
+ * held against a region — which one is folded shut — outlives the edits made
264
+ * while it is held. A body and a handler have a `kind` that names them
265
+ * outright, so neither takes a number and neither can move: adding a Branch to
266
+ * a Fork that also carries a `handler:` would have shifted an ordinal.
267
+ *
268
+ * **A Branch is not stable, and cannot be.** `branchIndex` is an ordinal into
269
+ * `branches:`, so inserting a Branch before it moves the fold onto its
270
+ * neighbour. There is nothing better to use: a Branch carries no id, and the
271
+ * schema refuses its `label` for identity because that is free text a user
272
+ * renames. Naming a Branch by *where it is* is the whole of what is available,
273
+ * and the narrower spelling buys the other two regions and not this one.
274
+ */
275
+ export interface RegionRef {
276
+ readonly board: BoardId;
277
+ /** The container Step that owns the region. */
278
+ readonly id: string;
279
+ readonly kind: RegionKind;
280
+ /** Which of the owner's Branches this is. Absent on a body and on a handler. */
281
+ readonly branchIndex?: number;
282
+ }
283
+ /**
284
+ * One string naming one region, for the places that need a flat key — a `Set`, a
285
+ * React key, a `data-` attribute.
286
+ *
287
+ * Minted beside `stepKey` and for the same reason: hand-rolled spellings are
288
+ * chances to pick a different separator, and two readers disagreeing about the
289
+ * spelling is a region folded under a key nothing looks up. `#` and `:` are safe
290
+ * because the schema holds every id to an identifier, which contains neither.
291
+ */
292
+ export declare const regionKey: ({ board, id, kind, branchIndex }: RegionRef) => string;
293
+ /** A Step by Board and id. Both halves are needed: ids are Board-local. */
294
+ export declare function findStep(doc: WorkflowDefinition, ref: StepRef): Step | undefined;
295
+ /**
296
+ * The variables one Board declares: the workflow's at the root, a Block's inside
297
+ * one.
298
+ *
299
+ * This is the whole of "a `core.set_var` can never reach out of the Board it is
300
+ * on" — there is no second list to fall back to, so a Block naming a workflow
301
+ * variable is an unknown name rather than a scope a runner resolves differently.
302
+ *
303
+ * Exported because a runner has to answer the same question the builder does,
304
+ * and the Go SDK's `VarsOn` is this function: a rule restated at two call sites
305
+ * is two rules the day one of them gains a fallback.
306
+ */
307
+ export declare const varsOn: (doc: WorkflowDefinition, board: BoardId) => readonly Variable[];
308
+ /** One Board's variable by key, or undefined when that Board declares none. */
309
+ export declare const variableOn: (doc: WorkflowDefinition, board: BoardId, key: string) => Variable | undefined;
310
+ /** Every step id on one Board, for detecting references to steps that vanished. */
311
+ export declare function stepIds(doc: WorkflowDefinition, board: BoardId): Set<string>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,167 @@
1
+ import { FunctionDeclarations } from '@hatua/expressions';
2
+ import { ContextKey, Manifest, WorkflowDefinition } from '@hatua/schema';
3
+ import { ConnectionTypes } from './connections';
4
+ import { Diagnostic } from './diagnostic';
5
+ /**
6
+ * Whether a Workflow Definition is filled in enough to run — the rules that read
7
+ * a Step against its Component Manifest, the verbs Hatua interprets
8
+ * structurally, the contract a Block declares, and the Connections a `conn`
9
+ * field may hold.
10
+ *
11
+ * Here rather than in @hatua/services for the same reason `tree.ts` is: these
12
+ * are pure domain rules over the typed projection, so a Host's runner can hold
13
+ * a definition to exactly what the builder held it to. The store that watches
14
+ * them and the region that draws a dot are separate concerns and live
15
+ * elsewhere.
16
+ *
17
+ * Every code and what it blocks is declared in
18
+ * `schemas/definition-diagnostics.yaml` and generated into both languages,
19
+ * because `blocks` is part of the contract: a code that stopped Publish here and
20
+ * merely informed in Go would let a workflow publish from one builder and not
21
+ * another.
22
+ *
23
+ * Nothing below walks `doc.steps`. `walkDocument` yields every Step on every
24
+ * Board, so a rule written here covers a Block's steps by construction — the
25
+ * alternative is a validator that reports nothing about three Blocks, silently,
26
+ * because it only ever looked at the root.
27
+ */
28
+ type ManifestIndex = ReadonlyMap<string, Manifest>;
29
+ /**
30
+ * Whether a field is shown, and therefore whether it can be missing.
31
+ *
32
+ * `when: [otherKey, value]` shows a field only while another field equals a
33
+ * value — it is how one trigger component reshapes its form across schedule,
34
+ * API and upstream modes. Counting a hidden field as unfilled would mark a Step
35
+ * invalid for a field the user cannot see, let alone fill.
36
+ *
37
+ * Exported because the form that draws the fields has to ask the same question,
38
+ * and two copies of it are two answers waiting to disagree: a hidden field that
39
+ * starts blocking Publish, or a visible required one that stops being reported.
40
+ * `reference.ts` and `slots.ts` refuse the same duplication for the same
41
+ * reason — the rule lives once, in the package that owns the domain.
42
+ */
43
+ export declare const fieldVisible: (field: Manifest["fields"][number], values: Record<string, unknown>) => boolean;
44
+ /**
45
+ * Required fields with nothing in them, per Step.
46
+ *
47
+ * A call and a `core.return` are checked against a declaration rather than a
48
+ * manifest — `block.<id>`'s fields are the Block's `params`, and a return's are
49
+ * the Block's `outputs`. Every parameter is required: a declaration IS the
50
+ * contract, and an optional one would be a second concept for a Block to carry.
51
+ */
52
+ export declare function missingRequiredFields(doc: WorkflowDefinition, manifests: ManifestIndex): Diagnostic[];
53
+ /**
54
+ * A Step or a Trigger whose verb nothing declares.
55
+ *
56
+ * The two roots fail differently, so they are two codes. A `component.*` verb
57
+ * nothing declares blocks editing, because building cannot produce it: the
58
+ * catalogue only offers what it declares, so it means a hand-edit or a Host that
59
+ * dropped a component — and in the second case the fields are gone too, so there
60
+ * is nothing to fill in. A `block.*` verb naming nothing blocks Publish only:
61
+ * renaming or deleting a block is ordinary building, and locking the document
62
+ * for editing over a name the user can fix three lines away would be absurd.
63
+ *
64
+ * Triggers are checked alongside Steps because the same mistake is possible in
65
+ * `triggers:` and has the same consequence: `missingRequiredFields` returns
66
+ * early for a manifest it cannot find, so without this a Trigger naming a verb
67
+ * nothing declares produces no diagnostic at all, while the Board panel draws
68
+ * it as a card that says its type is unknown.
69
+ */
70
+ export declare function unknownComponents(doc: WorkflowDefinition, manifests: ManifestIndex): Diagnostic[];
71
+ /**
72
+ * The verbs Hatua interprets structurally, held to what they mean.
73
+ *
74
+ * These are read from the tree rather than from a manifest, because a manifest
75
+ * cannot express them: `core.fork`'s Branches and `core.for_each`'s body are
76
+ * positions in the document, not fields under `with:`.
77
+ */
78
+ export declare function malformedContainers(doc: WorkflowDefinition, manifests?: ManifestIndex): Diagnostic[];
79
+ /**
80
+ * The rules a Block carries: recursion, where a return may sit, and whether one
81
+ * is reached.
82
+ *
83
+ * Recursion is answered here rather than by a runner's depth limit because
84
+ * ADR-0013 refuses it at design time — "unbounded recursion is the jump problem
85
+ * wearing a contract's clothes" — so both builders refuse the same document
86
+ * rather than one of them discovering it in production.
87
+ */
88
+ export declare function blockRules(doc: WorkflowDefinition): Diagnostic[];
89
+ /** Every step-level rule, in one pass, indexed by the Step it belongs to. */
90
+ export interface Validity {
91
+ /**
92
+ * Diagnostics for each Step that has any, keyed by `stepKey` — Board and id
93
+ * together, because a Block's `ret` and another Block's `ret` are two Steps.
94
+ */
95
+ byStep: ReadonlyMap<string, Diagnostic[]>;
96
+ /** The same, for Triggers, which are not Steps and are drawn by another region. */
97
+ byTrigger: ReadonlyMap<string, Diagnostic[]>;
98
+ /** The same, for what belongs to a Block rather than to any Step in it. */
99
+ byBlock: ReadonlyMap<string, Diagnostic[]>;
100
+ /**
101
+ * The same, for what belongs to a Connection rather than to any Step using it.
102
+ *
103
+ * Only CONNECTION_NOT_ESTABLISHED files here: the other connection codes are
104
+ * raised at a field, so they name a Step or a Trigger as well and belong on
105
+ * the row the user can act on. A Connection declared and never wired is at
106
+ * fault on its own — it is unfinished whether or not anything points at it
107
+ * yet — and there is no Step to hang it on.
108
+ *
109
+ * A fourth map for the reason the second and third exist, and the fault is
110
+ * filed once here rather than raised again at every field that points at the
111
+ * Connection — the duplication `troubledBlocks` refuses for a call, one seam
112
+ * over: a Publish gate counting faults must not count one Connection five
113
+ * times because five Steps use it. The `conn` field that draws it looks the
114
+ * Connection up by the id it holds.
115
+ */
116
+ byConnection: ReadonlyMap<string, Diagnostic[]>;
117
+ /**
118
+ * Everything, in the order the rules ran.
119
+ *
120
+ * Returned rather than left to a caller to flatten out of `byStep`: a
121
+ * diagnostic about a Trigger has no `stepId`, so flattening the Step map
122
+ * silently drops it — and a Publish gate counting what it found there would
123
+ * pass a workflow whose Trigger is missing a required field.
124
+ */
125
+ all: readonly Diagnostic[];
126
+ }
127
+ /**
128
+ * Every Template on every Board, checked against the type its field declares
129
+ * and the scope its Step can see.
130
+ *
131
+ * The fifth rule family, and the one that reaches into a different package:
132
+ * `@hatua/expressions` owns the grammar and the checking, and has done since
133
+ * before anything called it. What was missing was the walk — "which Templates
134
+ * are there, and what may each of them address" is a question about a Workflow
135
+ * Definition, which is this package's subject and not that one's.
136
+ *
137
+ * **Errors only.** An expression diagnostic carries a severity, and a warning
138
+ * informs without blocking anything (ADR-0009's gradual typing: an unprovable
139
+ * type defers to run time). A `Diagnostic` here carries `blocks` instead, whose
140
+ * two values both block something, so a warning has nothing to become. The
141
+ * Inspector calls `validate` itself and renders every severity; this pass exists
142
+ * to mark cards and gate Publish, and neither is a warning's business.
143
+ *
144
+ * **Steps only.** A Trigger's fields and a Variable's initial value are
145
+ * Templates too, and neither has a scope anyone has defined — `scopeFor` takes a
146
+ * `StepRef` because a scope is a position in a tree, and a Trigger is upstream
147
+ * of every position. Checking them against a scope invented here would be a
148
+ * second answer to a question the model has not been asked yet.
149
+ */
150
+ export declare function expressionRules(doc: WorkflowDefinition, manifests: ManifestIndex, context?: readonly ContextKey[], functions?: FunctionDeclarations): Diagnostic[];
151
+ /**
152
+ * Every rule family over every Board, filed by the subject each one names.
153
+ *
154
+ * `connectionTypes` is the one input that is not the document or a manifest. A
155
+ * Connection stores an opaque `ref` and nothing more (ADR-0007), so its type
156
+ * comes from the Host, asynchronously, and may never come at all — a Host that
157
+ * wires no `ConnectionSource` is correctly configured, not broken.
158
+ *
159
+ * **Absence narrows this pass; it never stops it.** Handed no types, the two
160
+ * connection codes that need one go unreported and every other family runs
161
+ * exactly as it would have. The alternative — returning nothing until the
162
+ * Connections arrive — would leave a Host that wires no `ConnectionSource` with
163
+ * no validation whatsoever, silently, including the rules that have nothing to
164
+ * do with Connections. See ADR-0022.
165
+ */
166
+ export declare function validateDefinition(doc: WorkflowDefinition, manifests: ManifestIndex, context?: readonly ContextKey[], connectionTypes?: ConnectionTypes): Validity;
167
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,17 +1,39 @@
1
1
  {
2
2
  "name": "@hatua/model",
3
- "version": "0.0.0",
4
- "description": "Placeholder reserving the name. Nothing is published here; see 0.1.0 and later.",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Internal to @hatua/react — published because it is an external of its build, not a supported API. Pure domain rules over the step tree: references, scope, validation.",
5
6
  "license": "MIT",
6
7
  "repository": {
7
8
  "type": "git",
8
9
  "url": "git+https://github.com/pedromvgomes/hatua.git",
9
10
  "directory": "source/packages/model"
10
11
  },
12
+ "sideEffects": false,
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
11
22
  "publishConfig": {
12
23
  "access": "public"
13
24
  },
14
- "files": [
15
- "README.md"
16
- ]
25
+ "dependencies": {
26
+ "@hatua/schema": "0.1.0",
27
+ "@hatua/expressions": "0.1.0",
28
+ "@hatua/document": "0.1.0"
29
+ },
30
+ "devDependencies": {
31
+ "yaml": "^2.8.1"
32
+ },
33
+ "scripts": {
34
+ "build": "vite build",
35
+ "typecheck": "tsc --noEmit",
36
+ "test": "vitest run --passWithNoTests",
37
+ "test:coverage": "vitest run --coverage --coverage.reporter=text-summary --coverage.reporter=json-summary --coverage.reporter=lcovonly --passWithNoTests"
38
+ }
17
39
  }
package/README.md DELETED
@@ -1,5 +0,0 @@
1
- # @hatua/model
2
-
3
- This version reserves the package name and contains no code.
4
-
5
- Install `0.1.0` or later.