@camstack/types 1.2.268 → 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 (33) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/capabilities/capability-definition.d.ts +8 -1
  4. package/dist/capabilities/composer.cap.d.ts +6 -0
  5. package/dist/capabilities/core-blocks.cap.d.ts +54 -3
  6. package/dist/capabilities/device-manager.cap.d.ts +4 -4
  7. package/dist/capabilities/doorbell.cap.d.ts +4 -0
  8. package/dist/capabilities/media-player.cap.d.ts +4 -4
  9. package/dist/capabilities/recording-archive.cap.d.ts +3 -3
  10. package/dist/catalogs/sensor-active-state.d.ts +25 -1
  11. package/dist/composition/composition-events.d.ts +42 -0
  12. package/dist/composition/composition-report.d.ts +22 -10
  13. package/dist/composition/composition.d.ts +8 -0
  14. package/dist/composition/evaluate-field.d.ts +8 -0
  15. package/dist/composition/expression-kinds.d.ts +1 -0
  16. package/dist/composition/index.d.ts +1 -0
  17. package/dist/composition/plan-result.d.ts +2 -0
  18. package/dist/{composition-QlOB7QTG.js → composition-BAH3n-zq.js} +412 -14
  19. package/dist/{composition-CPFIlFfw.mjs → composition-D5BQywfe.mjs} +311 -15
  20. package/dist/expression/ast.d.ts +2 -0
  21. package/dist/expression/builtins.d.ts +9 -0
  22. package/dist/expression/evaluator.d.ts +8 -2
  23. package/dist/expression/expression-source.d.ts +26 -4
  24. package/dist/expression/index.d.ts +6 -6
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +321 -324
  27. package/dist/index.mjs +299 -314
  28. package/dist/interfaces/recording-config.d.ts +3 -3
  29. package/dist/node.js +1 -1
  30. package/dist/node.mjs +1 -1
  31. package/dist/{sleep-BSzia-xT.js → sleep-Bg0IB7gg.js} +4 -15
  32. package/dist/{sleep-jkRQgtSc.mjs → sleep-E6eD4yQS.mjs} +4 -15
  33. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-BSzia-xT.js");
2
+ const require_sleep = require("./sleep-Bg0IB7gg.js");
3
3
  const require_event_category = require("./event-category-MbnB-6AN.js");
4
- const require_composition = require("./composition-QlOB7QTG.js");
4
+ const require_composition = require("./composition-BAH3n-zq.js");
5
5
  const require_err_msg = require("./err-msg-Dx2Kor0g.js");
6
6
  const require_enums = require("./enums.js");
7
7
  let zod = require("zod");
@@ -9333,6 +9333,197 @@ function kebabToCamel(s) {
9333
9333
  return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
9334
9334
  }
9335
9335
  //#endregion
