@camstack/types 1.2.267 → 1.2.269

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 (69) 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 +30 -1
  5. package/dist/capabilities/composer.cap.d.ts +105 -0
  6. package/dist/capabilities/consumables.cap.d.ts +79 -0
  7. package/dist/capabilities/core-blocks.cap.d.ts +1213 -104
  8. package/dist/capabilities/device-extension.cap.d.ts +12 -13
  9. package/dist/capabilities/device-manager.cap.d.ts +4 -4
  10. package/dist/capabilities/device-state.cap.d.ts +186 -2
  11. package/dist/capabilities/doorbell.cap.d.ts +4 -0
  12. package/dist/capabilities/index.d.ts +3 -3
  13. package/dist/capabilities/media-player.cap.d.ts +4 -4
  14. package/dist/capabilities/recording-archive.cap.d.ts +3 -3
  15. package/dist/catalogs/sensor-active-state.d.ts +25 -1
  16. package/dist/composition/composition-events.d.ts +42 -0
  17. package/dist/composition/composition-graph.d.ts +42 -9
  18. package/dist/composition/composition-items.d.ts +25 -0
  19. package/dist/composition/composition-report.d.ts +115 -12
  20. package/dist/composition/composition.d.ts +162 -3
  21. package/dist/composition/customization-name.d.ts +6 -0
  22. package/dist/composition/evaluate-field.d.ts +20 -0
  23. package/dist/composition/examples.d.ts +33 -0
  24. package/dist/composition/expression-kinds.d.ts +1 -0
  25. package/dist/composition/field-kinds.d.ts +42 -0
  26. package/dist/composition/index.d.ts +2 -0
  27. package/dist/composition/plan-result.d.ts +18 -0
  28. package/dist/composition/state-fields.d.ts +6 -0
  29. package/dist/composition/validate-composition.d.ts +44 -9
  30. package/dist/composition-BAH3n-zq.js +2582 -0
  31. package/dist/composition-D5BQywfe.mjs +2055 -0
  32. package/dist/device/device-context.d.ts +9 -0
  33. package/dist/device/device-runtime-state.d.ts +15 -1
  34. package/dist/device/index.d.ts +1 -1
  35. package/dist/device-extension/slot-descriptor.d.ts +8 -11
  36. package/dist/device-extension/slot-provider.d.ts +0 -2
  37. package/dist/enums/event-category.d.ts +25 -0
  38. package/dist/enums.js +1 -1
  39. package/dist/enums.mjs +1 -1
  40. package/dist/err-msg-DX6i_MY4.mjs +339 -0
  41. package/dist/err-msg-Dx2Kor0g.js +368 -0
  42. package/dist/{event-category-BVDXG4tB.mjs → event-category-C5xZWqz6.mjs} +31 -1
  43. package/dist/{event-category-BVfsrBYA.js → event-category-MbnB-6AN.js} +48 -0
  44. package/dist/expression/ast.d.ts +2 -0
  45. package/dist/expression/builtins.d.ts +9 -0
  46. package/dist/expression/evaluator.d.ts +8 -2
  47. package/dist/expression/expression-source.d.ts +26 -4
  48. package/dist/expression/index.d.ts +6 -6
  49. package/dist/generated/addon-api.d.ts +42 -0
  50. package/dist/generated/device-proxy.d.ts +1 -1
  51. package/dist/generated/method-access-map.d.ts +1 -1
  52. package/dist/generated/method-device-selectors.d.ts +2 -2
  53. package/dist/generated/system-proxy.d.ts +2 -2
  54. package/dist/index.d.ts +7 -6
  55. package/dist/index.js +1687 -1833
  56. package/dist/index.mjs +1359 -1550
  57. package/dist/interfaces/kernel-abstractions.d.ts +16 -0
  58. package/dist/interfaces/recording-config.d.ts +3 -3
  59. package/dist/interfaces/status-overlay.d.ts +42 -0
  60. package/dist/node.d.ts +1 -0
  61. package/dist/node.js +29 -8
  62. package/dist/node.mjs +23 -3
  63. package/dist/{sleep-8K9gue-H.js → sleep-Bg0IB7gg.js} +10 -367
  64. package/dist/{sleep-DC-wdyeS.mjs → sleep-E6eD4yQS.mjs} +11 -344
  65. package/package.json +1 -1
  66. package/dist/canonical-hash-CPK2Dy60.mjs +0 -715
  67. package/dist/canonical-hash-CSE4ioRi.js +0 -792
  68. package/dist/err-msg-COpsHMw2.js +0 -18
  69. package/dist/err-msg-IQTHeDzc.mjs +0 -13
@@ -2,11 +2,10 @@
2
2
  * `device-extension` — ONE place to see and author what a device is extended
3
3
  * with by OTHER devices (D648).
4
4
  *
