@camstack/types 1.2.266 → 1.2.268

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.
Files changed (57) hide show
  1. package/dist/addon.js +4 -4
  2. package/dist/addon.mjs +3 -3
  3. package/dist/capabilities/battery.cap.d.ts +17 -2
  4. package/dist/capabilities/capability-definition.d.ts +22 -0
  5. package/dist/capabilities/composer.cap.d.ts +99 -0
  6. package/dist/capabilities/consumables.cap.d.ts +79 -0
  7. package/dist/capabilities/core-blocks.cap.d.ts +1149 -91
  8. package/dist/capabilities/device-extension.cap.d.ts +12 -13
  9. package/dist/capabilities/device-state.cap.d.ts +186 -2
  10. package/dist/capabilities/index.d.ts +3 -3
  11. package/dist/capabilities/pipeline-analytics.cap.d.ts +14 -0
  12. package/dist/composition/composition-graph.d.ts +42 -9
  13. package/dist/composition/composition-items.d.ts +25 -0
  14. package/dist/composition/composition-report.d.ts +93 -2
  15. package/dist/composition/composition.d.ts +154 -3
  16. package/dist/composition/customization-name.d.ts +6 -0
  17. package/dist/composition/evaluate-field.d.ts +12 -0
  18. package/dist/composition/examples.d.ts +33 -0
  19. package/dist/composition/field-kinds.d.ts +42 -0
  20. package/dist/composition/index.d.ts +1 -0
  21. package/dist/composition/plan-result.d.ts +16 -0
  22. package/dist/composition/state-fields.d.ts +6 -0
  23. package/dist/composition/validate-composition.d.ts +44 -9
  24. package/dist/composition-CPFIlFfw.mjs +1759 -0
  25. package/dist/composition-QlOB7QTG.js +2184 -0
  26. package/dist/device/device-context.d.ts +9 -0
  27. package/dist/device/device-runtime-state.d.ts +15 -1
  28. package/dist/device/index.d.ts +1 -1
  29. package/dist/device-extension/slot-descriptor.d.ts +8 -11
  30. package/dist/device-extension/slot-provider.d.ts +0 -2
  31. package/dist/enums/event-category.d.ts +25 -0
  32. package/dist/enums.js +1 -1
  33. package/dist/enums.mjs +1 -1
  34. package/dist/err-msg-DX6i_MY4.mjs +339 -0
  35. package/dist/err-msg-Dx2Kor0g.js +368 -0
  36. package/dist/{event-category-BVDXG4tB.mjs → event-category-C5xZWqz6.mjs} +31 -1
  37. package/dist/{event-category-BVfsrBYA.js → event-category-MbnB-6AN.js} +48 -0
  38. package/dist/generated/addon-api.d.ts +42 -0
  39. package/dist/generated/device-proxy.d.ts +1 -1
  40. package/dist/generated/method-access-map.d.ts +1 -1
  41. package/dist/generated/method-device-selectors.d.ts +2 -2
  42. package/dist/generated/system-proxy.d.ts +2 -2
  43. package/dist/index.d.ts +4 -3
  44. package/dist/index.js +1548 -1660
  45. package/dist/index.mjs +1243 -1388
  46. package/dist/interfaces/kernel-abstractions.d.ts +16 -0
  47. package/dist/interfaces/status-overlay.d.ts +42 -0
  48. package/dist/node.d.ts +1 -0
  49. package/dist/node.js +29 -8
  50. package/dist/node.mjs +23 -3
  51. package/dist/{sleep-8K9gue-H.js → sleep-BSzia-xT.js} +6 -352
  52. package/dist/{sleep-DC-wdyeS.mjs → sleep-jkRQgtSc.mjs} +7 -329
  53. package/package.json +1 -1
  54. package/dist/canonical-hash-CPK2Dy60.mjs +0 -715
  55. package/dist/canonical-hash-CSE4ioRi.js +0 -792
  56. package/dist/err-msg-COpsHMw2.js +0 -18
  57. package/dist/err-msg-IQTHeDzc.mjs +0 -13
@@ -21,6 +21,11 @@ export declare const CompositionProblemCodeSchema: z.ZodEnum<{
21
21
  "expression-invalid": "expression-invalid";
22
22
  cycle: "cycle";
23
23
  "duplicate-target": "duplicate-target";
24
+ "not-item-array": "not-item-array";
25
+ "item-field-reserved": "item-field-reserved";
26
+ "target-missing": "target-missing";
27
+ "target-unreadable": "target-unreadable";
28
+ "not-replaceable": "not-replaceable";
24
29
  }>;
25
30
  export type CompositionProblemCode = z.infer<typeof CompositionProblemCodeSchema>;
26
31
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
@@ -43,6 +48,11 @@ export declare const CompositionProblemSchema: z.ZodObject<{
43
48
  "expression-invalid": "expression-invalid";
44
49
  cycle: "cycle";
45
50
  "duplicate-target": "duplicate-target";
51
+ "not-item-array": "not-item-array";
52
+ "item-field-reserved": "item-field-reserved";
53
+ "target-missing": "target-missing";
54
+ "target-unreadable": "target-unreadable";
55
+ "not-replaceable": "not-replaceable";
46
56
  }>;
