@camstack/types 1.2.267 → 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.
- package/dist/addon.js +4 -4
- package/dist/addon.mjs +3 -3
- package/dist/capabilities/battery.cap.d.ts +17 -2
- package/dist/capabilities/capability-definition.d.ts +22 -0
- package/dist/capabilities/composer.cap.d.ts +99 -0
- package/dist/capabilities/consumables.cap.d.ts +79 -0
- package/dist/capabilities/core-blocks.cap.d.ts +1149 -91
- package/dist/capabilities/device-extension.cap.d.ts +12 -13
- package/dist/capabilities/device-state.cap.d.ts +186 -2
- package/dist/capabilities/index.d.ts +3 -3
- package/dist/composition/composition-graph.d.ts +42 -9
- package/dist/composition/composition-items.d.ts +25 -0
- package/dist/composition/composition-report.d.ts +93 -2
- package/dist/composition/composition.d.ts +154 -3
- package/dist/composition/customization-name.d.ts +6 -0
- package/dist/composition/evaluate-field.d.ts +12 -0
- package/dist/composition/examples.d.ts +33 -0
- package/dist/composition/field-kinds.d.ts +42 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/plan-result.d.ts +16 -0
- package/dist/composition/state-fields.d.ts +6 -0
- package/dist/composition/validate-composition.d.ts +44 -9
- package/dist/composition-CPFIlFfw.mjs +1759 -0
- package/dist/composition-QlOB7QTG.js +2184 -0
- package/dist/device/device-context.d.ts +9 -0
- package/dist/device/device-runtime-state.d.ts +15 -1
- package/dist/device/index.d.ts +1 -1
- package/dist/device-extension/slot-descriptor.d.ts +8 -11
- package/dist/device-extension/slot-provider.d.ts +0 -2
- package/dist/enums/event-category.d.ts +25 -0
- package/dist/enums.js +1 -1
- package/dist/enums.mjs +1 -1
- package/dist/err-msg-DX6i_MY4.mjs +339 -0
- package/dist/err-msg-Dx2Kor0g.js +368 -0
- package/dist/{event-category-BVDXG4tB.mjs → event-category-C5xZWqz6.mjs} +31 -1
- package/dist/{event-category-BVfsrBYA.js → event-category-MbnB-6AN.js} +48 -0
- package/dist/generated/addon-api.d.ts +42 -0
- package/dist/generated/device-proxy.d.ts +1 -1
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +2 -2
- package/dist/generated/system-proxy.d.ts +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1513 -1656
- package/dist/index.mjs +1208 -1384
- package/dist/interfaces/kernel-abstractions.d.ts +16 -0
- package/dist/interfaces/status-overlay.d.ts +42 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +29 -8
- package/dist/node.mjs +23 -3
- package/dist/{sleep-8K9gue-H.js → sleep-BSzia-xT.js} +6 -352
- package/dist/{sleep-DC-wdyeS.mjs → sleep-jkRQgtSc.mjs} +7 -329
- package/package.json +1 -1
- package/dist/canonical-hash-CPK2Dy60.mjs +0 -715
- package/dist/canonical-hash-CSE4ioRi.js +0 -792
- package/dist/err-msg-COpsHMw2.js +0 -18
- package/dist/err-msg-IQTHeDzc.mjs +0 -13
|
@@ -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
|
-
*
|
|
18
|
-
*
|
|
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
|
-
/**
|
|
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 {};
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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;
|