9336
+ //#region src/device/schema-fields.ts
9337
+ /** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
9338
+ * Zod v4 exposes `.unwrap()` on all three wrapper classes. */
9339
+ function unwrapSchema(schema) {
9340
+ let s = schema;
9341
+ while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
9342
+ return s;
9343
+ }
9344
+ function leafKind(schema) {
9345
+ const s = unwrapSchema(schema);
9346
+ if (s instanceof zod.z.ZodEnum) return {
9347
+ kind: "enum",
9348
+ enumValues: s.options
9349
+ };
9350
+ if (s instanceof zod.z.ZodNumber) return { kind: "number" };
9351
+ if (s instanceof zod.z.ZodString) return { kind: "string" };
9352
+ if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
9353
+ return null;
9354
+ }
9355
+ /** Walk a cap status schema into flat wireable leaf fields (dotted paths).
9356
+ * Recurses into nested ZodObject (unwrapping nullable/optional/default first),
9357
+ * so fields with null live values are still offered. Arrays / unknown shapes
9358
+ * are skipped — never throws. */
9359
+ function enumerateSchemaFields(schema, prefix = "") {
9360
+ const root = unwrapSchema(schema);
9361
+ if (!(root instanceof zod.z.ZodObject)) return [];
9362
+ const out = [];
9363
+ const shape = root.shape;
9364
+ for (const [key, field] of Object.entries(shape)) {
9365
+ const path = prefix ? `${prefix}.${key}` : key;
9366
+ const inner = unwrapSchema(field);
9367
+ if (inner instanceof zod.z.ZodObject) {
9368
+ out.push(...enumerateSchemaFields(inner, path));
9369
+ continue;
9370
+ }
9371
+ const leaf = leafKind(field);
9372
+ if (leaf) out.push({
9373
+ path,
9374
+ kind: leaf.kind,
9375
+ ...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
9376
+ });
9377
+ }
9378
+ return out;
9379
+ }
9380
+ /** Enumerate the per-item wireable fields of an item-array cap (see
9381
+ * `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
9382
+ * `keyField` (the key comes from the link's `itemKey`, never from a wired
9383
+ * source), each tagged `item: true` so the authoring UI collects an
9384
+ * `itemKey` alongside the field. Never throws. */
9385
+ function enumerateItemArrayFields(itemArray) {
9386
+ return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
9387
+ ...f,
9388
+ item: true
9389
+ }));
9390
+ }
9391
+ //#endregion
9392
+ //#region src/composition/state-fields.ts
9393
+ /**
9394
+ * What a capability's state field IS: kind, nullability, whether required. The
9395
+ * validator needs nullability, which `enumerateSchemaFields` does not report,
9396
+ * and that decides a field's unavailable mode (D393).
9397
+ */
9398
+ function fieldAt(schema, path) {
9399
+ let current = schema;
9400
+ for (const segment of path.split(".")) {
9401
+ const container = unwrapSchema(current);
9402
+ if (!(container instanceof zod.z.ZodObject)) return null;
9403
+ const next = container.shape[segment];
9404
+ if (!(next instanceof zod.z.ZodType)) return null;
9405
+ current = next;
9406
+ }
9407
+ return current;
9408
+ }
9409
+ function describeStateField(schema, path) {
9410
+ const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
9411
+ if (leaf === void 0) return null;
9412
+ const field = fieldAt(schema, path);
9413
+ if (field === null) return null;
9414
+ return {
9415
+ path,
9416
+ kind: leaf.kind,
9417
+ nullable: field.safeParse(null).success,
9418
+ required: !field.safeParse(void 0).success,
9419
+ ...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
9420
+ };
9421
+ }
9422
+ function describeTopLevelStateFields(schema) {
9423
+ return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
9424
+ const described = describeStateField(schema, f.path);
9425
+ return described === null ? [] : [[f.path, described]];
9426
+ }));
9427
+ }
9428
+ /** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
9429
+ function requiredTopLevelKeys(schema) {
9430
+ const root = unwrapSchema(schema);
9431
+ if (!(root instanceof zod.z.ZodObject)) return [];
9432
+ return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
9433
+ }
9434
+ /**
9435
+ * The proper prefixes of `path` whose schema accepts `undefined`: a required
9436
+ * leaf under one of them is required only once something writes that parent
9437
+ * (`remaining.unit` is required only when `remaining` is present).
9438
+ */
9439
+ function optionalAncestors(schema, path) {
9440
+ const segments = path.split(".");
9441
+ return segments.slice(0, -1).flatMap((_, i) => {
9442
+ const prefix = segments.slice(0, i + 1).join(".");
9443
+ const field = fieldAt(schema, prefix);
9444
+ return field !== null && field.safeParse(void 0).success ? [prefix] : [];
9445
+ });
9446
+ }
9447
+ //#endregion
9448
+ //#region src/composition/composition-events.ts
9449
+ var COMPOSITION_EVENT_CATEGORY = { "doorbell.onPressed": require_event_category.EventCategory.DoorbellOnPressed };
9450
+ var EVENT_CATEGORIES = COMPOSITION_EVENT_CATEGORY;
9451
+ var CompositionEventPlanSchema = zod.z.object({
9452
+ featureIndex: zod.z.number().int().nonnegative(),
9453
+ cap: zod.z.string(),
9454
+ eventName: zod.z.string(),
9455
+ category: zod.z.enum(require_event_category.EventCategory),
9456
+ stateField: zod.z.string(),
9457
+ fieldKey: zod.z.string()
9458
+ });
9459
+ function eventProblem(code, path, message) {
9460
+ return {
9461
+ code,
9462
+ path,
9463
+ message
9464
+ };
9465
+ }
9466
+ function payloadReason(error) {
9467
+ return error.issues.map((issue) => `${issue.path.length === 0 ? "payload" : issue.path.join(".")}: ${issue.message}`).join("; ");
9468
+ }
9469
+ /**
9470
+ * Plan one capability's state-derived events after its feature mode and fields
9471
+ * are known. A native replacement never becomes a second event authority.
9472
+ */
9473
+ function planCompositionEvents(def, feature, fields) {
9474
+ if (feature.mode === "replace") return {
9475
+ problems: [],
9476
+ events: []
9477
+ };
9478
+ const problems = [];
9479
+ const events = [];
9480
+ for (const [eventName, declaration] of Object.entries(def.events ?? {})) {
9481
+ const fromState = declaration.fromState;
9482
+ if (fromState === void 0) continue;
9483
+ const statePath = `features[${feature.featureIndex}].fields.${fromState.field}`;
9484
+ const state = def.runtimeState ? describeStateField(def.runtimeState, fromState.field) : null;
9485
+ if (state === null) {
9486
+ problems.push(eventProblem("unknown-field", statePath, `\`${def.name}.${eventName}\` derives from missing state field \`${fromState.field}\``));
9487
+ continue;
9488
+ }
9489
+ if (state.kind !== "number") {
9490
+ problems.push(eventProblem("kind-mismatch", statePath, `\`${def.name}.${eventName}\` needs a numeric state field; \`${fromState.field}\` is ${state.kind}`));
9491
+ continue;
9492
+ }
9493
+ const eventKey = `${def.name}.${eventName}`;
9494
+ const category = EVENT_CATEGORIES[eventKey];
9495
+ if (category === void 0) {
9496
+ problems.push(eventProblem("not-composable", `features[${feature.featureIndex}].cap`, `\`${eventKey}\` has no explicit composition event-category mapping`));
9497
+ continue;
9498
+ }
9499
+ const payload = declaration.data.safeParse({
9500
+ deviceId: 1,
9501
+ timestamp: 1
9502
+ });
9503
+ if (!payload.success) {
9504
+ problems.push(eventProblem("not-composable", `features[${feature.featureIndex}].cap`, `\`${eventKey}\` cannot be derived from { deviceId, timestamp }: ${payloadReason(payload.error)}`));
9505
+ continue;
9506
+ }
9507
+ const field = fields.find((candidate) => candidate.featureIndex === feature.featureIndex && candidate.cap === def.name && candidate.path === fromState.field && candidate.item === void 0);
9508
+ if (field === void 0) {
9509
+ problems.push(eventProblem("unknown-field", statePath, `\`${eventKey}\` derives from \`${fromState.field}\`, but that field is not composed`));
9510
+ continue;
9511
+ }
9512
+ events.push({
9513
+ featureIndex: feature.featureIndex,
9514
+ cap: def.name,
9515
+ eventName,
9516
+ category,
9517
+ stateField: fromState.field,
9518
+ fieldKey: `${field.cap}.${field.path}`
9519
+ });
9520
+ }
9521
+ return {
9522
+ problems,
9523
+ events
9524
+ };
9525
+ }
9526
+ //#endregion
9336
9527
  //#region src/composition/composition-report.ts
9337
9528
  /**
9338
9529
  * What the validator says about a composition and what the composer says about
@@ -9388,12 +9579,14 @@ var CompositionUnavailableModeSchema = zod.z.enum([
9388
9579
  ]);
9389
9580
  /**
9390
9581
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
9391
- * field of its cap changes value · `constant` reads nothing, computed once.
9582
+ * field of its cap changes value · `constant` reads nothing, computed once ·
9583
+ * `accumulator` advances from the target's seed/current output.
9392
9584
  */
9393
9585
  var CompositionFieldRoleSchema = zod.z.enum([
9394
9586
  "derived",
9395
9587
  "clock",
9396
- "constant"
9588
+ "constant",
9589
+ "accumulator"
9397
9590
  ]);
9398
9591
  /** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
9399
9592
  var CompositionFieldItemSchema = zod.z.object({
@@ -9434,6 +9627,7 @@ var CompositionFeatureModeSchema = zod.z.enum([
9434
9627
  "replace"
9435
9628
  ]);
9436
9629
  var CompositionFeaturePlanSchema = zod.z.object({
9630
+ /** Index in the stored feature array; disabled features are omitted rather than re-indexed. */
9437
9631
  featureIndex: zod.z.number().int().nonnegative(),