47
57
  path: z.ZodString;
48
58
  message: z.ZodString;
@@ -55,10 +65,17 @@ export declare const CompositionFieldKindSchema: z.ZodEnum<{
55
65
  enum: "enum";
56
66
  }>;
57
67
  export type CompositionFieldKind = z.infer<typeof CompositionFieldKindSchema>;
58
- /** How a field says "unavailable": `null` when its schema allows it, else the device goes offline (D393). */
68
+ /**
69
+ * How a field says "unavailable" (D393, D663): `null` when its schema allows it;
70
+ * `unknown` — the enum's own word — for an ADDED field that has one; `release`
71
+ * for a REPLACED field of an existing device, whose claim is released so the
72
+ * native provider's reading shows again; else the (composed) device goes offline.
73
+ */
59
74
  export declare const CompositionUnavailableModeSchema: z.ZodEnum<{
60
75
  null: "null";
76
+ unknown: "unknown";
61
77
  offline: "offline";
78
+ release: "release";
62
79
  }>;
63
80
  export type CompositionUnavailableMode = z.infer<typeof CompositionUnavailableModeSchema>;
64
81
  /**
@@ -71,9 +88,21 @@ export declare const CompositionFieldRoleSchema: z.ZodEnum<{
71
88
  constant: "constant";
72
89
  }>;
73
90
  export type CompositionFieldRole = z.infer<typeof CompositionFieldRoleSchema>;
91
+ /** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
92
+ export declare const CompositionFieldItemSchema: z.ZodObject<{
93
+ arrayPath: z.ZodString;
94
+ key: z.ZodString;
95
+ label: z.ZodString;
96
+ }, z.core.$strip>;
97
+ export type CompositionFieldItem = z.infer<typeof CompositionFieldItemSchema>;
74
98
  export declare const CompositionFieldPlanSchema: z.ZodObject<{
75
99
  cap: z.ZodString;
76
100
  path: z.ZodString;
101
+ item: z.ZodOptional<z.ZodObject<{
102
+ arrayPath: z.ZodString;
103
+ key: z.ZodString;
104
+ label: z.ZodString;
105
+ }, z.core.$strip>>;
77
106
  featureIndex: z.ZodNumber;
78
107
  kind: z.ZodEnum<{
79
108
  string: "string";
@@ -85,7 +114,9 @@ export declare const CompositionFieldPlanSchema: z.ZodObject<{
85
114
  required: z.ZodBoolean;
86
115
  unavailable: z.ZodEnum<{
87
116
  null: "null";
117
+ unknown: "unknown";
88
118
  offline: "offline";
119
+ release: "release";
89
120
  }>;
90
121
  role: z.ZodEnum<{
91
122
  derived: "derived";
@@ -129,6 +160,29 @@ export declare const CompositionFieldPlanSchema: z.ZodObject<{
129
160
  }, z.core.$strip>>;
130
161
  }, z.core.$strip>;
131
162
  export type CompositionFieldPlan = z.infer<typeof CompositionFieldPlanSchema>;
163
+ /** The key every record map, log line and graph node uses for a planned field. Two items' `status` are two keys. */
164
+ export declare function compositionFieldKey(plan: Pick<CompositionFieldPlan, 'cap' | 'path' | 'item'>): string;
165
+ /**
166
+ * What a feature does to its target (D663): `new` builds a capability on a new
167
+ * device; on an existing device it `add`s a capability the device lacks, or
168
+ * `replace`s named fields of one it has natively.
169
+ */
170
+ export declare const CompositionFeatureModeSchema: z.ZodEnum<{
171
+ new: "new";
172
+ replace: "replace";
173
+ add: "add";
174
+ }>;
175
+ export type CompositionFeatureMode = z.infer<typeof CompositionFeatureModeSchema>;
176
+ export declare const CompositionFeaturePlanSchema: z.ZodObject<{
177
+ featureIndex: z.ZodNumber;
178
+ cap: z.ZodString;
179
+ mode: z.ZodEnum<{
180
+ new: "new";
181
+ replace: "replace";
182
+ add: "add";
183
+ }>;
184
+ }, z.core.$strip>;
185
+ export type CompositionFeaturePlan = z.infer<typeof CompositionFeaturePlanSchema>;
132
186
  export declare const CompositionValidationSchema: z.ZodObject<{
133
187
  ok: z.ZodBoolean;
134
188
  problems: z.ZodArray<z.ZodObject<{
@@ -150,6 +204,11 @@ export declare const CompositionValidationSchema: z.ZodObject<{
150
204
  "expression-invalid": "expression-invalid";
151
205
  cycle: "cycle";
152
206
  "duplicate-target": "duplicate-target";
207
+ "not-item-array": "not-item-array";
208
+ "item-field-reserved": "item-field-reserved";
209
+ "target-missing": "target-missing";
210
+ "target-unreadable": "target-unreadable";
211
+ "not-replaceable": "not-replaceable";
153
212
  }>;
154
213
  path: z.ZodString;
155
214
  message: z.ZodString;
@@ -157,6 +216,11 @@ export declare const CompositionValidationSchema: z.ZodObject<{
157
216
  fields: z.ZodArray<z.ZodObject<{
158
217
  cap: z.ZodString;
159
218
  path: z.ZodString;
219
+ item: z.ZodOptional<z.ZodObject<{
220
+ arrayPath: z.ZodString;
221
+ key: z.ZodString;
222
+ label: z.ZodString;
223
+ }, z.core.$strip>>;
160
224
  featureIndex: z.ZodNumber;
161
225
  kind: z.ZodEnum<{
162
226
  string: "string";
@@ -168,7 +232,9 @@ export declare const CompositionValidationSchema: z.ZodObject<{
168
232
  required: z.ZodBoolean;
169
233
  unavailable: z.ZodEnum<{
170
234
  null: "null";
235
+ unknown: "unknown";
171
236
  offline: "offline";
237
+ release: "release";
172
238
  }>;
173
239
  role: z.ZodEnum<{
174
240
  derived: "derived";
@@ -211,14 +277,28 @@ export declare const CompositionValidationSchema: z.ZodObject<{
211
277
  fieldPath: z.ZodString;
212
278
  }, z.core.$strip>>;
213
279
  }, z.core.$strip>>;
280
+ features: z.ZodArray<z.ZodObject<{
281
+ featureIndex: z.ZodNumber;
282
+ cap: z.ZodString;
283
+ mode: z.ZodEnum<{
284
+ new: "new";
285
+ replace: "replace";
286
+ add: "add";
287
+ }>;
288
+ }, z.core.$strip>>;
214
289
  }, z.core.$strip>;
215
290
  export type CompositionValidation = z.infer<typeof CompositionValidationSchema>;
216
- /** Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts` (Task 11). */
291
+ /**
292
+ * Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
293
+ * running, but a replaced field is released to the native provider while its
294
+ * source is unavailable (ruling S1b, D663) — the reason names each such field.
295
+ */
217
296
  export declare const CompositionRunStatusSchema: z.ZodEnum<{
218
297
  running: "running";
219
298
  failed: "failed";
220
299
  stopped: "stopped";
221
300
  starting: "starting";
301
+ degraded: "degraded";
222
302
  }>;
223
303
  export type CompositionRunStatus = z.infer<typeof CompositionRunStatusSchema>;
224
304
  export declare const CompositionFieldStateKindSchema: z.ZodEnum<{
@@ -230,6 +310,11 @@ export type CompositionFieldStateKind = z.infer<typeof CompositionFieldStateKind
230
310
  export declare const CompositionFieldStateSchema: z.ZodObject<{
231
311
  cap: z.ZodString;
232
312
  path: z.ZodString;
313
+ item: z.ZodOptional<z.ZodObject<{
314
+ arrayPath: z.ZodString;
315
+ key: z.ZodString;
316
+ label: z.ZodString;
317
+ }, z.core.$strip>>;
233
318
  state: z.ZodEnum<{
234
319
  unavailable: "unavailable";
235
320
  fresh: "fresh";
@@ -247,11 +332,17 @@ export declare const CompositionBlockStateSchema: z.ZodObject<{
247
332
  failed: "failed";
248
333
  stopped: "stopped";
249
334
  starting: "starting";
335
+ degraded: "degraded";
250
336
  }>;
251
337
  reason: z.ZodOptional<z.ZodString>;
252
338
  fields: z.ZodArray<z.ZodObject<{
253
339
  cap: z.ZodString;
254
340
  path: z.ZodString;
341
+ item: z.ZodOptional<z.ZodObject<{
342
+ arrayPath: z.ZodString;
343
+ key: z.ZodString;
344
+ label: z.ZodString;
345
+ }, z.core.$strip>>;
255
346
  state: z.ZodEnum<{
256
347
  unavailable: "unavailable";
257
348
  fresh: "fresh";
@@ -14,13 +14,19 @@
14
14
  * Later slices EXTEND these unions and do not reshape them. The variants a later
15
15
  * slice implements are already in the wire shape, and `validateComposition`
16
16
  * refuses them BY NAME until then:
17
- * target `existing` → slice 2 · feature `passthrough` → slice 3 ·
18
- * `commands` (`forward`) → slice 3 · source `code` → slice 4.
17
+ * feature `passthrough` → slice 3 · `commands` (`forward`) → slice 3 ·
18
+ * source `code` → slice 4. Target `existing` (customize a device) is slice 2 (D663).
19
19
  */
20
20
  import { z } from 'zod';
21
21
  import { DeviceRole, DeviceType } from '../device/device-type.js';
22
22
  /** The owner of every composed device: the `composer` builtin. */
23
23
  export declare const COMPOSER_ADDON_ID = "composer";
24
+ /**
25
+ * The stored name of a block that customizes an EXISTING device starts with this
26
+ * (`customizationBlockName`, `@camstack/types/node`). Never parsed to tell a
27
+ * customization apart: `composition.target.kind === 'existing'` says that (D663).
28
+ */
29
+ export declare const CUSTOMIZATION_BLOCK_NAME_PREFIX = "customize:";
24
30
  /** A composed device's stableId is this prefix plus the block id. */
25
31
  export declare const COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
26
32
  /** A device with more capabilities than this is two devices. */
@@ -153,6 +159,47 @@ export declare const CompositionCommandTargetSchema: z.ZodDiscriminatedUnion<[z.
153
159
  code: z.ZodString;
154
160
  }, z.core.$strip>], "kind">;
155
161
  export type CompositionCommandTarget = z.infer<typeof CompositionCommandTargetSchema>;
162
+ /** An item key inside an item-array cap (`consumables.items[<key>]`). */
163
+ export declare const COMPOSITION_ITEM_KEY_RE: RegExp;
164
+ export declare const MAX_COMPOSITION_ITEMS = 16;
165
+ /** The item-array path of every item-array cap that exists (`consumables.items`). */
166
+ export declare const COMPOSITION_ITEM_ARRAY_PATH = "items";
167
+ /**
168
+ * One item of an item-array cap (D663), addressed through the cap's
169
+ * `status.itemArray` descriptor. `fields` are paths INSIDE the item, nested
170
+ * allowed (`remaining.value`); the key and label come from the entry itself.
171
+ */
172
+ export declare const CompositionItemEntrySchema: z.ZodObject<{
173
+ label: z.ZodString;
174
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
175
+ source: z.ZodObject<{
176
+ addonId: z.ZodString;
177
+ stableId: z.ZodString;
178
+ }, z.core.$strip>;
179
+ cap: z.ZodString;
180
+ fieldPath: z.ZodString;
181
+ kind: z.ZodLiteral<"from">;
182
+ }, z.core.$strip>, z.ZodObject<{
183
+ kind: z.ZodLiteral<"expression">;
184
+ expr: z.ZodString;
185
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
186
+ source: z.ZodObject<{
187
+ addonId: z.ZodString;
188
+ stableId: z.ZodString;
189
+ }, z.core.$strip>;
190
+ cap: z.ZodString;
191
+ fieldPath: z.ZodString;
192
+ kind: z.ZodLiteral<"from">;
193
+ }, z.core.$strip>, z.ZodObject<{
194
+ kind: z.ZodLiteral<"literal">;
195
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
196
+ }, z.core.$strip>], "kind">>;
197
+ }, z.core.$strip>, z.ZodObject<{
198
+ kind: z.ZodLiteral<"code">;
199
+ code: z.ZodString;
200
+ }, z.core.$strip>], "kind">>;
201
+ }, z.core.$strip>;
202
+ export type CompositionItemEntry = z.infer<typeof CompositionItemEntrySchema>;
156
203
  export declare const CompositionFieldsFeatureSchema: z.ZodObject<{
157
204
  kind: z.ZodLiteral<"fields">;
158
205
  cap: z.ZodString;
@@ -183,6 +230,36 @@ export declare const CompositionFieldsFeatureSchema: z.ZodObject<{
183
230
  kind: z.ZodLiteral<"code">;
184
231
  code: z.ZodString;
185
232
  }, z.core.$strip>], "kind">>;
233
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
234
+ label: z.ZodString;
235
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
236
+ source: z.ZodObject<{
237
+ addonId: z.ZodString;
238
+ stableId: z.ZodString;
239
+ }, z.core.$strip>;
240
+ cap: z.ZodString;
241
+ fieldPath: z.ZodString;
242
+ kind: z.ZodLiteral<"from">;
243
+ }, z.core.$strip>, z.ZodObject<{
244
+ kind: z.ZodLiteral<"expression">;
245
+ expr: z.ZodString;
246
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
247
+ source: z.ZodObject<{
248
+ addonId: z.ZodString;
249
+ stableId: z.ZodString;
250
+ }, z.core.$strip>;
251
+ cap: z.ZodString;
252
+ fieldPath: z.ZodString;
253
+ kind: z.ZodLiteral<"from">;
254
+ }, z.core.$strip>, z.ZodObject<{
255
+ kind: z.ZodLiteral<"literal">;
256
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
257
+ }, z.core.$strip>], "kind">>;
258
+ }, z.core.$strip>, z.ZodObject<{
259
+ kind: z.ZodLiteral<"code">;
260
+ code: z.ZodString;
261
+ }, z.core.$strip>], "kind">>;
262
+ }, z.core.$strip>>>;
186
263
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
187
264
  kind: z.ZodLiteral<"forward">;
