@tai42/api-client 13.2.2 → 14.0.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/src/errors.ts CHANGED
@@ -15,12 +15,26 @@ export class ApiError extends Error {
15
15
  * caller that does not ignores it.
16
16
  */
17
17
  readonly retryAfterSeconds?: number;
18
- constructor(message: string, status: number, code?: string, retryAfterSeconds?: number) {
18
+ /**
19
+ * The full parsed error body (`{ error, code, …extra }`), when the failure carried a
20
+ * JSON body. Operations spread structured follow-up data beside the message (e.g. a
21
+ * reconcile refusal's `{ reconcile: true, orphans: [...] }`), so a UI keys its
22
+ * follow-up on this DATA, not on the prose. `undefined` when the body was not JSON.
23
+ */
24
+ readonly body?: unknown;
25
+ constructor(
26
+ message: string,
27
+ status: number,
28
+ code?: string,
29
+ retryAfterSeconds?: number,
30
+ body?: unknown,
31
+ ) {
19
32
  super(message);
20
33
  this.name = 'ApiError';
21
34
  this.status = status;
22
35
  this.code = code;
23
36
  this.retryAfterSeconds = retryAfterSeconds;
37
+ this.body = body;
24
38
  }
25
39
  }
26
40
 
@@ -34,8 +48,8 @@ export class ApiUnauthorizedError extends ApiError {
34
48
 
35
49
  /** A duplicate answer / alias collision etc. (HTTP 409). */
36
50
  export class ApiConflictError extends ApiError {
37
- constructor(message: string) {
38
- super(message, 409);
51
+ constructor(message: string, body?: unknown) {
52
+ super(message, 409, undefined, undefined, body);
39
53
  this.name = 'ApiConflictError';
40
54
  }
41
55
  }
package/src/http.ts CHANGED
@@ -132,8 +132,10 @@ export async function apiRequest<S extends z.ZodType>(
132
132
  if (!response.ok) {
133
133
  const { message, code } = extractError(payload);
134
134
  const text = message ?? (response.statusText || 'request failed');
135
- if (response.status === 409) throw new ApiConflictError(text);
136
- throw new ApiError(text, response.status, code, retryAfter);
135
+ // The parsed body rides the error so a caller can key a follow-up on its structured
136
+ // fields (e.g. a reconcile refusal's `orphans`), never on the message prose.
137
+ if (response.status === 409) throw new ApiConflictError(text, payload);
138
+ throw new ApiError(text, response.status, code, retryAfter, payload);
137
139
  }
138
140
 
139
141
  if (!isDataEnvelope(payload)) {
package/src/index.ts CHANGED
@@ -26,8 +26,8 @@ export type {
26
26
  SavePresetVersionBody,
27
27
  ValidatePresetBody,
28
28
  StateDeclarationBody,
29
- StateModuleBody,
30
- StateMountBody,
29
+ StateTemplateBody,
30
+ StateAttachmentBody,
31
31
  StateSubjectRef,
32
32
  StatePageQuery,
33
33
  ToolMetaPatch,
@@ -109,13 +109,21 @@ export type {
109
109
  StateSubject,
110
110
  StateDeclaration,
111
111
  StateListItem,
112
- StateMount,
112
+ StateAttachment,
113
113
  StateDetail,
114
114
  StateStats,
115
- StateModuleDocument,
116
- StateModuleListItem,
117
- RecordView,
115
+ TemplateJq,
116
+ TemplateReconcile,
117
+ StateTemplateDocument,
118
+ StateTemplateListItem,
119
+ StateInjection,
120
+ StateUpdate,
121
+ StateAttach,
122
+ StateBinding,
123
+ StateRecord,
118
124
  ApplyResult,
125
+ TemplateJqResult,
126
+ TemplateJqApplyResult,
119
127
  SubjectRow,
120
128
  SubjectPage,
121
129
  RecordSearchPage,
@@ -125,9 +133,9 @@ export type {
125
133
  ConsumerLink,
126
134
  ConsumerRow,
127
135
  StateConsumers,
128
- StateMounted,
129
- StateMountUpdated,
130
- StateUnmounted,
136
+ StateAttached,
137
+ StateAttachmentUpdated,
138
+ StateDetached,
131
139
  StateFoldReport,
132
140
  StateRetentionPruned,
133
141
  FolderRecord,
package/src/schemas.ts CHANGED
@@ -115,8 +115,9 @@ export const presetExtensions = z.array(z.array(presetExtensionElement));
115
115
  * One preset as `GET /api/presets` returns it. Every preset is versioned, so
116
116
  * `active_version` is always an int; `conflicted` marks a QUARANTINED row (its
117
117
  * name collided with a foreign tool at boot — delete-only). `extensions` are the
118
- * ACTIVE version's extension combos and `output_schema` the optional author-set
119
- * output JSON Schema. Categorization tags live in the tool_meta overlay
118
+ * ACTIVE version's extension combos, `output_schema` the optional author-set
119
+ * output JSON Schema, and `input_schema` the optional author-set input JSON
120
+ * Schema. Categorization tags live in the tool_meta overlay
120
121
  * (`GET /api/tool-meta`), never on the record. A drift throws `ApiSchemaError`;
121
122
  * nothing is coerced.
122
123
  */
@@ -127,6 +128,7 @@ export const presetRecord = z.object({
127
128
  active_version: z.number(),
128
129
  extensions: presetExtensions,
129
130
  output_schema: z.record(z.string(), z.unknown()).nullable(),
131
+ input_schema: z.record(z.string(), z.unknown()).nullable(),
130
132
  conflicted: z.boolean(),
131
133
  // The human-readable cause a row is quarantined (its name collided with a
132
134
  // foreign tool at boot), or `null` when the row is not conflicted. Rendered
@@ -147,6 +149,75 @@ export const presetDetail = presetRecord.extend({
147
149
  });
148
150
  export type PresetDetail = z.infer<typeof presetDetail>;
149
151
 
152
+ /**
153
+ * One input injection of a state binding: BEFORE the run, a value is produced and
154
+ * placed into the run input under `into` (the run-input field name). A template
155
+ * `input` jq (`template_jq`, named `name` or attachment-qualified `template.name`) reads the
156
+ * record — its input is the record (`.`), with declared params bound as `$params`; a
157
+ * custom `jq` reads `{record, input}` → the value. Exactly one of `template_jq`/`jq`
158
+ * carries the program; the other is `null`.
159
+ */
160
+ export const stateInjection = z.object({
161
+ template_jq: z.string().nullable().default(null),
162
+ jq: z.string().nullable().default(null),
163
+ into: z.string(),
164
+ });
165
+ export type StateInjection = z.infer<typeof stateInjection>;
166
+
167
+ /**
168
+ * One update of a state binding: AFTER the run, a template-relative op batch is
169
+ * applied through the store. A NAMED update (`template_jq`) runs the template `update`
170
+ * jq over `{record, input}` where `input` is built by `adapter` — a jq over
171
+ * `{output, input}` that constructs the update jq's declared input object. A custom
172
+ * `jq` runs over `{record, output, input}` → `[{op, path, value}]` and carries no
173
+ * adapter. `op_id` is an optional idempotency-key expression. Exactly one of
174
+ * `template_jq`/`jq` carries the program.
175
+ */
176
+ export const stateUpdate = z.object({
177
+ template_jq: z.string().nullable().default(null),
178
+ jq: z.string().nullable().default(null),
179
+ // A named update's adapter is either a non-empty jq or `null` (no adapter — the
180
+ // run input passes through). `min(1)` makes the empty string impossible to
181
+ // round-trip: the platform compile-checks any non-null adapter and refuses `''`.
182
+ adapter: z.string().min(1).nullable().default(null),
183
+ op_id: z.string().nullable().default(null),
184
+ });
185
+ export type StateUpdate = z.infer<typeof stateUpdate>;
186
+
187
+ /**
188
+ * One attached state of a binding: the `state`, one or more `templates`
189
+ * (attach-on-use — attached to the state on the binding's save), the `subject_expr`
190
+ * (a jq yielding the record KEY — a bare key string OR a full subject object — that
191
+ * this binding reads and updates), an optional `scope_expr` (a boolean jq predicate;
192
+ * when it is false this state is skipped for the run), and the ordered
193
+ * `input_injections` (before the run) and `updates` (after it).
194
+ */
195
+ export const stateAttach = z.object({
196
+ state: z.string(),
197
+ templates: z.array(z.string()).default([]),
198
+ // The platform contract enforces a non-empty subject (min_length=1); an empty
199
+ // expression is rejected here, never sent for the server to refuse.
200
+ subject_expr: z.string().min(1),
201
+ scope_expr: z.string().nullable().default(null),
202
+ input_injections: z.array(stateInjection).default([]),
203
+ updates: z.array(stateUpdate).default([]),
204
+ });
205
+ export type StateAttach = z.infer<typeof stateAttach>;
206
+
207
+ /**
208
+ * The one generic binding shape carried, optionally, on every runnable definition
209
+ * (a preset, a channel route, a schedule, a hook) and repeated per node by the
210
+ * flow engine. It attaches one or more states, each with its templates, subject,
211
+ * injections and updates. `null` on a definition means no binding. Mirrors the
212
+ * platform `StateBinding` document.
213
+ */
214
+ export const stateBinding = z.object({
215
+ // At least one attached state: the platform contract refuses a zero-state binding, so
216
+ // "no binding" is spelled `null` on the definition, never `{ states: [] }`.
217
+ states: z.array(stateAttach).min(1),
218
+ });
219
+ export type StateBinding = z.infer<typeof stateBinding>;
220
+
150
221
  /** The full version body a preset stores under `kind="preset"`. */
151
222
  export const presetBody = z.object({
152
223
  base_tool: z.string(),
@@ -154,6 +225,10 @@ export const presetBody = z.object({
154
225
  fixed_kwargs: z.record(z.string(), z.unknown()),
155
226
  extensions: presetExtensions,
156
227
  output_schema: z.record(z.string(), z.unknown()).nullable(),
228
+ input_schema: z.record(z.string(), z.unknown()).nullable(),
229
+ // The optional door-layer state binding this preset applies around every run
230
+ // (`null` when the preset touches no state).
231
+ state_binding: stateBinding.nullable().default(null),
157
232
  });
158
233
  export type PresetBody = z.infer<typeof presetBody>;
159
234
 
@@ -1140,6 +1215,9 @@ export const conversationRoute = z.object({
1140
1215
  turns_per_hour_override: z.number().int().nullable().default(null),
1141
1216
  error_reply_text: z.string().nullable().default(null),
1142
1217
  execution_key_fingerprint: z.string(),
1218
+ // The door-layer state binding the backend stores on the route's target config and
1219
+ // returns on read (`null` when the route touches no state) — the edit form prefills it.
1220
+ state_binding: stateBinding.nullable().default(null),
1143
1221
  });
1144
1222
  export type ConversationRoute = z.infer<typeof conversationRoute>;
1145
1223
 
@@ -1176,6 +1254,9 @@ export const conversationRouteCreate = z.object({
1176
1254
  callback_url: z.string().nullable().default(null),
1177
1255
  turns_per_hour_override: z.number().int().positive().nullable().default(null),
1178
1256
  error_reply_text: z.string().min(1).max(2000).nullable().default(null),
1257
+ // The optional door-layer state binding this route applies around every turn's
1258
+ // tool run (`null` when the route touches no state).
1259
+ state_binding: stateBinding.nullable().default(null),
1179
1260
  });
1180
1261
  export type ConversationRouteCreate = z.infer<typeof conversationRouteCreate>;
1181
1262
 
@@ -1540,6 +1621,9 @@ export const hookParams = z.object({
1540
1621
  expr: z.string().nullable().default(null),
1541
1622
  expr_id: z.string().nullable().default(null),
1542
1623
  expr_kwargs: z.record(z.string(), z.unknown()).default({}),
1624
+ // The optional door-layer state binding this hook applies around its fire's tool
1625
+ // run (`null` when the hook touches no state).
1626
+ state_binding: stateBinding.nullable().default(null),
1543
1627
  });
1544
1628
  export type HookParams = z.infer<typeof hookParams>;
1545
1629
 
@@ -2613,11 +2697,11 @@ export { toolRunSubmitResult, toolRunRecord, toolRunList } from './tool-runs';
2613
2697
 
2614
2698
  // -- states ------------------------------------------------------------------
2615
2699
  // Shapes mirror tai42_contract.states.models: a declared JSON document, one per
2616
- // subject. The base document, module fragments, write regimes and effective schema
2700
+ // subject. The base document, template fragments, write regimes and effective schema
2617
2701
  // are permissive JSON records — the auto-form and JsonTree interpret them at runtime;
2618
- // a drift throws ApiSchemaError. Fields that WP-3's router is finishing concurrently
2619
- // (`effective_schema`, `regimes`, list/stats derived columns) are modelled optional so
2620
- // a server that has not yet composed them still parses.
2702
+ // a drift throws ApiSchemaError. Server-composed fields (`effective_schema`, `regimes`,
2703
+ // list/stats derived columns) are modelled optional so a response that omits them still
2704
+ // parses.
2621
2705
 
2622
2706
  /** One addressed subject: the conversation-target scope plus the (kind, key) within it. */
2623
2707
  export const stateSubject = z.object({
@@ -2628,12 +2712,12 @@ export const stateSubject = z.object({
2628
2712
  });
2629
2713
  export type StateSubject = z.infer<typeof stateSubject>;
2630
2714
 
2631
- /** One absolute write-regime rule composed over the mounts: `{path, regime}`, permissive. */
2715
+ /** One absolute write-regime rule composed over the attachments: `{path, regime}`, permissive. */
2632
2716
  export const stateRegime = z.record(z.string(), z.unknown());
2633
2717
 
2634
2718
  /**
2635
2719
  * A declared state served on every read. `schema` is the base JSON Schema;
2636
- * `effective_schema` (the base composed with every mounted module's fragment) and
2720
+ * `effective_schema` (the base composed with every attached template's fragment) and
2637
2721
  * `regimes` (the absolute write-regime rules) are platform-COMPUTED and served on every
2638
2722
  * read — modelled optional so a write body that omits them, or a server yet to compose
2639
2723
  * them, still parses. A drift throws ApiSchemaError.
@@ -2662,19 +2746,19 @@ export const stateListItem = stateDeclaration.extend({
2662
2746
  export type StateListItem = z.infer<typeof stateListItem>;
2663
2747
  export const stateList = z.array(stateListItem);
2664
2748
 
2665
- /** One module mount on a state: where the fragment lands + its param/declaration values. */
2666
- export const stateMount = z.object({
2667
- module: z.string(),
2749
+ /** One template attachment on a state: where the fragment lands + its param/declaration values. */
2750
+ export const stateAttachment = z.object({
2751
+ template: z.string(),
2668
2752
  path: z.array(z.string()),
2669
2753
  parameters: z.record(z.string(), z.unknown()).default({}),
2670
2754
  declarations: z.record(z.string(), z.unknown()).default({}),
2671
2755
  });
2672
- export type StateMount = z.infer<typeof stateMount>;
2673
- export const stateMountList = z.array(stateMount);
2756
+ export type StateAttachment = z.infer<typeof stateAttachment>;
2757
+ export const stateAttachmentList = z.array(stateAttachment);
2674
2758
 
2675
- /** `GET /api/states/{name}` — the declaration (with effective schema + regimes) plus mounts. */
2759
+ /** `GET /api/states/{name}` — the declaration (with effective schema + regimes) plus attachments. */
2676
2760
  export const stateDetail = stateDeclaration.extend({
2677
- mounts: z.array(stateMount).default([]),
2761
+ attachments: z.array(stateAttachment).default([]),
2678
2762
  });
2679
2763
  export type StateDetail = z.infer<typeof stateDetail>;
2680
2764
 
@@ -2692,9 +2776,43 @@ export const stateStats = z.object({
2692
2776
  });
2693
2777
  export type StateStats = z.infer<typeof stateStats>;
2694
2778
 
2695
- /** The platform half of a state-module document (mirrors StateModuleDocument). */
2696
- export const stateModuleDocument = z.object({
2697
- kind: z.literal('state-module').default('state-module'),
2779
+ /**
2780
+ * One template jq: `jq` is a program over the subject's attached subtree, its `purpose`
2781
+ * either `input` (a read-only program feeding a tool argument) or `update` (a program
2782
+ * returning an op batch that mutates the record). `params` are its declared argument
2783
+ * names; `reads`/`writes` are the template-relative record paths an `update` declares,
2784
+ * each a list of key segments; `description` is the human label.
2785
+ */
2786
+ export const templateJq = z.object({
2787
+ description: z.string().default(''),
2788
+ purpose: z.enum(['input', 'update']),
2789
+ params: z.array(z.string()).default([]),
2790
+ reads: z.array(z.array(z.string())).default([]),
2791
+ writes: z.array(z.array(z.string())).default([]),
2792
+ jq: z.string(),
2793
+ });
2794
+ export type TemplateJq = z.infer<typeof templateJq>;
2795
+
2796
+ /**
2797
+ * How a declarations edit settles open records: `view` reads the record, `close`
2798
+ * builds the op batch that settles it, `resolutions` names the resolutions a close
2799
+ * may name — each a jq program.
2800
+ */
2801
+ export const templateReconcile = z.object({
2802
+ view: z.string(),
2803
+ close: z.string(),
2804
+ resolutions: z.string(),
2805
+ });
2806
+ export type TemplateReconcile = z.infer<typeof templateReconcile>;
2807
+
2808
+ /**
2809
+ * The platform half of a state-template document (mirrors StateTemplateDocument).
2810
+ * `template_jq` maps a name to its definition (each carrying its `purpose`);
2811
+ * `reconcile` is the settle policy — both optional (`null` when the template declares
2812
+ * none).
2813
+ */
2814
+ export const stateTemplateDocument = z.object({
2815
+ kind: z.literal('state-template').default('state-template'),
2698
2816
  name: z.string(),
2699
2817
  description: z.string().default(''),
2700
2818
  parameters: z.record(z.string(), z.unknown()).default({}),
@@ -2702,24 +2820,26 @@ export const stateModuleDocument = z.object({
2702
2820
  regimes: z.array(stateRegime).default([]),
2703
2821
  declarations: z.record(z.string(), z.unknown()).nullable().default(null),
2704
2822
  trace: z.record(z.string(), z.unknown()).default({}),
2823
+ template_jq: z.record(z.string(), templateJq).nullable().default(null),
2824
+ reconcile: templateReconcile.nullable().default(null),
2705
2825
  });
2706
- export type StateModuleDocument = z.infer<typeof stateModuleDocument>;
2826
+ export type StateTemplateDocument = z.infer<typeof stateTemplateDocument>;
2707
2827
 
2708
2828
  /**
2709
- * One row of `GET /api/state-modules`. The module document plus the two derived columns
2710
- * the Modules tab shows: `mounted_on` (how many states mount it — a delete is refused
2711
- * while > 0) and `shipped_default` (a platform-shipped module). ASSUMED derived fields
2712
- * (WP-3 owns the list router); the document fields are verbatim.
2829
+ * One row of `GET /api/state-templates`. The template document plus the two derived columns
2830
+ * the Templates tab shows: `attached_to` (how many states attach it — a delete is refused
2831
+ * while > 0) and `shipped_default` (a platform-shipped template). Both are server-derived
2832
+ * columns; the document fields are verbatim.
2713
2833
  */
2714
- export const stateModuleListItem = stateModuleDocument.extend({
2715
- mounted_on: z.number().default(0),
2834
+ export const stateTemplateListItem = stateTemplateDocument.extend({
2835
+ attached_to: z.number().default(0),
2716
2836
  shipped_default: z.boolean().default(false),
2717
2837
  });
2718
- export type StateModuleListItem = z.infer<typeof stateModuleListItem>;
2719
- export const stateModuleList = z.array(stateModuleListItem);
2838
+ export type StateTemplateListItem = z.infer<typeof stateTemplateListItem>;
2839
+ export const stateTemplateList = z.array(stateTemplateListItem);
2720
2840
 
2721
2841
  /** A read record: the state, its subject, the document + monotonic seq, and any fold. */
2722
- export const recordView = z.object({
2842
+ export const stateRecord = z.object({
2723
2843
  state: z.string(),
2724
2844
  subject: stateSubject,
2725
2845
  data: z.record(z.string(), z.unknown()).default({}),
@@ -2727,7 +2847,7 @@ export const recordView = z.object({
2727
2847
  canonical_subject: stateSubject,
2728
2848
  folded_from: z.array(stateSubject).default([]),
2729
2849
  });
2730
- export type RecordView = z.infer<typeof recordView>;
2850
+ export type StateRecord = z.infer<typeof stateRecord>;
2731
2851
 
2732
2852
  /** The outcome of an `apply` (a delta batch): whether it applied + the resulting doc. */
2733
2853
  export const applyResult = z.object({
@@ -2738,6 +2858,33 @@ export const applyResult = z.object({
2738
2858
  });
2739
2859
  export type ApplyResult = z.infer<typeof applyResult>;
2740
2860
 
2861
+ /**
2862
+ * `GET …/template-jq/{name}` — the evaluated template jq's `name`, its `purpose`, and
2863
+ * its `value` (the `input` jq's read). GET evaluates ONLY an `input`-purpose jq; a GET
2864
+ * on an `update`-purpose name is refused with 422, so the result's purpose is always
2865
+ * `input`.
2866
+ */
2867
+ export const templateJqResult = z.object({
2868
+ name: z.string(),
2869
+ purpose: z.literal('input'),
2870
+ value: z.unknown(),
2871
+ });
2872
+ export type TemplateJqResult = z.infer<typeof templateJqResult>;
2873
+
2874
+ /**
2875
+ * `POST …/template-jq/{name}` — the applied template jq's outcome. The jq lands an op
2876
+ * batch through the same `apply` chokepoint as a delta, so `applied`/`data`/`seq`/`skipped`
2877
+ * carry that outcome.
2878
+ */
2879
+ export const templateJqApplyResult = z.object({
2880
+ name: z.string(),
2881
+ applied: z.boolean(),
2882
+ data: z.record(z.string(), z.unknown()).nullable().default(null),
2883
+ seq: z.number().nullable().default(null),
2884
+ skipped: z.array(z.record(z.string(), z.unknown())).default([]),
2885
+ });
2886
+ export type TemplateJqApplyResult = z.infer<typeof templateJqApplyResult>;
2887
+
2741
2888
  /**
2742
2889
  * One paged subject row: the addressed `subject` plus its record's last-write
2743
2890
  * `updated_at` — epoch seconds (the store's `extract(epoch FROM updated_at)`), served
@@ -2831,29 +2978,29 @@ export type StateConsumers = z.infer<typeof stateConsumers>;
2831
2978
  /** `DELETE /api/states/{name}` — the removed state. */
2832
2979
  export const stateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
2833
2980
 
2834
- /** `PUT /api/states/{name}/mounts/{module}` — the module now mounted on the state. */
2835
- export const stateMounted = z.object({
2836
- mounted: z.literal(true),
2981
+ /** `PUT /api/states/{name}/attachments/{template}` — the template now attached to the state. */
2982
+ export const stateAttached = z.object({
2983
+ attached: z.literal(true),
2837
2984
  state: z.string(),
2838
- module: z.string(),
2985
+ template: z.string(),
2839
2986
  });
2840
- export type StateMounted = z.infer<typeof stateMounted>;
2987
+ export type StateAttached = z.infer<typeof stateAttached>;
2841
2988
 
2842
- /** `PATCH /api/states/{name}/mounts/{module}` — the mount whose declarations were rewritten. */
2843
- export const stateMountUpdated = z.object({
2989
+ /** `PATCH /api/states/{name}/attachments/{template}` — the attachment whose declarations were rewritten. */
2990
+ export const stateAttachmentUpdated = z.object({
2844
2991
  updated: z.literal(true),
2845
2992
  state: z.string(),
2846
- module: z.string(),
2993
+ template: z.string(),
2847
2994
  });
2848
- export type StateMountUpdated = z.infer<typeof stateMountUpdated>;
2995
+ export type StateAttachmentUpdated = z.infer<typeof stateAttachmentUpdated>;
2849
2996
 
2850
- /** `DELETE /api/states/{name}/mounts/{module}` — the module unmounted from the state. */
2851
- export const stateUnmounted = z.object({
2852
- unmounted: z.literal(true),
2997
+ /** `DELETE /api/states/{name}/attachments/{template}` — the template detached from the state. */
2998
+ export const stateDetached = z.object({
2999
+ detached: z.literal(true),
2853
3000
  state: z.string(),
2854
- module: z.string(),
3001
+ template: z.string(),
2855
3002
  });
2856
- export type StateUnmounted = z.infer<typeof stateUnmounted>;
3003
+ export type StateDetached = z.infer<typeof stateDetached>;
2857
3004
 
2858
3005
  /**
2859
3006
  * `POST /api/states/{name}/records/.../fold` — the fold report: the `mode`, the
@@ -2869,8 +3016,8 @@ export const stateFoldReport = z.object({
2869
3016
  });
2870
3017
  export type StateFoldReport = z.infer<typeof stateFoldReport>;
2871
3018
 
2872
- /** `DELETE /api/state-modules/{name}` — the removed module document. */
2873
- export const stateModuleDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
3019
+ /** `DELETE /api/state-templates/{name}` — the removed template document. */
3020
+ export const stateTemplateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
2874
3021
 
2875
3022
  /** `DELETE /api/states/{name}/records/...` — the erased record marker. */
2876
3023
  export const recordErased = z.object({ erased: z.literal(true) });