9438
9632
  cap: zod.z.string(),
9439
9633
  mode: CompositionFeatureModeSchema
@@ -9442,7 +9636,8 @@ var CompositionValidationSchema = zod.z.object({
9442
9636
  ok: zod.z.boolean(),
9443
9637
  problems: zod.z.array(CompositionProblemSchema),
9444
9638
  fields: zod.z.array(CompositionFieldPlanSchema),
9445
- features: zod.z.array(CompositionFeaturePlanSchema)
9639
+ features: zod.z.array(CompositionFeaturePlanSchema),
9640
+ events: zod.z.array(CompositionEventPlanSchema)
9446
9641
  });
9447
9642
  /**
9448
9643
  * Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
@@ -29781,172 +29976,6 @@ var CLIP_PLAYBACK_OPTIONS = {
29781
29976
  }
29782
29977
  };
29783
29978
  //#endregion
29784
- //#region src/catalogs/sensor-active-state.ts
29785
- /**
29786
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
29787
- * valutatore puro del suo FRONTE.
29788
- *
29789
- * Viveva dentro il builtin virtual-doorbell
29790
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
29791
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
29792
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
29793
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
29794
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
29795
- * SPOSTA qui e il doorbell la ri-esporta.
29796
- *
29797
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
29798
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
29799
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
29800
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
29801
- */
29802
- /**
29803
- * Known binary / switch source caps → the boolean slice field whose
29804
- * false→true rise counts as ACTIVE. Every entry is "fire on active".
29805
- * Sensors whose "active" reading is not a plain boolean (presence's string
29806
- * state, connectivity's connected flag) are deliberately excluded — a
29807
- * reconnect is not a doorbell press, and it is not a recording either.
29808
- */
29809
- var SOURCE_CAP_ACTIVE_FIELD = {
29810
- contact: "entryOpen",
29811
- binary: "on",
29812
- switch: "on",
29813
- motion: "detected",
29814
- flood: "flooded",
29815
- gas: "detected",
29816
- smoke: "detected",
29817
- "carbon-monoxide": "detected",
29818
- vibration: "detected",
29819
- tamper: "tampered"
29820
- };
29821
- /**
29822
- * The same caps → the slice field carrying the ms-epoch timestamp of the
29823
- * last transition. Every source cap MUST appear here (guarded by a spec):
29824
- * without a transition timestamp the evaluator cannot tell a genuine rise
29825
- * from a boot-time hydration when the FIRST slice it ever sees is already
29826
- * active, and errs towards silence — swallowing the rise.
29827
- *
29828
- * These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
29829
- * provider derives them from `state.last_changed`, so they survive our own
29830
- * restarts and correctly read as "hours ago" for a state that has been
29831
- * active for hours. `motion` names its rise timestamp `lastDetectedAt`.
29832
- */
29833
- var SOURCE_CAP_CHANGED_AT_FIELD = {
29834
- contact: "lastChangedAt",
29835
- binary: "lastChangedAt",
29836
- switch: "lastChangedAt",
29837
- motion: "lastDetectedAt",
29838
- flood: "lastChangedAt",
29839
- gas: "lastChangedAt",
29840
- smoke: "lastChangedAt",
29841
- "carbon-monoxide": "lastChangedAt",
29842
- vibration: "lastChangedAt",
29843
- tamper: "lastChangedAt"
29844
- };
29845
- /** Cap names whose presence in a device's bindings qualify it as a source. */
29846
- var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
29847
- /**
29848
- * Device `type` values (from `DeviceType`) that can host a binary/switch
29849
- * source cap. Used by the camera's `device-multiselect` picker as the
29850
- * CLIENT-SIDE filter, alongside `SOURCE_CAPS`.
29851
- *
29852
- * Why types and not caps alone: the shared picker filters
29853
- * `deviceManager.listAll` rows client-side, and those rows carry only the
29854
- * device's advertised `features` — NOT its registered cap list. On the live
29855
- * cluster binary sensors and switches advertise EMPTY features (features
29856
- * mirror only a handful of caps like `motion-trigger`), so a caps-only
29857
- * filter matched against `features` would list nothing (the very bug this
29858
- * replaced, which relied on the now-empty `getAllBindings`). Matching by
29859
- * `type` is the reliable client-side signal; the union with `SOURCE_CAPS`
29860
- * still captures any device that DOES advertise a source-cap feature.
29861
- * `sensor` covers contact/motion/flood/gas/smoke/CO/vibration/tamper,
29862
- * `switch` covers switches, `control` covers generic binary actuators.
29863
- */
29864
- var SOURCE_DEVICE_TYPES = [
29865
- "sensor",
29866
- "switch",
29867
- "control"
29868
- ];
29869
- /** True when a cap is a recognised binary/switch source. */
29870
- function isSourceCap(capName) {
29871
- return Object.prototype.hasOwnProperty.call(SOURCE_CAP_ACTIVE_FIELD, capName);
29872
- }
29873
- /** Extract the "active" boolean a source cap's slice carries, or null when
29874
- * the cap is unknown or the field is missing / non-boolean. */
29875
- function sliceActiveValue(capName, slice) {
29876
- const field = SOURCE_CAP_ACTIVE_FIELD[capName];
29877
- if (field === void 0) return null;
29878
- const raw = slice[field];
29879
- return typeof raw === "boolean" ? raw : null;
29880
- }
29881
- /** Ms-epoch transition timestamp a source cap's slice carries, or null when
29882
- * it is absent, non-numeric or the zero "never observed" sentinel. */
29883
- function sliceChangedAt(capName, slice) {
29884
- const field = SOURCE_CAP_CHANGED_AT_FIELD[capName];
29885
- if (field === void 0) return null;
29886
- const raw = slice[field];
29887
- if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return null;
29888
- return raw;
29889
- }
29890
- /**
29891
- * How recent a source's own transition timestamp must be for a FIRST
29892
- * sighting that is already active to count as a genuine rise rather than a
29893
- * hydration of long-standing state.
29894
- */
29895
- var DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = 3e4;
29896
- /**
29897
- * IL fronte. Puro: nessun orologio proprio, nessuna memoria — il chiamante
29898
- * porta `prior`, `nowMs` e il proprio `startedAtMs`.
29899
- *
29900
- * Il caso della PRIMA slice già attiva è trattato esplicitamente e vale come
29901
- * fronte solo se il timestamp UPSTREAM della transizione è posteriore a
29902
- * `startedAtMs` **e** entro `firstSightingFreshnessMs`. Entrambe le metà
29903
- * servono: la sola freschezza scatterebbe su un'idratazione al boot di uno
29904
- * stato flippato pochi secondi prima del riavvio, e il solo "dopo che abbiamo
29905
- * iniziato" scatterebbe, su un processo di lunga vita, per una sorgente
29906
- * adottata oggi il cui stato è cambiato ieri. Il caso ambiguo ERRA VERSO IL
29907
- * SILENZIO e lo dichiara (`baseline-seeded-stale-active`).
29908
- */
29909
- function evaluateSensorEdge(input) {
29910
- const value = sliceActiveValue(input.capName, input.slice);
29911
- if (value === null) return {
29912
- edge: "none",
29913
- value: null,
29914
- reason: isSourceCap(input.capName) ? "non-boolean-value" : "unknown-cap"
29915
- };
29916
- if (input.prior === void 0) {
29917
- if (!value) return {
29918
- edge: "none",
29919
- value,
29920
- reason: "baseline-seeded-inactive"
29921
- };
29922
- const changedAt = sliceChangedAt(input.capName, input.slice);
29923
- const floor = Math.max(input.startedAtMs, input.nowMs - input.firstSightingFreshnessMs);
29924
- if (changedAt === null || changedAt < floor) return {
29925
- edge: "none",
29926
- value,
29927
- reason: "baseline-seeded-stale-active"
29928
- };
29929
- return {
29930
- edge: "rising",
29931
- value: true
29932
- };
29933
- }
29934
- if (input.prior === value) return {
29935
- edge: "none",
29936
- value,
29937
- reason: "no-change"
29938
- };
29939
- if (!value) return {
29940
- edge: "none",
29941
- value,
29942
- reason: "falling-edge"
29943
- };
29944
- return {
29945
- edge: "rising",
29946
- value: true
29947
- };
29948
- }
29949
- //#endregion
29950
29979
  //#region src/capabilities/doorbell.cap.ts