5
- * **A contract, not a store.** Every slot (`linked-devices`,
6
- * `doorbell-source`, later `consumables-graft`) is declared by the cap that
7
- * owns the function (`extensionSlots` in its `*.cap.ts`, D4) and SERVED by the
8
- * addon that already owns its store, over that store and its existing write
9
- * path. This cap persists nothing and has no config method (guarded by
5
+ * **A contract, not a store.** Every slot (`linked-devices`, `doorbell-source`)
6
+ * is declared by the cap that owns the function (`extensionSlots` in its
7
+ * `*.cap.ts`, D4) and SERVED by the addon that already owns its store, over
8
+ * that store and its existing write path. This cap persists nothing and has no config method (guarded by
10
9
  * `scripts/check-extension-slots.ts`): D62 applied to the whole feature, and
11
10
  * D3 — no shadow registry.
12
11
  *
@@ -27,6 +26,11 @@
27
26
  * The slot's value travels as the generated discriminated union
28
27
  * (`ExtensionSlotValue`, keyed on `slot`), so a value under the wrong slot is
29
28
  * a schema error before it reaches any owner.
29
+ *
30
+ * **Associations only.** A slot LISTS other devices on its host. A host that
31
+ * GAINS a capability from other devices is a composition (D663, amends D648:
32
+ * the reserved `graft` shape, its `projects` and its `enabled` switch were
33
+ * retired unimplemented).
30
34
  */
31
35
  import { z } from 'zod';
32
36
  import { type InferProvider } from './capability-definition.js';
@@ -58,7 +62,7 @@ export type ExtensionSource = z.infer<typeof ExtensionSourceSchema>;
58
62
  /**
59
63
  * How one picked source stands. `missing` — no such device (deleted, or an id
60
64
  * that never existed); `foreign` — a device the slot's owner cannot read from
61
- * (slice 2's cross-owner graft source); `unavailable` — it exists but is not a
65
+ * (a source owned by another addon); `unavailable` — it exists but is not a
62
66
  * valid source now (a container, which is never a pick). A source in any of
63
67
  * these states is SHOWN, never silently dropped or re-pointed.
64
68
  */
@@ -107,8 +111,6 @@ export declare const ExtensionSlotStateSchema: z.ZodObject<{
107
111
  "doorbell-source": "doorbell-source";
108
112
  }>;
109
113
  authority: z.ZodString;
110
- enabled: z.ZodNullable<z.ZodBoolean>;
111
- projects: z.ZodNullable<z.ZodString>;
112
114
  activation: z.ZodNullable<z.ZodObject<{
113
115
  state: z.ZodEnum<{
114
116
  unknown: "unknown";
@@ -169,8 +171,6 @@ export declare const ExtensionSlotRowSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
169
171
  "doorbell-source": "doorbell-source";
170
172
  }>;
171
173
  authority: z.ZodString;
172
- enabled: z.ZodNullable<z.ZodBoolean>;
173
- projects: z.ZodNullable<z.ZodString>;
174
174
  activation: z.ZodNullable<z.ZodObject<{
175
175
  state: z.ZodEnum<{
176
176
  unknown: "unknown";
@@ -244,7 +244,8 @@ export type ExtensionCandidates = z.infer<typeof ExtensionCandidatesSchema>;
244
244
  /**
245
245
  * What a write did. `none` — applied in place. `host` / `parent` — the owner
246
246
  * reloaded the host (or, for an accessory child, its parent) because the
247
- * write changed what the host REGISTERS (a graft switched on or off, slice 2).
247
+ * write changed what the host REGISTERS. A slot never adds a capability to its
248
+ * host — that is a composition (D663) — so today's owners answer `none`.
248
249
  */
249
250
  export declare const ExtensionSetResultSchema: z.ZodObject<{
250
251
  applied: z.ZodLiteral<true>;
@@ -318,8 +319,6 @@ export declare const deviceExtensionCapability: {
318
319
  "doorbell-source": "doorbell-source";
319
320
  }>;
320
321
  authority: z.ZodString;
321
- enabled: z.ZodNullable<z.ZodBoolean>;
322
- projects: z.ZodNullable<z.ZodString>;
323
322
  activation: z.ZodNullable<z.ZodObject<{
324
323
  state: z.ZodEnum<{
325
324
  unknown: "unknown";
@@ -277,8 +277,8 @@ export declare const DevicePersistConfigPayloadSchema: z.ZodObject<{
277
277
  * answer: a camera that could not be asked is not a camera that was silenced. */
278
278
  export declare const MigrateSwitchOutcomeSchema: z.ZodEnum<{
279
279
  off: "off";
280
- unreachable: "unreachable";
281
280
  on: "on";
281
+ unreachable: "unreachable";
282
282
  "not-offered": "not-offered";
283
283
  }>;
284
284
  export declare const MigrateSwitchReportSchema: z.ZodObject<{
@@ -296,8 +296,8 @@ export declare const MigrateSwitchReportSchema: z.ZodObject<{
296
296
  }>;
297
297
  outcome: z.ZodEnum<{
298
298
  off: "off";
299
- unreachable: "unreachable";
300
299
  on: "on";
300
+ unreachable: "unreachable";
301
301
  "not-offered": "not-offered";
302
302
  }>;
303
303
  detail: z.ZodOptional<z.ZodString>;
@@ -320,8 +320,8 @@ export declare const MigrateDeviceResultSchema: z.ZodObject<{
320
320
  }>;
321
321
  outcome: z.ZodEnum<{
322
322
  off: "off";
323
- unreachable: "unreachable";
324
323
  on: "on";
324
+ unreachable: "unreachable";
325
325
  "not-offered": "not-offered";
326
326
  }>;
327
327
  detail: z.ZodOptional<z.ZodString>;
@@ -421,8 +421,8 @@ export declare const deviceManagerCapability: {
421
421
  }>;
422
422
  outcome: z.ZodEnum<{
423
423
  off: "off";
424
- unreachable: "unreachable";
425
424
  on: "on";
425
+ unreachable: "unreachable";
426
426
  "not-offered": "not-offered";
427
427
  }>;
428
428
  detail: z.ZodOptional<z.ZodString>;
@@ -1,4 +1,69 @@
1
1
  import { z } from 'zod';
2
+ /**
3
+ * Per-field ownership (D663). A composition may CLAIM fields of a native
4
+ * cap's runtime-state slice on an existing device: `replace` overlays the
5
+ * claimed fields on the native slice, `add` builds a slice the device does
6
+ * not natively have. Declared here — once — so the hub mirror (Task 5) and
7
+ * the claim methods (Task 6) share one union.
8
+ */
9
+ export declare const FieldClaimModeSchema: z.ZodEnum<{
10
+ replace: "replace";
11
+ add: "add";
12
+ }>;
13
+ export type FieldClaimMode = z.infer<typeof FieldClaimModeSchema>;
14
+ /** What a claim, patch or release answers. A refusal always names its reason. */
15
+ export declare const ClaimOutcomeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
16
+ ok: z.ZodLiteral<true>;
17
+ changed: z.ZodBoolean;
18
+ }, z.core.$strip>, z.ZodObject<{
19
+ ok: z.ZodLiteral<false>;
20
+ code: z.ZodEnum<{
21
+ "unknown-device": "unknown-device";
22
+ "owned-by-other": "owned-by-other";
23
+ "not-claimed": "not-claimed";
24
+ "field-not-claimed": "field-not-claimed";
25
+ "invalid-slice": "invalid-slice";
26
+ "row-unreadable": "row-unreadable";
27
+ "migration-in-flight": "migration-in-flight";
28
+ }>;
29
+ message: z.ZodString;
30
+ }, z.core.$strip>], "ok">;
31
+ export type ClaimOutcome = z.infer<typeof ClaimOutcomeSchema>;
32
+ /** One claim as `listClaims` reports it. `fields` is the PLANNED set, explicit (ruling S5). */
33
+ export declare const FieldClaimSchema: z.ZodObject<{
34
+ deviceId: z.ZodNumber;
35
+ capName: z.ZodString;
36
+ owner: z.ZodString;
37
+ mode: z.ZodEnum<{
38
+ replace: "replace";
39
+ add: "add";
40
+ }>;
41
+ fields: z.ZodArray<z.ZodString>;
42
+ }, z.core.$strip>;
43
+ export type FieldClaim = z.infer<typeof FieldClaimSchema>;
44
+ /**
45
+ * What `listClaims` answers. The claims INDEX is a listing projection loaded
46
+ * from the settings store at boot; until a load has succeeded it is
47
+ * `not-loaded`, never `[]` — an unanswered question must not look like an
48
+ * empty answer (D315).
49
+ */
50
+ export declare const ClaimsListingSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
51
+ state: z.ZodLiteral<"loaded">;
52
+ claims: z.ZodArray<z.ZodObject<{
53
+ deviceId: z.ZodNumber;
54
+ capName: z.ZodString;
55
+ owner: z.ZodString;
56
+ mode: z.ZodEnum<{
57
+ replace: "replace";
58
+ add: "add";
59
+ }>;
60
+ fields: z.ZodArray<z.ZodString>;
61
+ }, z.core.$strip>>;
62
+ }, z.core.$strip>, z.ZodObject<{
63
+ state: z.ZodLiteral<"not-loaded">;
64
+ reason: z.ZodString;
65
+ }, z.core.$strip>], "state">;
66
+ export type ClaimsListing = z.infer<typeof ClaimsListingSchema>;
2
67
  /**
3
68
  * `deviceState` — generic, cap-agnostic surface for cross-process
4
69
  * access to per-device runtime state. Read pendant for every cap's
@@ -32,8 +97,12 @@ export declare const deviceStateCapability: {
32
97
  readonly getSnapshot: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
33
98
  deviceId: z.ZodNumber;
34
99
  }, z.core.$strip>, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, import("./capability-definition.js").CapabilityMethodKind>;
35
- /** Single cap slice. Returns null when the slice hasn't been
36
- * written or the device isn't registered. */
100
+ /**
101
+ * Single cap slice — the EFFECTIVE one: the merge every consumer sees, null
102
+ * when the slice hasn't been written, the device isn't registered, or a
103
+ * claim HOLDS the cap (D663). Never the native shadow — that is
104
+ * `getNativeCapSlice`, admin-only.
105
+ */
37
106
  readonly getCapSlice: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
38
107
  deviceId: z.ZodNumber;
39
108
  capName: z.ZodString;
@@ -79,6 +148,121 @@ export declare const deviceStateCapability: {
79
148
  capName: z.ZodString;
80
149
  slice: z.ZodRecord<z.ZodString, z.ZodUnknown>;
81
150
  }, z.core.$strip>, z.ZodVoid, "mutation">;
151
+ /**
152
+ * Claim `fields` of `capName` on a device for `owner`. The PLANNED field set
153
+ * is explicit (ruling S5): `values` may be partial and MUST be a subset of
154
+ * `fields` (else `field-not-claimed`); a claimed field with no value is HELD,
155
+ * never answered from the native. A re-claim by the same owner REPLACES
156
+ * `fields` and MERGES `values` — a field dropped from `fields` loses its
157
+ * value. Another owner's claim → `owned-by-other`.
158
+ */
159
+ readonly claimFields: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
160
+ deviceId: z.ZodNumber;
161
+ capName: z.ZodString;
162
+ owner: z.ZodString;
163
+ mode: z.ZodEnum<{
164
+ replace: "replace";
165
+ add: "add";
166
+ }>;
167
+ fields: z.ZodArray<z.ZodString>;
168
+ values: z.ZodRecord<z.ZodString, z.ZodUnknown>;
169
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
170
+ ok: z.ZodLiteral<true>;
171
+ changed: z.ZodBoolean;
172
+ }, z.core.$strip>, z.ZodObject<{
173
+ ok: z.ZodLiteral<false>;
174
+ code: z.ZodEnum<{
175
+ "unknown-device": "unknown-device";
176
+ "owned-by-other": "owned-by-other";
177
+ "not-claimed": "not-claimed";
178
+ "field-not-claimed": "field-not-claimed";
179
+ "invalid-slice": "invalid-slice";
180
+ "row-unreadable": "row-unreadable";
181
+ "migration-in-flight": "migration-in-flight";
182
+ }>;
183
+ message: z.ZodString;
184
+ }, z.core.$strip>], "ok">, "mutation">;
185
+ /**
186
+ * Write owned values. Every key of `values` must be in the claim's `fields`
187
+ * (`field-not-claimed`); no claim → `not-claimed`; another owner's →
188
+ * `owned-by-other`. Partial patches merge (S5); debounced like a native slice.
189
+ */
190
+ readonly patchOwnedFields: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
191
+ deviceId: z.ZodNumber;
192
+ capName: z.ZodString;
193
+ owner: z.ZodString;
194
+ values: z.ZodRecord<z.ZodString, z.ZodUnknown>;
195
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
196
+ ok: z.ZodLiteral<true>;
197
+ changed: z.ZodBoolean;
198
+ }, z.core.$strip>, z.ZodObject<{
199
+ ok: z.ZodLiteral<false>;
200
+ code: z.ZodEnum<{
201
+ "unknown-device": "unknown-device";
202
+ "owned-by-other": "owned-by-other";
203
+ "not-claimed": "not-claimed";
204
+ "field-not-claimed": "field-not-claimed";
205
+ "invalid-slice": "invalid-slice";
206
+ "row-unreadable": "row-unreadable";
207
+ "migration-in-flight": "migration-in-flight";
208
+ }>;
209
+ message: z.ZodString;
210
+ }, z.core.$strip>], "ok">, "mutation">;
211
+ /**
212
+ * Hand the cap back. A `replace` re-emits the native slice exactly as last
213
+ * written; an `add` leaves the mirror. `not-claimed` also removes a stale
214
+ * index entry — the index self-heals through this method.
215
+ */
216
+ readonly releaseClaim: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
217
+ deviceId: z.ZodNumber;
218
+ capName: z.ZodString;
219
+ owner: z.ZodString;
220
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
221
+ ok: z.ZodLiteral<true>;
222
+ changed: z.ZodBoolean;
223
+ }, z.core.$strip>, z.ZodObject<{
224
+ ok: z.ZodLiteral<false>;
225
+ code: z.ZodEnum<{
226
+ "unknown-device": "unknown-device";
227
+ "owned-by-other": "owned-by-other";
228
+ "not-claimed": "not-claimed";
229
+ "field-not-claimed": "field-not-claimed";
230
+ "invalid-slice": "invalid-slice";
231
+ "row-unreadable": "row-unreadable";
232
+ "migration-in-flight": "migration-in-flight";
233
+ }>;
234
+ message: z.ZodString;
235
+ }, z.core.$strip>], "ok">, "mutation">;
236
+ /** Every claim the index lists, optionally those whose owner starts with `ownerPrefix`. */
237
+ readonly listClaims: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
238
+ ownerPrefix: z.ZodOptional<z.ZodString>;
239
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
240
+ state: z.ZodLiteral<"loaded">;
241
+ claims: z.ZodArray<z.ZodObject<{
242
+ deviceId: z.ZodNumber;
243
+ capName: z.ZodString;
244
+ owner: z.ZodString;
245
+ mode: z.ZodEnum<{
246
+ replace: "replace";
247
+ add: "add";
248
+ }>;
249
+ fields: z.ZodArray<z.ZodString>;
250
+ }, z.core.$strip>>;
251
+ }, z.core.$strip>, z.ZodObject<{
252
+ state: z.ZodLiteral<"not-loaded">;
253
+ reason: z.ZodString;
254
+ }, z.core.$strip>], "state">, import("./capability-definition.js").CapabilityMethodKind>;
255
+ /**
256
+ * The NATIVE slice — what the provider wrote, the shadow under a `replace`
257
+ * claim — for the owner's derived reads. Admin-only (D224, ruled in the
258
+ * Task 6 review): the shadow is a second truth beside the merge, and the
259
+ * event channel already refuses it to everyone but the composer; a
260
+ * protected read of it would hand out what the events withhold.
261
+ */
262
+ readonly getNativeCapSlice: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
263
+ deviceId: z.ZodNumber;
264
+ capName: z.ZodString;
265
+ }, z.core.$strip>, z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>, import("./capability-definition.js").CapabilityMethodKind>;
82
266
  };