188
265
  source: z.ZodObject<{
@@ -237,6 +314,36 @@ export declare const CompositionFeatureSchema: z.ZodDiscriminatedUnion<[z.ZodObj
237
314
  kind: z.ZodLiteral<"code">;
238
315
  code: z.ZodString;
239
316
  }, z.core.$strip>], "kind">>;
317
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
318
+ label: z.ZodString;
319
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
320
+ source: z.ZodObject<{
321
+ addonId: z.ZodString;
322
+ stableId: z.ZodString;
323
+ }, z.core.$strip>;
324
+ cap: z.ZodString;
325
+ fieldPath: z.ZodString;
326
+ kind: z.ZodLiteral<"from">;
327
+ }, z.core.$strip>, z.ZodObject<{
328
+ kind: z.ZodLiteral<"expression">;
329
+ expr: z.ZodString;
330
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
331
+ source: z.ZodObject<{
332
+ addonId: z.ZodString;
333
+ stableId: z.ZodString;
334
+ }, z.core.$strip>;
335
+ cap: z.ZodString;
336
+ fieldPath: z.ZodString;
337
+ kind: z.ZodLiteral<"from">;
338
+ }, z.core.$strip>, z.ZodObject<{
339
+ kind: z.ZodLiteral<"literal">;
340
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
341
+ }, z.core.$strip>], "kind">>;
342
+ }, z.core.$strip>, z.ZodObject<{
343
+ kind: z.ZodLiteral<"code">;
344
+ code: z.ZodString;
345
+ }, z.core.$strip>], "kind">>;
346
+ }, z.core.$strip>>>;
240
347
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
241
348
  kind: z.ZodLiteral<"forward">;