29951
29980
  /**
29952
29981
  * Doorbell button cap. Two kinds of providers coexist behind this cap
@@ -30001,7 +30030,7 @@ var DOORBELL_SOURCE_SLOT = {
30001
30030
  description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
30002
30031
  shape: "association",
30003
30032
  hostDeviceTypes: [require_err_msg.DeviceType.Camera],
30004
- sourceCaps: SOURCE_CAPS,
30033
+ sourceCaps: require_composition.SOURCE_CAPS,
30005
30034
  cardinality: "many",
30006
30035
  value: DoorbellSourceSlotValueSchema
30007
30036
  };
@@ -30021,7 +30050,13 @@ var doorbellCapability = {
30021
30050
  * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
30022
30051
  * release/duration — it's a pulse.
30023
30052
  */
30024
- onPressed: { data: DoorbellPressEventSchema } },
30053
+ onPressed: {
30054
+ data: DoorbellPressEventSchema,
30055
+ fromState: {
30056
+ field: "lastPressedAt",
30057
+ on: "advance"
30058
+ }
30059
+ } },
30025
30060
  status: {
30026
30061
  schema: DoorbellStatusSchema,
30027
30062
  kind: "push"
@@ -44506,7 +44541,7 @@ function createDeviceExtensionProvider(options) {
44506
44541
  var CompositionGraphError = class extends Error {};
44507
44542
  /** `"cap.field"` of every field a peer writes — the same spelling as `compositionFieldKey`. */
44508
44543
  function writtenFields(peer) {
44509
- return new Set(peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
44544
+ return new Set(peer.composition.features.flatMap((feature) => !require_composition.compositionFeatureEnabled(feature) || feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
44510
44545
  }
44511
44546
  /** A read of the peer's OWN device is an edge only when it reads the peer's own output (rule 5, D663). */
44512
44547
  function readsComposedValue(peer, written, read) {
@@ -44516,7 +44551,7 @@ function readsComposedValue(peer, written, read) {
44516
44551
  }
44517
44552
  function peerEdges(peer) {
44518
44553
  const written = writtenFields(peer);
44519
- return peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
44554
+ return peer.composition.features.flatMap((feature) => !require_composition.compositionFeatureEnabled(feature) || feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
44520
44555
  source: peer.target,
44521
44556
  cap: feature.cap,
44522
44557
  fieldPath
@@ -44642,118 +44677,6 @@ function findCandidateCycles(candidate, stored) {
44642
44677
  });
44643
44678
  }
44644
44679
  //#endregion
44645
- //#region src/device/schema-fields.ts
44646
- /** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
44647
- * Zod v4 exposes `.unwrap()` on all three wrapper classes. */
44648
- function unwrapSchema(schema) {
44649
- let s = schema;
44650
- while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
44651
- return s;
44652
- }
44653
- function leafKind(schema) {
44654
- const s = unwrapSchema(schema);
44655
- if (s instanceof zod.z.ZodEnum) return {
44656
- kind: "enum",
44657
- enumValues: s.options
44658
- };
44659
- if (s instanceof zod.z.ZodNumber) return { kind: "number" };
44660
- if (s instanceof zod.z.ZodString) return { kind: "string" };
44661
- if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
44662
- return null;
44663
- }
44664
- /** Walk a cap status schema into flat wireable leaf fields (dotted paths).
44665
- * Recurses into nested ZodObject (unwrapping nullable/optional/default first),
44666
- * so fields with null live values are still offered. Arrays / unknown shapes
44667
- * are skipped — never throws. */
44668
- function enumerateSchemaFields(schema, prefix = "") {
44669
- const root = unwrapSchema(schema);
44670
- if (!(root instanceof zod.z.ZodObject)) return [];
44671
- const out = [];
44672
- const shape = root.shape;
44673
- for (const [key, field] of Object.entries(shape)) {
44674
- const path = prefix ? `${prefix}.${key}` : key;
44675
- const inner = unwrapSchema(field);
44676
- if (inner instanceof zod.z.ZodObject) {
44677
- out.push(...enumerateSchemaFields(inner, path));
44678
- continue;
44679
- }
44680
- const leaf = leafKind(field);
44681
- if (leaf) out.push({
44682
- path,
44683
- kind: leaf.kind,
44684
- ...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
44685
- });
44686
- }
44687
- return out;
44688
- }
44689
- /** Enumerate the per-item wireable fields of an item-array cap (see
44690
- * `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
44691
- * `keyField` (the key comes from the link's `itemKey`, never from a wired
44692
- * source), each tagged `item: true` so the authoring UI collects an
44693
- * `itemKey` alongside the field. Never throws. */
44694
- function enumerateItemArrayFields(itemArray) {
44695
- return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
44696
- ...f,
44697
- item: true
44698
- }));
44699
- }
44700
- //#endregion
44701
- //#region src/composition/state-fields.ts
44702
- /**
44703
- * What a capability's state field IS: kind, nullability, whether required. The
44704
- * validator needs nullability, which `enumerateSchemaFields` does not report,
44705
- * and that decides a field's unavailable mode (D393).
44706
- */
44707
- function fieldAt(schema, path) {
44708
- let current = schema;
44709
- for (const segment of path.split(".")) {
44710
- const container = unwrapSchema(current);
44711
- if (!(container instanceof zod.z.ZodObject)) return null;
44712
- const next = container.shape[segment];
44713
- if (!(next instanceof zod.z.ZodType)) return null;
44714
- current = next;
44715
- }
44716
- return current;
44717
- }
44718
- function describeStateField(schema, path) {
44719
- const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
44720
- if (leaf === void 0) return null;
44721
- const field = fieldAt(schema, path);
44722
- if (field === null) return null;
44723
- return {
44724
- path,
44725
- kind: leaf.kind,
44726
- nullable: field.safeParse(null).success,
44727
- required: !field.safeParse(void 0).success,
44728
- ...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
44729
- };
44730
- }
44731
- function describeTopLevelStateFields(schema) {
44732
- return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
44733
- const described = describeStateField(schema, f.path);
44734
- return described === null ? [] : [[f.path, described]];
44735
- }));
44736
- }
44737
- /** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
44738
- function requiredTopLevelKeys(schema) {
44739
- const root = unwrapSchema(schema);
44740
- if (!(root instanceof zod.z.ZodObject)) return [];
44741
- return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
44742
- }
44743
- /**
44744
- * The proper prefixes of `path` whose schema accepts `undefined`: a required
44745
- * leaf under one of them is required only once something writes that parent
44746
- * (`remaining.unit` is required only when `remaining` is present).
44747
- */
44748
- function optionalAncestors(schema, path) {
44749
- const segments = path.split(".");
44750
- return segments.slice(0, -1).flatMap((_, i) => {
44751
- const prefix = segments.slice(0, i + 1).join(".");
44752
- const field = fieldAt(schema, prefix);
44753
- return field !== null && field.safeParse(void 0).success ? [prefix] : [];
44754
- });
44755
- }
44756
- //#endregion
44757
44680
  //#region src/composition/plan-result.ts