83
267
  readonly events: {
84
268
  /**
@@ -95,6 +95,10 @@ export declare const doorbellCapability: {
95
95
  deviceId: z.ZodNumber;
96
96
  timestamp: z.ZodNumber;
97
97
  }, z.core.$strip>;
98
+ readonly fromState: {
99
+ readonly field: "lastPressedAt";
100
+ readonly on: "advance";
101
+ };
98
102
  };
99
103
  };
100
104
  readonly status: {
@@ -38,7 +38,7 @@ export { cameraStreamsCapability, type ICameraStreamsProvider, type PickedCamStr
38
38
  export { emitsCollectionSelector, extractNestedAddonId, isArrayOutputSchema, isCollectionArrayMethod, isObjectInput, isVoidInput, kebabToCamel, looseSchema, objectInputDeclaresAddonId, objectInputDeclaresRequiredDeviceId, procedureAuthKey, resolveMethodAuth, } from './cap-router-predicates.js';
39
39
  export type { CapabilityDefinition, CapabilityEventSchema, CapabilityMethodAuth, CapabilityMethodCaller, CapabilityMethodKind, CapabilityMethodOptions, CapabilityMethodSchema, CapabilityMountHint, CapabilityMountKind, CapabilityStatusItemArray, CapabilityStatusKind, CapabilityStatusSchema, CapCaller, DeviceConfigDerivedFormUi, DeviceConfigSpec, DeviceConfigUiSpec, DeviceConfigWidgetUi, DeviceSettingsContribution, InferDeviceProxyCap, InferEvents, InferName, InferNativeProvider, InferProvider, InferRuntimeState, ProviderKind, RuntimeStateDurability, UiContribution, UiContributionKind, UiContributionRemote, } from './capability-definition.js';
40
40
  export { DEFAULT_RUNTIME_STATE_DURABILITY, DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, event, expandCapMethods, isDeviceConfigCap, method, optionalMethod, PROVIDER_PIN_FIELD, resolveCapMount, } from './capability-definition.js';
41
- export { CORE_BLOCK_ADDON_PREFIX, CORE_BLOCKS_ADDON_ID, type CompositionBlockInput, CompositionBlockInputSchema, type CompositionBlockPatch, type CoreBlock, type CoreBlockCompileResult, CoreBlockCompileResultSchema, type CoreBlockInput, CoreBlockInputSchema, type CoreBlockPlacement, CoreBlockPlacementSchema, CoreBlockSchema, type CoreBlockSource, type CoreBlockSourceKind, CoreBlockSourceSchema, type CoreBlockStatus, CoreBlockStatusSchema, coreBlockAddonId, coreBlockComposition, coreBlockIdFromAddonId, coreBlockSourceKind, coreBlocksCapability, type CompositionGetRead, CompositionGetReadSchema, type CompositionListRead, CompositionListReadSchema, type CompositionStateRead, CompositionStateReadSchema, type CompositionView, CompositionViewSchema, type ICoreBlocksProvider, } from './core-blocks.cap.js';
41
+ export { CORE_BLOCK_ADDON_PREFIX, CORE_BLOCKS_ADDON_ID, type CompositionBlockInput, CompositionBlockInputSchema, type CompositionBlockPatch, type CoreBlock, type CoreBlockCompileResult, CoreBlockCompileResultSchema, type CoreBlockInput, CoreBlockInputSchema, type CoreBlockPlacement, CoreBlockPlacementSchema, CoreBlockSchema, type CoreBlockSource, type CoreBlockSourceKind, CoreBlockSourceSchema, type CoreBlockStatus, CoreBlockStatusSchema, coreBlockAddonId, coreBlockComposition, coreBlockIdFromAddonId, coreBlockSourceKind, coreBlocksCapability, type CompositionCustomizationRead, CompositionCustomizationReadSchema, type CompositionGetRead, CompositionGetReadSchema, type CompositionListRead, CompositionListReadSchema, type CompositionStateRead, CompositionStateReadSchema, type CompositionView, CompositionViewSchema, type ICoreBlocksProvider, } from './core-blocks.cap.js';
42
42
  export { COMPOSER_RUNNER_ID, type ComposerApplyInput, ComposerApplyInputSchema, type ComposerApplyResult, ComposerApplyResultSchema, type ComposerBlock, ComposerBlockSchema, type ComposerBlockVerdict, ComposerBlockVerdictSchema, type ComposerUnreadableBlock, ComposerUnreadableBlockSchema, composerCapability, type IComposerProvider, } from './composer.cap.js';
43
43
  export * from './custom-actions.js';
44
44
  export type { CustomModelDescriptor, ICustomModelRegistryProvider, } from './custom-model-registry.cap.js';
@@ -55,7 +55,7 @@ export { DeviceExportStatusSchema, deviceExportCapability, ExportSetupFieldSchem
55
55
  export type { DeviceInfo, DeviceManagerApplyInitialMetaInput } from './device-manager.cap.js';
56
56
  export { ConfigEntrySchema, DEVICE_CHILDREN_BATCH_MAX, DeviceInfoSchema, deviceManagerCapability, type IDeviceManagerProvider, type LinkedDevice, LinkedDeviceSchema, type LinkedDevicesMode, LinkedDevicesModeSchema, LINKED_DEVICES_SLOT, type LinkedDevicesSlotValue, LinkedDevicesSlotValueSchema, type MigrateDeviceResult, MigrateDeviceResultSchema, type MigrateSwitchOutcome, MigrateSwitchOutcomeSchema, type MigrateSwitchReport, MigrateSwitchReportSchema, } from './device-manager.cap.js';
57
57
  export { DiscoveredDeviceSchema, deviceProviderCapability, ProviderStatusSchema, } from './device-provider.cap.js';
58
- export { deviceStateCapability } from './device-state.cap.js';
58
+ export { type ClaimOutcome, ClaimOutcomeSchema, type ClaimsListing, ClaimsListingSchema, deviceStateCapability, type FieldClaim, type FieldClaimMode, FieldClaimModeSchema, FieldClaimSchema, } from './device-state.cap.js';
59
59
  export type { EmbeddingFailedModel, EmbeddingFailedRequirement, EmbeddingModelFailure, EmbeddingRefusal, EmbeddingRefusalCode, EmbeddingTower, IEmbeddingEncoderProvider, } from './embedding-encoder.cap.js';
60
60
  export { EMBEDDING_MODEL_FAILED, EMBEDDING_REQUIREMENTS_FAILED, EMBEDDING_REQUIREMENTS_UNAVAILABLE, EmbeddingFailedModelSchema, EmbeddingFailedRequirementSchema, EmbeddingInfoSchema, EmbeddingRefusalCodeSchema, EmbeddingResultSchema, EmbeddingTowerSchema, embeddingEncoderCapability, embeddingModelFailedError, embeddingModelFailedOf, embeddingRefusalOf, embeddingRequirementsFailedError, embeddingRequirementsUnavailableError, isEmbeddingModelFailed, } from './embedding-encoder.cap.js';
61
61
  export type { FailureContribution, IFailureContributionProvider, } from './failure-contribution.cap.js';
@@ -145,7 +145,7 @@ export { type ClimateControlStatus, ClimateControlStatusSchema, climateControlCa
145
145
  export { type ColorHsvTriplet, type ColorInput, type ColorRgbTriplet, type ColorStatus, ColorStatusSchema, colorCapability, type IColorProvider, } from './color.cap.js';
146
146
  export { CONNECTION_TEST_TIMEOUT_MS, ConnectionTestDescriptorSchema, ConnectionTestInputSchema, type ConnectionTestOutcome, ConnectionTestOutcomeSchema, connectionTestCapability, type IConnectionTestProvider, } from './connection-test.cap.js';
147
147
  export { type ConnectivityStatus, ConnectivityStatusSchema, connectivityCapability, type IConnectivityProvider, } from './connectivity.cap.js';
148
- export { type ConsumableItem, ConsumableItemSchema, type ConsumablesStatus, ConsumablesStatusSchema, consumablesCapability, type IConsumablesProvider, } from './consumables.cap.js';
148
+ export { type ConsumableItem, ConsumableItemSchema, type ConsumableRemaining, ConsumableRemainingSchema, type ConsumableRemainingUnit, ConsumableRemainingUnitSchema, type ConsumablesStatus, ConsumablesStatusSchema, consumablesCapability, type IConsumablesProvider, } from './consumables.cap.js';
149
149
  export { type ContactStatus, ContactStatusSchema, contactCapability, type IContactProvider, } from './contact.cap.js';
150
150
  export { type ControlKind, ControlKindSchema, type ControlSetValueInput, type ControlStatus, ControlStatusSchema, controlCapability, type IControlProvider, } from './control.cap.js';
151
151
  export { type CoverState, CoverStateSchema, type CoverStatus, CoverStatusSchema, coverCapability, type ICoverProvider, } from './cover.cap.js';
@@ -17,8 +17,8 @@ export declare const MediaPlayerStateSchema: z.ZodEnum<{
17
17
  idle: "idle";
18
18
  paused: "paused";
19
19
  off: "off";
20
- playing: "playing";
21
20
  on: "on";
21
+ playing: "playing";
22
22
  buffering: "buffering";
23
23
  standby: "standby";
24
24
  }>;
@@ -42,8 +42,8 @@ export declare const MediaPlayerStatusSchema: z.ZodObject<{
42
42
  idle: "idle";
43
43
  paused: "paused";
44
44
  off: "off";
45
- playing: "playing";
46
45
  on: "on";
46
+ playing: "playing";
47
47
  buffering: "buffering";
48
48
  standby: "standby";
49
49
  }>;
@@ -131,8 +131,8 @@ export declare const mediaPlayerCapability: {
131
131
  idle: "idle";
132
132
  paused: "paused";
133
133
  off: "off";
134
- playing: "playing";
135
134
  on: "on";
135
+ playing: "playing";
136
136
  buffering: "buffering";
137
137
  standby: "standby";
138
138
  }>;
@@ -169,8 +169,8 @@ export declare const mediaPlayerCapability: {
169
169
  idle: "idle";
170
170
  paused: "paused";
171
171
  off: "off";
172
- playing: "playing";
173
172
  on: "on";
173
+ playing: "playing";
174
174
  buffering: "buffering";
175
175
  standby: "standby";
176
176
  }>;
@@ -523,8 +523,8 @@ export declare const recordingArchiveCapability: {
523
523
  continuous: "continuous";
524
524
  }>;
525
525
  audio: z.ZodOptional<z.ZodEnum<{
526
- muted: "muted";
527
526
  on: "on";
527
+ muted: "muted";
528
528
  }>>;
529
529
  triggers: z.ZodOptional<z.ZodObject<{
530
530
  motion: z.ZodOptional<z.ZodBoolean>;
@@ -636,8 +636,8 @@ export declare const recordingArchiveCapability: {
636
636
  continuous: "continuous";
637
637
  }>;
638
638
  audio: z.ZodOptional<z.ZodEnum<{
639
- muted: "muted";
640
639
  on: "on";
640
+ muted: "muted";
641
641
  }>>;
642
642
  triggers: z.ZodOptional<z.ZodObject<{
643
643
  motion: z.ZodOptional<z.ZodBoolean>;
@@ -681,8 +681,8 @@ export declare const recordingArchiveCapability: {
681
681
  continuous: "continuous";
682
682
  }>;
683
683
  audio: z.ZodOptional<z.ZodEnum<{
684
- muted: "muted";
685
684
  on: "on";
685
+ muted: "muted";
686
686
  }>>;
687
687
  triggers: z.ZodOptional<z.ZodObject<{
688
688
  motion: z.ZodOptional<z.ZodBoolean>;
@@ -82,7 +82,10 @@ export type SensorEdgeIgnoreReason =
82
82
  /** Re-emission carrying the same binary value. */
83
83
  | 'no-change'
84
84
  /** The falling edge — switch-off / contact-close never fires. */
85
- | 'falling-edge';
85
+ | 'falling-edge'
86
+ /** A false→true level moved, but no finite source transition timestamp can
87
+ * prove when it happened. */
88
+ | 'missing-timestamp';
86
89
  export interface SensorEdgeInput {
87
90
  readonly capName: string;
88
91
  readonly slice: Readonly<Record<string, unknown>>;
@@ -114,6 +117,27 @@ export type SensorEdgeVerdict = {
114
117
  * hydration of long-standing state.
115
118
  */
116
119
  export declare const DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = 30000;
120
+ export interface SensorLevelEdgeInput {
121
+ readonly level: boolean;
122
+ readonly changedAt: number | null;
123
+ readonly priorLevel: boolean | undefined;
124
+ readonly startedAtMs: number;
125
+ readonly nowMs: number;
126
+ readonly firstSightingFreshnessMs: number;
127
+ }
128
+ export type SensorLevelEdgeVerdict = {
129
+ readonly kind: 'rise';
130
+ readonly timestamp: number;
131
+ } | {
132
+ readonly kind: 'none';
133
+ readonly nextPriorLevel: boolean;
134
+ };
135
+ /**
136
+ * The source-independent edge rule. The caller supplies an already extracted
137
+ * boolean level and source timestamp; this function owns first-sighting
138
+ * freshness and false-to-true detection.
139
+ */
140
+ export declare function evaluateSensorLevelEdge(input: SensorLevelEdgeInput): SensorLevelEdgeVerdict;
117
141
  /**
118
142
  * IL fronte. Puro: nessun orologio proprio, nessuna memoria — il chiamante
119
143
  * porta `prior`, `nowMs` e il proprio `startedAtMs`.
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ import type { CapabilityDefinition } from '../capabilities/capability-definition.js';
3
+ import { EventCategory } from '../enums/event-category.js';
4
+ export declare const COMPOSITION_EVENT_CATEGORY: {
5
+ readonly 'doorbell.onPressed': EventCategory.DoorbellOnPressed;
6
+ };
7
+ export declare const CompositionEventPlanSchema: z.ZodObject<{
8
+ featureIndex: z.ZodNumber;
9
+ cap: z.ZodString;
10
+ eventName: z.ZodString;
11
+ category: z.ZodEnum<typeof EventCategory>;
12
+ stateField: z.ZodString;
13
+ fieldKey: z.ZodString;
14
+ }, z.core.$strip>;
15
+ export type CompositionEventPlan = z.infer<typeof CompositionEventPlanSchema>;
16
+ type EventProblemCode = 'unknown-field' | 'kind-mismatch' | 'not-composable';
17
+ export interface CompositionEventProblem {
18
+ readonly code: EventProblemCode;
19
+ readonly path: string;
20
+ readonly message: string;
21
+ }
22
+ export interface CompositionEventFeatureInput {
23
+ readonly featureIndex: number;
24
+ readonly cap: string;
25
+ readonly mode: 'new' | 'add' | 'replace';
26
+ }
27
+ export interface CompositionEventFieldInput {
28
+ readonly featureIndex: number;
29
+ readonly cap: string;
30
+ readonly path: string;
31
+ readonly item?: unknown;
32
+ }
33
+ export interface CompositionEventPlanningResult {
34
+ readonly problems: readonly CompositionEventProblem[];
35
+ readonly events: readonly CompositionEventPlan[];
36
+ }
37
+ /**
38
+ * Plan one capability's state-derived events after its feature mode and fields
39
+ * are known. A native replacement never becomes a second event authority.
40
+ */
41
+ export declare function planCompositionEvents(def: CapabilityDefinition, feature: CompositionEventFeatureInput, fields: readonly CompositionEventFieldInput[]): CompositionEventPlanningResult;
42
+ export {};
@@ -6,31 +6,64 @@
6
6
  * through another composition, is refused at save by name (spec §2).
7
7
  *
8
8
  * The graph is built for ONE save: the CANDIDATE composition (the one being
9
- * validated) plus every STORED composition. The candidate ALWAYS replaces any
10
- * stored peer that targets the same device, regardless of where that stored
11
- * peer sits in `stored` — whether a save introduces or removes a cycle must
12
- * never depend on array order. Two DIFFERENT stored peers that (wrongly)
13
- * target the same device are corrupted state, not a cycle to resolve by
14
- * picking one silently; that is refused by name (D391).
9
+ * validated) plus every STORED composition. The candidate replaces its own old
10
+ * version, identified BY BLOCK ID wherever it sits in `stored` — whether a save
11
+ * introduces or removes a cycle must never depend on array order. A DIFFERENT
12
+ * block targeting the candidate's device is refused by name: one composition
13
+ * per device (D663). Two different stored peers that (wrongly) target the same
14
+ * device are corrupted state, not a cycle to resolve by picking one silently;
15
+ * that is refused by name too (D391).
16
+ *
17
+ * A customization of an EXISTING device reads that device's NATIVE value for a
18
+ * field it replaces or does not write ("Invert state" reads the `on` it
19
+ * replaces): such a self-read is no edge, so it is never a cycle (D663).
20
+ * Another composition reading that field reads the customizer's output.
15
21
  *
16
22
  * `findCompositionCycles` reports at least one cycle per cycle-SET (the DFS
17
- * marks a node `done` after its first expansion) — enough to refuse a save,
18
- * not to enumerate every elementary cycle through a shared node. A dotted
23
+ * marks a node `done` after its first expansion) — not every elementary cycle
24
+ * through a shared node, so the path it names may AVOID the candidate while
25
+ * one through it goes unreported. What a save refuses is therefore decided per
26
+ * strongly connected component (`findCandidateCycles`, C-1). A dotted
19
27
  * `fieldPath` is matched only as an exact string: a write to `state.value` and
20
28
  * a read of `state` would not connect (no nested field writes exist yet).
29
+ *
30
+ * An item leaf is its own node, `…#consumables.items[desiccant].status`
31
+ * (`featureFieldEntries`), so two items sharing an inner path never merge. No
32
+ * READ can name an array element (`describeStateField` never describes one),
33
+ * so an item node is write-only: its edges to sources are what the check needs.
21
34
  */
22
35
  import { type Composition, type CompositionSourceRef } from './composition.js';
23
36
  export interface CompositionPeer {
37
+ /** The block that stores this composition — its identity (D663). */
38
+ readonly blockId: string;
24
39
  /** The device this composition writes: `composedDeviceRef(blockId)` for a new target. */
25
40
  readonly target: CompositionSourceRef;
26
41
  readonly composition: Composition;
42
+ /** `"cap.field"` keys this composition REPLACES on an existing target; its reads of them are native. */
43
+ readonly replaced?: ReadonlySet<string>;
27
44
  }
28
45
  export interface CompositionCycle {
29
46
  /** Node keys, first and last equal. */
30
47
  readonly path: readonly string[];
31
48
  }
32
- /** Two stored compositions both target the same device — refused by name, never silently resolved. */
49
+ /** Two blocks' compositions target the same device — refused by name, never silently resolved. */
33
50
  export declare class CompositionGraphError extends Error {
34
51
  }
35
52
  export declare function compositionEdges(candidate: CompositionPeer, stored: readonly CompositionPeer[]): ReadonlyMap<string, readonly string[]>;
36
53
  export declare function findCompositionCycles(candidate: CompositionPeer, stored: readonly CompositionPeer[]): readonly CompositionCycle[];
54
+ /** A cycle-bearing strongly connected component that holds one of the candidate's nodes. */
55
+ export interface CandidateCycle {
56
+ /** One representative cycle through a candidate node inside the component: first and last equal. */
57
+ readonly path: readonly string[];
58
+ /** Every node of the component — what the save would close a loop through. */
59
+ readonly component: ReadonlySet<string>;
60
+ }
61
+ /**
62
+ * The cycles THIS save closes, decided per strongly connected component — never
63
+ * per reported DFS path, which names one back-edge per revisit and can report a
64
+ * component's cycle by a path that avoids the candidate while the one through it
65
+ * goes unreported. A component refuses when it holds a candidate node and a
66
+ * cycle (more than one node, or a self-loop). Components without a candidate
67
+ * node are not this save's cycles.
68
+ */
69
+ export declare function findCandidateCycles(candidate: CompositionPeer, stored: readonly CompositionPeer[]): readonly CandidateCycle[];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Item-array fields of a composition (D663): `consumables.items[<key>]`.
3
+ *
4
+ * Items are addressed through the cap's `status.itemArray` descriptor — the
5
+ * one the source picker already uses — so a cap without one is refused
6
+ * (`not-item-array`). A composition that names `items` owns the WHOLE array.
7
+ * Each item leaf is planned as its own field, carrying `item`, and keyed by
8
+ * `compositionFieldKey` so two items sharing an inner path never share a
9
+ * record or a graph node.
10
+ *
11
+ * The composer sets some item fields itself: the key and label (from the
12
+ * entry) and {@link COMPOSED_ITEM_FIXED_FIELDS}. A source for any of them is
13
+ * refused by name (`item-field-reserved`) — `resettable` is fixed `false`
14
+ * because `reset` is refused until commands arrive (slice 3).
15
+ */
16
+ import type { CapabilityDefinition } from '../capabilities/capability-definition.js';
17
+ import { type CompositionFieldsFeature } from './composition.js';
18
+ import type { CompositionFeatureMode } from './composition-report.js';
19
+ import { type CompositionPlanResult } from './plan-result.js';
20
+ import type { CapabilityLookup } from './validate-composition.js';
21
+ /** Item fields the composer writes itself, with the value it writes. */
22
+ export declare const COMPOSED_ITEM_FIXED_FIELDS: {
23
+ readonly resettable: false;
24
+ };
25
+ export declare function planItems(def: CapabilityDefinition, feature: CompositionFieldsFeature, featureIndex: number, lookupCap: CapabilityLookup, mode?: CompositionFeatureMode): CompositionPlanResult;