242
349
  source: z.ZodObject<{
@@ -268,7 +375,7 @@ export declare const CompositionNewTargetSchema: z.ZodObject<{
268
375
  role: z.ZodOptional<z.ZodEnum<typeof DeviceRole>>;
269
376
  }, z.core.$strip>;
270
377
  export type CompositionNewTarget = z.infer<typeof CompositionNewTargetSchema>;
271
- /** RESERVED for slice 2: customize an existing device. */
378
+ /** Customize an EXISTING device: each feature adds a capability or replaces fields of a native one (D663). */
272
379
  export declare const CompositionExistingTargetSchema: z.ZodObject<{
273
380
  kind: z.ZodLiteral<"existing">;
274
381
  device: z.ZodObject<{
@@ -331,6 +438,36 @@ export declare const CompositionSchema: z.ZodObject<{
331
438
  kind: z.ZodLiteral<"code">;
332
439
  code: z.ZodString;
333
440
  }, z.core.$strip>], "kind">>;
441
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
442
+ label: z.ZodString;
443
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
444
+ source: z.ZodObject<{
445
+ addonId: z.ZodString;
446
+ stableId: z.ZodString;
447
+ }, z.core.$strip>;
448
+ cap: z.ZodString;
449
+ fieldPath: z.ZodString;
450
+ kind: z.ZodLiteral<"from">;
451
+ }, z.core.$strip>, z.ZodObject<{
452
+ kind: z.ZodLiteral<"expression">;
453
+ expr: z.ZodString;
454
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
455
+ source: z.ZodObject<{
456
+ addonId: z.ZodString;
457
+ stableId: z.ZodString;
458
+ }, z.core.$strip>;
459
+ cap: z.ZodString;
460
+ fieldPath: z.ZodString;
461
+ kind: z.ZodLiteral<"from">;
462
+ }, z.core.$strip>, z.ZodObject<{
463
+ kind: z.ZodLiteral<"literal">;
464
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
465
+ }, z.core.$strip>], "kind">>;
466
+ }, z.core.$strip>, z.ZodObject<{
467
+ kind: z.ZodLiteral<"code">;
468
+ code: z.ZodString;
469
+ }, z.core.$strip>], "kind">>;
470
+ }, z.core.$strip>>>;
334
471
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
335
472
  kind: z.ZodLiteral<"forward">;