44758
44681
  function problem(code, path, message) {
44759
44682
  return {
@@ -44766,7 +44689,8 @@ function refused(...problems) {
44766
44689
  return {
44767
44690
  problems,
44768
44691
  fields: [],
44769
- features: []
44692
+ features: [],
44693
+ events: []
44770
44694
  };
44771
44695
  }
44772
44696
  /** Where a planned field sits in the composition: `features[N].fields.<path>` or `features[N].items.<key>.fields.<path>`. */
@@ -44810,7 +44734,12 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
44810
44734
  number: {
44811
44735
  kind: "fixed",
44812
44736
  result: ["number", "null"]
44813
- }
44737
+ },
44738
+ rose: {
44739
+ kind: "fixed",
44740
+ result: ["number", "null"]
44741
+ },
44742
+ count: NUMBER
44814
44743
  });
44815
44744
  var KindInferenceError = class extends Error {};
44816
44745
  function kindOfValue(value) {
@@ -44869,6 +44798,21 @@ function kindsOf(node, bindings) {
44869
44798
  case "call": return callKinds(node.callee, node.args.map((a) => kindsOf(a, bindings)));
44870
44799
  }
44871
44800
  }
44801
+ function nodeContainsCall(node, callee) {
44802
+ switch (node.kind) {
44803
+ case "literal":
44804
+ case "identifier": return false;
44805
+ case "unary": return nodeContainsCall(node.operand, callee);
44806
+ case "binary":
44807
+ case "logical": return nodeContainsCall(node.left, callee) || nodeContainsCall(node.right, callee);
44808
+ case "conditional": return nodeContainsCall(node.test, callee) || nodeContainsCall(node.consequent, callee) || nodeContainsCall(node.alternate, callee);
44809
+ case "call": return node.callee === callee || node.args.some((arg) => nodeContainsCall(arg, callee));
44810
+ }
44811
+ }
44812
+ function expressionContainsBuiltinCall(expr, callee) {
44813
+ const compiled = require_composition.compileExpressionSafe(expr);
44814
+ return compiled.ok && nodeContainsCall(compiled.parsed.ast, callee);
44815
+ }
44872
44816
  function inferExpressionKinds(input) {
44873
44817
  const compiled = require_composition.compileExpressionSafe(input.expr);
44874
44818
  if (!compiled.ok) return {
@@ -44991,6 +44935,7 @@ function enumLiteralProblem(cap, target, source, at) {
44991
44935
  }
44992
44936
  function roleOf(source) {
44993
44937
  if (source.kind !== "expression") return "derived";
44938
+ if (expressionContainsBuiltinCall(source.expr, "count")) return "accumulator";
44994
44939
  if (require_composition.fieldReads(source).length > 0) return "derived";
44995
44940
  const compiled = require_composition.compileExpressionSafe(source.expr);
44996
44941
  return compiled.ok && compiled.parsed.identifiers.has("now") ? "clock" : "constant";
@@ -45002,13 +44947,13 @@ function roleOf(source) {
45002
44947
  * field that READS a source never gets `offline`.
45003
44948
  */
45004
44949
  function unavailableFor(tf, role, mode, cap, at) {
45005
- if (mode === "new" || role !== "derived") return {
44950
+ if (mode === "replace" && (role === "derived" || role === "accumulator")) return {
45006
44951
  ok: true,
45007
- unavailable: tf.nullable ? "null" : "offline"
44952
+ unavailable: "release"
45008
44953
  };
45009
- if (mode === "replace") return {
44954
+ if (mode === "new" || role !== "derived") return {
45010
44955
  ok: true,
45011
- unavailable: "release"
44956
+ unavailable: tf.nullable ? "null" : "offline"
45012
44957
  };
45013
44958
  if (tf.nullable) return {
45014
44959
  ok: true,
@@ -45083,7 +45028,8 @@ function planItemField(ctx, leaf) {
45083
45028
  return {
45084
45029
  problems: [...compatibility(capName, tf, kinds.kinds, at), ...enumProblem === null ? [] : [enumProblem]],
45085
45030
  fields: [plan],
45086
- features: []
45031
+ features: [],
45032
+ events: []
45087
45033
  };
45088
45034
  }
45089
45035
  function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
@@ -45102,7 +45048,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
45102
45048
  const results = Object.entries(feature.items ?? {}).flatMap(([key, item]) => [{
45103
45049
  problems: missingLeaves(ctx, item, `${at}.${key}`),
45104
45050
  fields: [],
45105
- features: []
45051
+ features: [],
45052
+ events: []
45106
45053
  }, ...Object.entries(item.fields).map(([path, source]) => planItemField(ctx, {
45107
45054
  key,
45108
45055
  label: item.label,
@@ -45112,7 +45059,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
45112
45059
  return {
45113
45060
  problems: results.flatMap((r) => r.problems),
45114
45061
  fields: results.flatMap((r) => r.fields),
45115
- features: []
45062
+ features: [],
45063
+ events: []
45116
45064
  };
45117
45065
  }
45118
45066
  //#endregion
@@ -45138,7 +45086,7 @@ function fromReading(reading, read) {
45138
45086
  deadline: null
45139
45087
  };
45140
45088
  }
45141
- function expressionOutcome(source, read, now) {
45089
+ function expressionOutcome(source, read, now, stateful) {
45142
45090
  const values = {};
45143
45091
  const staleReasons = [];
45144
45092
  let fatalUnavailable = null;
@@ -45167,10 +45115,31 @@ function expressionOutcome(source, read, now) {
45167
45115
  values[name] = reading.value;
45168
45116
  if (reading.state === "stale") staleReasons.push(`\`${name}\`: ${reading.reason}`);
45169
45117
  }
45170
- if (fatalUnavailable !== null) return fatalUnavailable;
45171
- if (nonFatalUnavailable !== null) return nonFatalUnavailable;
45118
+ const unavailable = fatalUnavailable ?? nonFatalUnavailable;
45119
+ if (unavailable !== null) {
45120
+ if (stateful !== void 0 && stateful.currentOutput !== void 0 && expressionContainsBuiltinCall(source.expr, "count")) return {
45121
+ state: "stale",
45122
+ value: require_composition.evaluateCount(null, {
45123
+ kind: "count",
45124
+ highWater: null
45125
+ }, stateful.currentOutput),
45126
+ reason: `${unavailable.reason}; holding the last accumulator value`,
45127
+ deadline: null
45128
+ };
45129
+ return unavailable;
45130
+ }
45172
45131
  const deadlines = [];
45173
- const result = require_composition.evaluateExpressionSource(source.expr, values, now, { hooks: { noteDeadline: (at) => deadlines.push(at) } });
45132
+ const result = require_composition.evaluateExpressionSource(source.expr, values, now, {
45133
+ hooks: { noteDeadline: (at) => deadlines.push(at) },
45134
+ ...stateful === void 0 ? {} : { invokeStateful: (invocation) => require_composition.evaluateStatefulExpressionCall(stateful.callPathPrefix === void 0 ? invocation : {
45135
+ ...invocation,
45136
+ path: `${stateful.callPathPrefix}@${invocation.path}`
45137
+ }, stateful.expressionMemory, {
45138
+ currentOutput: stateful.currentOutput,
45139
+ startedAtMs: stateful.startedAtMs,
45140
+ nowMs: now
45141
+ }) }
45142
+ });
45174
45143
  if (!result.ok) return {
45175
45144
  state: "unavailable",
45176
45145
  value: null,
@@ -45189,7 +45158,7 @@ function evaluateCompositionField(input) {
45189
45158
  const { source } = input;
45190
45159
  switch (source.kind) {
45191
45160
  case "from": return fromReading(input.read(source), source);
45192
- case "expression": return expressionOutcome(source, input.read, input.now);
45161
+ case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
45193
45162
  case "code": return {
45194
45163
  state: "unavailable",
45195
45164
  value: null,
@@ -45471,7 +45440,8 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
45471
45440
  return {
45472
45441
  problems: [...compatibility(def.name, tf, kinds.kinds, fieldAt), ...enumProblem === null ? [] : [enumProblem]],
45473
45442
  fields: [plan],
45474
- features: []
45443
+ features: [],
45444
+ events: []
45475
45445
  };
45476
45446
  }
45477
45447
  function planFeature(feature, featureIndex, target, lookupCap) {
@@ -45487,14 +45457,22 @@ function planFeature(feature, featureIndex, target, lookupCap) {
45487
45457
  }, target.mode, lookupCap));
45488
45458
  const items = feature.items === void 0 ? [] : [planItems(cap.def, feature, featureIndex, lookupCap, target.mode)];
45489
45459
  const all = [...perField, ...items];
45460
+ const fields = all.flatMap((result) => result.fields);
45461
+ const featurePlan = {
45462
+ featureIndex,
45463
+ cap: cap.def.name,
45464
+ mode: target.mode
45465
+ };
45466
+ const eventPlan = planCompositionEvents(cap.def, featurePlan, fields);
45490
45467
  return {
45491
- problems: [...capProblems, ...all.flatMap((r) => r.problems)],
45492
- fields: all.flatMap((r) => r.fields),
45493
- features: [{
45494
- featureIndex,
45495
- cap: cap.def.name,
45496
- mode: target.mode
45497
- }]
45468
+ problems: [
45469
+ ...capProblems,
45470
+ ...all.flatMap((r) => r.problems),
45471
+ ...eventPlan.problems
45472
+ ],
45473
+ fields,
45474
+ features: [featurePlan],
45475
+ events: eventPlan.events
45498
45476
  };
45499
45477
  }
45500
45478
  /** A cap the device serves itself; one the composer grafted (an earlier ADD) is not native. */
@@ -45536,17 +45514,23 @@ function planComposition(composition, lookupCap, target) {
45536
45514
  const planTarget = planTargetOf(composition, target);
45537
45515
  if ("code" in planTarget) return refused(planTarget);
45538
45516
  const results = composition.features.map((feature, index) => {
45539
- if (feature.kind === "passthrough") return refused(problem("reserved-variant", `features[${index}]`, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
45540
- return planFeature(feature, index, featureTargetOf(planTarget, feature.cap), lookupCap);
45517
+ const result = feature.kind === "passthrough" ? refused(problem("reserved-variant", `features[${index}]`, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`)) : planFeature(feature, index, featureTargetOf(planTarget, feature.cap), lookupCap);
45518
+ return require_composition.compositionFeatureEnabled(feature) ? result : {
45519
+ problems: result.problems,
45520
+ fields: [],
45521
+ features: [],
45522
+ events: []
45523
+ };
45541
45524
  });
45542
45525
  return {
45543
45526
  problems: results.flatMap((r) => r.problems),
45544
45527
  fields: results.flatMap((r) => r.fields),
45545
- features: results.flatMap((r) => r.features)
45528
+ features: results.flatMap((r) => r.features),
45529
+ events: results.flatMap((r) => r.events)
45546
45530
  };
45547
45531
  }
45548
45532
  function compositionSourceRefs(composition) {
45549
- const refs = composition.features.flatMap((f) => f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
45533
+ const refs = composition.features.flatMap((f) => require_composition.compositionFeatureEnabled(f) && f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
45550
45534
  return [...new Map(refs.map((r) => [require_composition.compositionSourceKey(r), r])).values()];
45551
45535
  }
45552
45536
  /**
@@ -45681,7 +45665,8 @@ function validateComposition(composition, ctx) {
45681
45665
  ok: problems.length === 0,
45682
45666
  problems,
45683
45667
  fields: [...plan.fields],
45684
- features: [...plan.features]
45668
+ features: [...plan.features],
45669
+ events: [...plan.events]
45685
45670
  };
45686
45671
  }
45687
45672
  //#endregion
@@ -64185,7 +64170,7 @@ var NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = "This rule belongs to the alarm,
64185
64170
  */
64186
64171
  /** Event kind → the boolean field of its cap slice that means "raised". */
64187
64172
  var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
64188
- const field = SOURCE_CAP_ACTIVE_FIELD[capName];
64173
+ const field = require_composition.SOURCE_CAP_ACTIVE_FIELD[capName];
64189
64174
  if (field === void 0 || descriptor.category !== "sensor") return [];
64190
64175
  return [[descriptor.kind, field]];
64191
64176
  })));
@@ -68287,6 +68272,7 @@ exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = require_composition.COMPOSED_DEVICE_S
68287
68272
  exports.COMPOSED_ITEM_FIXED_FIELDS = COMPOSED_ITEM_FIXED_FIELDS;
68288
68273
  exports.COMPOSER_ADDON_ID = require_composition.COMPOSER_ADDON_ID;
68289
68274
  exports.COMPOSER_RUNNER_ID = COMPOSER_RUNNER_ID;
68275
+ exports.COMPOSITION_EVENT_CATEGORY = COMPOSITION_EVENT_CATEGORY;
68290
68276
  exports.COMPOSITION_ITEM_ARRAY_PATH = require_composition.COMPOSITION_ITEM_ARRAY_PATH;
68291
68277
  exports.COMPOSITION_ITEM_KEY_RE = require_composition.COMPOSITION_ITEM_KEY_RE;
68292
68278
  exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
@@ -68371,6 +68357,7 @@ exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
68371
68357
  exports.CompositionCodeSourceSchema = require_composition.CompositionCodeSourceSchema;
68372
68358
  exports.CompositionCommandTargetSchema = require_composition.CompositionCommandTargetSchema;
68373
68359
  exports.CompositionCustomizationReadSchema = CompositionCustomizationReadSchema;
68360
+ exports.CompositionEventPlanSchema = CompositionEventPlanSchema;
68374
68361
  exports.CompositionExistingTargetSchema = require_composition.CompositionExistingTargetSchema;
68375
68362
  exports.CompositionExpressionSourceSchema = require_composition.CompositionExpressionSourceSchema;
68376
68363
  exports.CompositionFeatureModeSchema = CompositionFeatureModeSchema;
@@ -68451,7 +68438,7 @@ exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
68451
68438
  exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
68452
68439
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
68453
68440
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
68454
- exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
68441
+ exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = require_composition.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
68455
68442
  exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
68456
68443
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
68457
68444
  exports.DEFAULT_OVERLAY_LAYERS = DEFAULT_OVERLAY_LAYERS;
@@ -69245,10 +69232,10 @@ exports.SCOPE_PRESETS = SCOPE_PRESETS;
69245
69232
  exports.SENSOR_FEATURES = SENSOR_FEATURES;
69246
69233
  exports.SENSOR_MAP = SENSOR_MAP;
69247
69234
  exports.SHARE_VIEW_KINDS = require_sleep.SHARE_VIEW_KINDS;
69248
- exports.SOURCE_CAPS = SOURCE_CAPS;
69249
- exports.SOURCE_CAP_ACTIVE_FIELD = SOURCE_CAP_ACTIVE_FIELD;
69250
- exports.SOURCE_CAP_CHANGED_AT_FIELD = SOURCE_CAP_CHANGED_AT_FIELD;
69251
- exports.SOURCE_DEVICE_TYPES = SOURCE_DEVICE_TYPES;
69235
+ exports.SOURCE_CAPS = require_composition.SOURCE_CAPS;
69236
+ exports.SOURCE_CAP_ACTIVE_FIELD = require_composition.SOURCE_CAP_ACTIVE_FIELD;
69237
+ exports.SOURCE_CAP_CHANGED_AT_FIELD = require_composition.SOURCE_CAP_CHANGED_AT_FIELD;
69238
+ exports.SOURCE_DEVICE_TYPES = require_composition.SOURCE_DEVICE_TYPES;
69252
69239
  exports.SOURCE_INFO_METADATA_KEY = SOURCE_INFO_METADATA_KEY;
69253
69240
  exports.STATIONARY_OVERLAY_STYLE = STATIONARY_OVERLAY_STYLE;
69254
69241
  exports.STORAGE_ACCESS_FALLBACK = STORAGE_ACCESS_FALLBACK;
@@ -69560,6 +69547,7 @@ exports.climateControlCapability = climateControlCapability;
69560
69547
  exports.clipExportFailure = clipExportFailure;
69561
69548
  exports.clipExportFailureOf = clipExportFailureOf;
69562
69549
  exports.clipReasonHeaderValue = clipReasonHeaderValue;
69550
+ exports.cloneStatefulExpressionMemory = require_composition.cloneStatefulExpressionMemory;
69563
69551
  exports.clusterModelSettingKey = clusterModelSettingKey;
69564
69552
  exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
69565
69553
  exports.clusterStepSettingKey = clusterStepSettingKey;
@@ -69578,6 +69566,7 @@ exports.composedDeviceRef = require_composition.composedDeviceRef;
69578
69566
  exports.composedDeviceStableId = require_composition.composedDeviceStableId;
69579
69567
  exports.composerCapability = composerCapability;
69580
69568
  exports.compositionEdges = compositionEdges;
69569
+ exports.compositionFeatureEnabled = require_composition.compositionFeatureEnabled;
69581
69570
  exports.compositionFieldKey = compositionFieldKey;
69582
69571
  exports.compositionItemFieldPath = require_composition.compositionItemFieldPath;
69583
69572
  exports.compositionReadKey = require_composition.compositionReadKey;
@@ -69614,6 +69603,7 @@ exports.createLogChannelsProvider = createLogChannelsProvider;
69614
69603
  exports.createMirrorSource = require_sleep.createMirrorSource;
69615
69604
  exports.createRuntimeStateBridge = createRuntimeStateBridge;
69616
69605
  exports.createSliceHandle = require_sleep.createSliceHandle;
69606
+ exports.createStatefulExpressionMemory = require_composition.createStatefulExpressionMemory;
69617
69607
  exports.createSystemProxy = createSystemProxy;
69618
69608
  exports.customAction = require_sleep.customAction;
69619
69609
  exports.customModelRegistryCapability = customModelRegistryCapability;
@@ -69680,9 +69670,13 @@ exports.enumerateSchemaFields = enumerateSchemaFields;
69680
69670
  exports.errMsg = require_err_msg.errMsg;
69681
69671
  exports.evaluateAst = require_composition.evaluateAst;
69682
69672
  exports.evaluateCompositionField = evaluateCompositionField;
69673
+ exports.evaluateCount = require_composition.evaluateCount;
69683
69674
  exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
69684
69675
  exports.evaluatePoolMemory = evaluatePoolMemory;
69685
- exports.evaluateSensorEdge = evaluateSensorEdge;
69676
+ exports.evaluateRose = require_composition.evaluateRose;
69677
+ exports.evaluateSensorEdge = require_composition.evaluateSensorEdge;
69678
+ exports.evaluateSensorLevelEdge = require_composition.evaluateSensorLevelEdge;
69679
+ exports.evaluateStatefulExpressionCall = require_composition.evaluateStatefulExpressionCall;
69686
69680
  exports.evaluateZoneRules = evaluateZoneRules;
69687
69681
  exports.event = require_sleep.event;
69688
69682
  exports.eventEmitterCapability = eventEmitterCapability;
@@ -69692,6 +69686,7 @@ exports.expandAudioChunkToF32le = require_sleep.expandAudioChunkToF32le;
69692
69686
  exports.expandCapMethods = require_sleep.expandCapMethods;
69693
69687
  exports.expandContainer = expandContainer;
69694
69688
  exports.exportSubjectOf = exportSubjectOf;
69689
+ exports.expressionContainsBuiltinCall = expressionContainsBuiltinCall;
69695
69690
  exports.extensionSlotRef = extensionSlotRef;
69696
69691
  exports.extractNestedAddonId = extractNestedAddonId;
69697
69692
  exports.extractSourceInfoFromMetadata = extractSourceInfoFromMetadata;
@@ -69771,7 +69766,8 @@ exports.isSameAddonId = isSameAddonId;
69771
69766
  exports.isScheduleActive = isScheduleActive;
69772
69767
  exports.isSecretConfigField = isSecretConfigField;
69773
69768
  exports.isSoftwareDecode = require_composition.isSoftwareDecode;
69774
- exports.isSourceCap = isSourceCap;
69769
+ exports.isSourceCap = require_composition.isSourceCap;
69770
+ exports.isStatefulBuiltin = require_composition.isStatefulBuiltin;
69775
69771
  exports.isStorageLocationMode = isStorageLocationMode;
69776
69772
  exports.isSystemDelivery = isSystemDelivery;
69777
69773
  exports.isSystemEventFamily = isSystemEventFamily;
@@ -69887,6 +69883,7 @@ exports.pipelineExecutorCapability = pipelineExecutorCapability;
69887
69883
  exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;
69888
69884
  exports.pipelineRunnerCapability = pipelineRunnerCapability;
69889
69885
  exports.planComposition = planComposition;
69886
+ exports.planCompositionEvents = planCompositionEvents;
69890
69887
  exports.planItems = planItems;
69891
69888
  exports.plateGalleryCapability = plateGalleryCapability;
69892
69889
  exports.platformProbeCapability = platformProbeCapability;
@@ -69986,8 +69983,8 @@ exports.signalPercentFromRssi = signalPercentFromRssi;
69986
69983
  exports.siteZoneKey = siteZoneKey;
69987
69984
  exports.sleep = require_sleep.sleep;
69988
69985
  exports.sleepCancellable = require_sleep.sleepCancellable;
69989
- exports.sliceActiveValue = sliceActiveValue;
69990
- exports.sliceChangedAt = sliceChangedAt;
69986
+ exports.sliceActiveValue = require_composition.sliceActiveValue;
69987
+ exports.sliceChangedAt = require_composition.sliceChangedAt;
69991
69988
  exports.smokeCapability = smokeCapability;
69992
69989
  exports.smtpProviderCapability = smtpProviderCapability;
69993
69990
  exports.snapshotCapability = snapshotCapability;