336
473
  source: z.ZodObject<{
@@ -360,3 +497,17 @@ export declare function composedDeviceStableId(blockId: string): string;
360
497
  export declare function composedDeviceRef(blockId: string): CompositionSourceRef;
361
498
  /** Every device field a source reads: `from` is one read, an expression is its `from` bindings. */
362
499
  export declare function fieldReads(source: CompositionFieldSource): readonly CompositionFieldRead[];
500
+ /** The ONE spelling of an item leaf as a field path: `items[desiccant].remaining.value`. */
501
+ export declare function compositionItemFieldPath(arrayPath: string, key: string, path: string): string;
502
+ export interface CompositionFeatureFieldEntry {
503
+ readonly fieldPath: string;
504
+ readonly source: CompositionFieldSource;
505
+ }
506
+ /**
507
+ * Every written field of a feature, item leaves under their bracketed path.
508
+ * `arrayPath` is `'items'` for every item-array cap that exists
509
+ * (`consumables.cap.ts`); the graph has no cap lookup, so the default stands
510
+ * and `planItems` asserts it agrees with the cap's descriptor.
511
+ */
512
+ export declare function featureFieldEntries(feature: CompositionFieldsFeature, arrayPath?: string): readonly CompositionFeatureFieldEntry[];
513
+ export declare function featureSources(feature: CompositionFieldsFeature): readonly CompositionFieldSource[];
@@ -0,0 +1,6 @@
1
+ import { type CompositionSourceRef } from './composition.js';
2
+ /**
3
+ * Derived by the SERVER on save, never sent by the client; never shown as the
4
+ * device's name. Unique per target: the plain ref when it fits, else a hash.
5
+ */
6
+ export declare function customizationBlockName(ref: CompositionSourceRef): string;
@@ -15,6 +15,14 @@
15
15
  * - an expression that fails on a value makes the field unavailable for that
16
16
  * value, and NOT fatal: the next value may compute.
17
17
  *
18
+ * `confirmed` (D663, D49): whether a NON-fatal unavailability is an ANSWER — a
19
+ * cap the provider unregistered and a re-read agreed, a field the source
20
+ * reported without, an expression that failed on a value — or only the
21
+ * absence of one (a failed read, a first or empty read, a source not tracked
22
+ * yet). Only a confirmed unavailability may hand a `release`-mode field back
23
+ * to the native provider; an unconfirmed one holds it on its last value.
24
+ * Absent means NOT confirmed. Fatal is always confirmed.
25
+ *
18
26
  * When an expression has more than one unavailable binding, a FATAL one always
19
27
  * wins the outcome, regardless of position: every binding is scanned before
20
28
  * the field is judged, so an earlier non-fatal binding (e.g. a cap that is
@@ -37,6 +45,8 @@ export interface SourceUnavailableReading {
37
45
  readonly reason: string;
38
46
  /** True when the source is GONE: device or cap missing, two reads agreed. */
39
47
  readonly fatal: boolean;
48
+ /** The unavailability is an answer, not a missing one (see the header). Absent = not confirmed. */
49
+ readonly confirmed?: boolean;
40
50
  }
41
51
  export type SourceReading = SourceFreshReading | SourceStaleReading | SourceUnavailableReading;
42
52
  export type SourceReader = (read: CompositionFieldRead) => SourceReading;
@@ -53,6 +63,8 @@ export interface FieldUnavailableOutcome {
53
63
  readonly value: null;
54
64
  readonly reason: string;
55
65
  readonly fatal: boolean;
66
+ /** Fatal, or a non-fatal unavailability that is an answer (see the header). Absent = not confirmed. */
67
+ readonly confirmed?: boolean;
56
68
  }
57
69
  export type FieldOutcome = FieldValueOutcome | FieldUnavailableOutcome;
58
70
  export interface EvaluateCompositionFieldInput {
@@ -8,3 +8,36 @@ export interface RoomExampleInput {
8
8
  readonly occupancyWindowMs: number;
9
9
  }
10
10
  export declare function roomCompositionExample(input: RoomExampleInput): Composition;
11
+ /**
12
+ * The slice-2 worked customization (D663): the PetKit "Fresh Element Infinity"
13
+ * feeder as Home Assistant imports it — ONE `Container` with a child per entity
14
+ * (`<container stableId>-<entityId>`), and NO native battery (its
15
+ * `binary_sensor.*_battery` is `battery_charging`, which `isBatteryEntity` does
16
+ * not match). The customization ADDS `consumables` (the desiccant) and
17
+ * `battery`. It is the Task 14 acceptance case and the template slice 5's
18
+ * presets start from.
19
+ *
20
+ * Every read names what the HA provider REALLY registers (read 2026-09-28):
21
+ * the desiccant sensor has a unit (`d`) but no device_class, so HA hosts it as
22
+ * an `enum-sensor` whose `value` is the raw STRING state — `number(d)` reads it,
23
+ * and anything that is not a number is `null`, never 0 (D393). The battery
24
+ * status sensor is an `enum-sensor` too (`unavailable` keeps its cold `''`, so
25
+ * `percentage` is `null`). `charging` maps `battery_charging` off to
26
+ * `'unknown'`, never `'none'`: off does not prove "on battery alone" (the
27
+ * operator confirms the real semantics live).
28
+ */
29
+ export declare const FEEDER_EXAMPLE_HA_DEVICE_ID = "8dec3b512fda40cbb8cd121c7a99f890";
30
+ export declare const FEEDER_EXAMPLE_ADDON_ID = "provider-homeassistant";
31
+ /** The container and the three children the feeder customization reads, under one HA broker. */
32
+ export interface FeederExampleSources {
33
+ readonly feeder: CompositionSourceRef;
34
+ /** `sensor.freshelement_3_desiccant_days_remaining` — `enum-sensor.value`, a numeric string. */
35
+ readonly desiccantDays: CompositionSourceRef;
36
+ /** `sensor.freshelement_3_battery_status` — `enum-sensor.value`. */
37
+ readonly batteryStatus: CompositionSourceRef;
38
+ /** `binary_sensor.freshelement_3_battery` (`battery_charging`) — `binary.on`. */
39
+ readonly batteryCharging: CompositionSourceRef;
40
+ }
41
+ /** The HA container's stableId (`ha-discovery.ts`) and a child's (`<container>-<entityId>`). */
42
+ export declare function feederExampleSources(brokerId: string): FeederExampleSources;
43
+ export declare function feederCustomizationExample(sources: FeederExampleSources): Composition;
@@ -0,0 +1,42 @@
1
+ import { type CompositionFieldSource } from './composition.js';
2
+ import type { CompositionFeatureMode, CompositionFieldRole, CompositionProblem, CompositionProblemCode, CompositionUnavailableMode } from './composition-report.js';
3
+ import { type ExpressionKindSet } from './expression-kinds.js';
4
+ import { type StateFieldDescription } from './state-fields.js';
5
+ import type { CapabilityLookup } from './validate-composition.js';
6
+ interface KindsFound {
7
+ readonly ok: true;
8
+ readonly kinds: ExpressionKindSet;
9
+ }
10
+ interface KindsRefused {
11
+ readonly ok: false;
12
+ readonly code: CompositionProblemCode;
13
+ readonly message: string;
14
+ }
15
+ type KindsResult = KindsFound | KindsRefused;
16
+ export declare function sourceKinds(source: CompositionFieldSource, lookupCap: CapabilityLookup): KindsResult;
17
+ export declare function compatibility(cap: string, target: StateFieldDescription, kinds: ExpressionKindSet, at: string): readonly CompositionProblem[];
18
+ /**
19
+ * An enum target whose source is a save-time-KNOWN string literal outside its
20
+ * `enumValues` is refused now rather than left to fail the write later. A
21
+ * dynamic source (a `from` read, a non-literal expression) is left to
22
+ * runtime — see {@link literalStringValue}.
23
+ */
24
+ export declare function enumLiteralProblem(cap: string, target: StateFieldDescription, source: CompositionFieldSource, at: string): CompositionProblem | null;
25
+ export declare function roleOf(source: CompositionFieldSource): CompositionFieldRole;
26
+ interface UnavailableChosen {
27
+ readonly ok: true;
28
+ readonly unavailable: CompositionUnavailableMode;
29
+ }
30
+ interface UnavailableRefused {
31
+ readonly ok: false;
32
+ readonly problem: CompositionProblem;
33
+ }
34
+ export type UnavailableResult = UnavailableChosen | UnavailableRefused;
35
+ /**
36
+ * How a planned field says "unavailable", per feature mode and AFTER `roleOf`
37
+ * (D393, D663 rulings S1 + S1b). The composer cannot take a device it does not
38
+ * own offline, and D393 forbids a stale number, so on an existing target a
39
+ * field that READS a source never gets `offline`.
40
+ */
41
+ export declare function unavailableFor(tf: StateFieldDescription, role: CompositionFieldRole, mode: CompositionFeatureMode, cap: string, at: string): UnavailableResult;
42
+ export {};
@@ -4,6 +4,7 @@
4
4
  */
5
5
  export * from './composition.js';
6
6
  export * from './composition-graph.js';
7
+ export * from './composition-items.js';
7
8
  export * from './composition-report.js';
8
9
  export * from './evaluate-field.js';
9
10
  export * from './examples.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The result of planning part of a composition, and the two helpers every
3
+ * planner builds it with. Internal to the composition module — NOT in the
4
+ * barrel (`problem`/`refused` are too generic a name for `@camstack/types`).
5
+ */
6
+ import type { CompositionFeaturePlan, CompositionFieldPlan, CompositionProblem, CompositionProblemCode } from './composition-report.js';
7
+ export interface CompositionPlanResult {
8
+ readonly problems: readonly CompositionProblem[];
9
+ readonly fields: readonly CompositionFieldPlan[];
10
+ /** One entry per planned feature, with its mode; empty for a per-field or per-item result. */
11
+ readonly features: readonly CompositionFeaturePlan[];
12
+ }
13
+ export declare function problem(code: CompositionProblemCode, path: string, message: string): CompositionProblem;
14
+ export declare function refused(...problems: readonly CompositionProblem[]): CompositionPlanResult;
15
+ /** Where a planned field sits in the composition: `features[N].fields.<path>` or `features[N].items.<key>.fields.<path>`. */
16
+ export declare function compositionFieldAt(field: CompositionFieldPlan): string;
@@ -17,3 +17,9 @@ export declare function describeStateField(schema: z.ZodType, path: string): Sta
17
17
  export declare function describeTopLevelStateFields(schema: z.ZodType): ReadonlyMap<string, StateFieldDescription>;
18
18
  /** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
19
19
  export declare function requiredTopLevelKeys(schema: z.ZodType): readonly string[];
20
+ /**
21
+ * The proper prefixes of `path` whose schema accepts `undefined`: a required
22
+ * leaf under one of them is required only once something writes that parent
23
+ * (`remaining.unit` is required only when `remaining` is present).
24
+ */
25
+ export declare function optionalAncestors(schema: z.ZodType, path: string): readonly string[];
@@ -1,16 +1,19 @@
1
1
  /**
2
2
  * Save-time validation of a composition (D659): shape, capability fit, field
3
- * kinds, nullability, sources, cycles. Every refusal names its reason (D391),
3
+ * kinds, nullability, sources, cycles — and on an EXISTING target (D663),
4
+ * add vs replace per feature, self reads, one composition per device. Every refusal names its reason (D391),
4
5
  * and every variant a later slice implements is refused BY NAME with that slice.
5
6
  *
6
- * Pure: the caller DESCRIBES the sources (one read each) and passes the other
7
- * stored compositions. `planComposition` is the static half the composer
7
+ * Pure: the caller DESCRIBES the sources and an existing target (one read
8
+ * each) and passes the other stored compositions. `planComposition` is the static half the composer
8
9
  * re-runs at apply time, where the sources are the tracker's business.
9
10
  */
10
11
  import type { CapabilityDefinition } from '../capabilities/capability-definition.js';
12
+ import type { DeviceType } from '../device/device-type.js';
11
13
  import { type Composition, type CompositionSourceRef } from './composition.js';
14
+ import { type CompositionPlanResult } from './plan-result.js';
12
15
  import { type CompositionPeer } from './composition-graph.js';
13
- import type { CompositionFieldPlan, CompositionProblem, CompositionValidation } from './composition-report.js';
16
+ import { type CompositionValidation } from './composition-report.js';
14
17
  export type CapabilityLookup = (capName: string) => CapabilityDefinition | null;
15
18
  export declare function buildCapabilityLookup(defs: readonly CapabilityDefinition[]): CapabilityLookup;
16
19
  /** Caps every `BaseDevice` registers on itself; a second registration throws. */
@@ -28,19 +31,51 @@ export interface CompositionSourceUnreadable {
28
31
  readonly error: string;
29
32
  }
30
33
  export type CompositionSourceDescription = CompositionSourceFound | CompositionSourceAbsent | CompositionSourceUnreadable;
34
+ /** An existing target device, read once: its type and each cap bound to it, with the addon serving it. */
35
+ export interface CompositionTargetFound {
36
+ readonly kind: 'found';
37
+ readonly deviceId: number;
38
+ readonly type: DeviceType;
39
+ /** cap name → `nativeAddonId` (`getBindings`). A cap the composer grafted carries `COMPOSER_ADDON_ID`. */
40
+ readonly nativeCaps: ReadonlyMap<string, string>;
41
+ }
42
+ export type CompositionTargetDescription = CompositionTargetFound | CompositionSourceAbsent | CompositionSourceUnreadable;
31
43
  export interface ValidateCompositionContext {
32
44
  readonly lookupCap: CapabilityLookup;
33
45
  /** Keyed by `compositionSourceKey`. A ref with no entry was not read, and is refused as unreadable. */
34
46
  readonly sources: ReadonlyMap<string, CompositionSourceDescription>;
35
47
  /** The device this composition writes; null on create, when the block has no id yet. */
36
48
  readonly self: CompositionSourceRef | null;
49
+ /** The block being saved; null on create. Its stored old version is recognised by this id (D663). */
50
+ readonly blockId: string | null;
51
+ /** The EXISTING target device, read once; null for a new-device composition (a missing read is refused). */
52
+ readonly target: CompositionTargetDescription | null;
37
53
  /** Every OTHER stored composition; cycles run through them. */
38
54
  readonly peers: readonly CompositionPeer[];
55
+ /**
56
+ * Devices of stored customizations whose target could not be read, by
57
+ * `compositionSourceKey` → why. Their peers are OVER-approximated (nothing
58
+ * `replaced`, so every self-read is an edge — edges are only added, a cycle
59
+ * never hidden). A cyclic component holding a candidate node and such a
60
+ * device refuses NAMING the device ("possible cycle"); a component without a
61
+ * candidate node is never this save's cycle (`findCandidateCycles`).
62
+ */
63
+ readonly unreadTargets?: ReadonlyMap<string, string>;
39
64
  }
40
- export interface CompositionPlanResult {
41
- readonly problems: readonly CompositionProblem[];
42
- readonly fields: readonly CompositionFieldPlan[];
43
- }
44
- export declare function planComposition(composition: Composition, lookupCap: CapabilityLookup): CompositionPlanResult;
65
+ export type { CompositionPlanResult } from './plan-result.js';
66
+ /** The candidate's block id before its first save. Stored block ids are `randomUUID()`, so none can carry it. */
67
+ export declare const PENDING_BLOCK_ID = "(unsaved)";
68
+ /**
69
+ * The static plan. `target` describes an EXISTING target device (one read);
70
+ * it is ignored for a new one. On an existing target each feature REPLACES a
71
+ * cap the device has natively, else ADDS it (D663).
72
+ */
73
+ export declare function planComposition(composition: Composition, lookupCap: CapabilityLookup, target?: CompositionTargetDescription): CompositionPlanResult;
45
74
  export declare function compositionSourceRefs(composition: Composition): readonly CompositionSourceRef[];
75
+ /**
76
+ * `compositionFieldKey` of every field a REPLACE feature of `plan` owns — the
77
+ * candidate's own, and a stored peer's `CompositionPeer.replaced` (D663): one
78
+ * derivation, so the graph reads both the same way.
79
+ */
80
+ export declare function replacedFieldKeys(plan: CompositionPlanResult): ReadonlySet<string>;
46
81
  export declare function validateComposition(composition: Composition, ctx: ValidateCompositionContext): CompositionValidation;