@camstack/types 1.2.268 → 1.2.270

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 +5 -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 +335 -329
  27. package/dist/index.mjs +313 -319
  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"
@@ -39626,12 +39661,21 @@ var RecordingStorageUsageSchema = zod.z.object({
39626
39661
  */
39627
39662
  devicesRead: zod.z.enum(["archive", "unavailable"]).optional(),
39628
39663
  /**
39664
+ * Is the `archive` answer WHOLE (D674): the hour ledger loaded without
39665
+ * hitting its row cap, and at least one location resolved? Only then may a
39666
+ * camera ABSENT from `devices[]` be read as "no footage" — and only then is a
39667
+ * row's `oldestMs` the archive's oldest rather than the oldest of a fraction.
39668
+ * OPTIONAL: a recorder predating D674 omits it, and a consumer must read the
39669
+ * absence as `false`. A retention floor is a delete; it never guesses.
39670
+ */
39671
+ complete: zod.z.boolean().optional(),
39672
+ /**
39629
39673
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
39630
- * of the payload without it: the hub serves this method through a BAKED
39631
- * router, so a hub whose framework train predates a change to this array
39632
- * strips it out of an answer a newer recorder happily produced. A UI that
39633
- * dereferences it unconditionally crashes the whole Storage page over a
39634
- * missing disk bar.
39674
+ * of the payload without it: a recorder that could not build it omits it. A
39675
+ * UI that dereferences it unconditionally crashes the whole Storage page over
39676
+ * a missing disk bar. (The hub's cap routers pass output through unvalidated
39677
+ * since 2026-07-11 — `cap-router-builder.ts` — so a newer recorder's fields
39678
+ * are not stripped by an older hub.)
39635
39679
  */
39636
39680
  locations: zod.z.array(RecordingLocationUsageSchema).optional()
39637
39681
  });
@@ -44506,7 +44550,7 @@ function createDeviceExtensionProvider(options) {
44506
44550
  var CompositionGraphError = class extends Error {};
44507
44551
  /** `"cap.field"` of every field a peer writes — the same spelling as `compositionFieldKey`. */
44508
44552
  function writtenFields(peer) {
44509
- return new Set(peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
44553
+ 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
44554
  }
44511
44555
  /** A read of the peer's OWN device is an edge only when it reads the peer's own output (rule 5, D663). */
44512
44556
  function readsComposedValue(peer, written, read) {
@@ -44516,7 +44560,7 @@ function readsComposedValue(peer, written, read) {
44516
44560
  }
44517
44561
  function peerEdges(peer) {
44518
44562
  const written = writtenFields(peer);
44519
- return peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
44563
+ return peer.composition.features.flatMap((feature) => !require_composition.compositionFeatureEnabled(feature) || feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
44520
44564
  source: peer.target,
44521
44565
  cap: feature.cap,
44522
44566
  fieldPath
@@ -44642,118 +44686,6 @@ function findCandidateCycles(candidate, stored) {
44642
44686
  });
44643
44687
  }
44644
44688
  //#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
44689
  //#region src/composition/plan-result.ts
44758
44690
  function problem(code, path, message) {
44759
44691
  return {
@@ -44766,7 +44698,8 @@ function refused(...problems) {
44766
44698
  return {
44767
44699
  problems,
44768
44700
  fields: [],
44769
- features: []
44701
+ features: [],
44702
+ events: []
44770
44703
  };
44771
44704
  }
44772
44705
  /** Where a planned field sits in the composition: `features[N].fields.<path>` or `features[N].items.<key>.fields.<path>`. */
@@ -44810,7 +44743,12 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
44810
44743
  number: {
44811
44744
  kind: "fixed",
44812
44745
  result: ["number", "null"]
44813
- }
44746
+ },
44747
+ rose: {
44748
+ kind: "fixed",
44749
+ result: ["number", "null"]
44750
+ },
44751
+ count: NUMBER
44814
44752
  });
44815
44753
  var KindInferenceError = class extends Error {};
44816
44754
  function kindOfValue(value) {
@@ -44869,6 +44807,21 @@ function kindsOf(node, bindings) {
44869
44807
  case "call": return callKinds(node.callee, node.args.map((a) => kindsOf(a, bindings)));
44870
44808
  }
44871
44809
  }
44810
+ function nodeContainsCall(node, callee) {
44811
+ switch (node.kind) {
44812
+ case "literal":
44813
+ case "identifier": return false;
44814
+ case "unary": return nodeContainsCall(node.operand, callee);
44815
+ case "binary":
44816
+ case "logical": return nodeContainsCall(node.left, callee) || nodeContainsCall(node.right, callee);
44817
+ case "conditional": return nodeContainsCall(node.test, callee) || nodeContainsCall(node.consequent, callee) || nodeContainsCall(node.alternate, callee);
44818
+ case "call": return node.callee === callee || node.args.some((arg) => nodeContainsCall(arg, callee));
44819
+ }
44820
+ }
44821
+ function expressionContainsBuiltinCall(expr, callee) {
44822
+ const compiled = require_composition.compileExpressionSafe(expr);
44823
+ return compiled.ok && nodeContainsCall(compiled.parsed.ast, callee);
44824
+ }
44872
44825
  function inferExpressionKinds(input) {
44873
44826
  const compiled = require_composition.compileExpressionSafe(input.expr);
44874
44827
  if (!compiled.ok) return {
@@ -44991,6 +44944,7 @@ function enumLiteralProblem(cap, target, source, at) {
44991
44944
  }
44992
44945
  function roleOf(source) {
44993
44946
  if (source.kind !== "expression") return "derived";
44947
+ if (expressionContainsBuiltinCall(source.expr, "count")) return "accumulator";
44994
44948
  if (require_composition.fieldReads(source).length > 0) return "derived";
44995
44949
  const compiled = require_composition.compileExpressionSafe(source.expr);
44996
44950
  return compiled.ok && compiled.parsed.identifiers.has("now") ? "clock" : "constant";
@@ -45002,13 +44956,13 @@ function roleOf(source) {
45002
44956
  * field that READS a source never gets `offline`.
45003
44957
  */
45004
44958
  function unavailableFor(tf, role, mode, cap, at) {
45005
- if (mode === "new" || role !== "derived") return {
44959
+ if (mode === "replace" && (role === "derived" || role === "accumulator")) return {
45006
44960
  ok: true,
45007
- unavailable: tf.nullable ? "null" : "offline"
44961
+ unavailable: "release"
45008
44962
  };
45009
- if (mode === "replace") return {
44963
+ if (mode === "new" || role !== "derived") return {
45010
44964
  ok: true,
45011
- unavailable: "release"
44965
+ unavailable: tf.nullable ? "null" : "offline"
45012
44966
  };
45013
44967
  if (tf.nullable) return {
45014
44968
  ok: true,
@@ -45083,7 +45037,8 @@ function planItemField(ctx, leaf) {
45083
45037
  return {
45084
45038
  problems: [...compatibility(capName, tf, kinds.kinds, at), ...enumProblem === null ? [] : [enumProblem]],
45085
45039
  fields: [plan],
45086
- features: []
45040
+ features: [],
45041
+ events: []
45087
45042
  };
45088
45043
  }
45089
45044
  function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
@@ -45102,7 +45057,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
45102
45057
  const results = Object.entries(feature.items ?? {}).flatMap(([key, item]) => [{
45103
45058
  problems: missingLeaves(ctx, item, `${at}.${key}`),
45104
45059
  fields: [],
45105
- features: []
45060
+ features: [],
45061
+ events: []
45106
45062
  }, ...Object.entries(item.fields).map(([path, source]) => planItemField(ctx, {
45107
45063
  key,
45108
45064
  label: item.label,
@@ -45112,7 +45068,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
45112
45068
  return {
45113
45069
  problems: results.flatMap((r) => r.problems),
45114
45070
  fields: results.flatMap((r) => r.fields),
45115
- features: []
45071
+ features: [],
45072
+ events: []
45116
45073
  };
45117
45074
  }
45118
45075
  //#endregion
@@ -45138,7 +45095,7 @@ function fromReading(reading, read) {
45138
45095
  deadline: null
45139
45096
  };
45140
45097
  }
45141
- function expressionOutcome(source, read, now) {
45098
+ function expressionOutcome(source, read, now, stateful) {
45142
45099
  const values = {};
45143
45100
  const staleReasons = [];
45144
45101
  let fatalUnavailable = null;
@@ -45167,10 +45124,31 @@ function expressionOutcome(source, read, now) {
45167
45124
  values[name] = reading.value;
45168
45125
  if (reading.state === "stale") staleReasons.push(`\`${name}\`: ${reading.reason}`);
45169
45126
  }
45170
- if (fatalUnavailable !== null) return fatalUnavailable;
45171
- if (nonFatalUnavailable !== null) return nonFatalUnavailable;
45127
+ const unavailable = fatalUnavailable ?? nonFatalUnavailable;
45128
+ if (unavailable !== null) {
45129
+ if (stateful !== void 0 && stateful.currentOutput !== void 0 && expressionContainsBuiltinCall(source.expr, "count")) return {
45130
+ state: "stale",
45131
+ value: require_composition.evaluateCount(null, {
45132
+ kind: "count",
45133
+ highWater: null
45134
+ }, stateful.currentOutput),
45135
+ reason: `${unavailable.reason}; holding the last accumulator value`,
45136
+ deadline: null
45137
+ };
45138
+ return unavailable;
45139
+ }
45172
45140
  const deadlines = [];
45173
- const result = require_composition.evaluateExpressionSource(source.expr, values, now, { hooks: { noteDeadline: (at) => deadlines.push(at) } });
45141
+ const result = require_composition.evaluateExpressionSource(source.expr, values, now, {
45142
+ hooks: { noteDeadline: (at) => deadlines.push(at) },
45143
+ ...stateful === void 0 ? {} : { invokeStateful: (invocation) => require_composition.evaluateStatefulExpressionCall(stateful.callPathPrefix === void 0 ? invocation : {
45144
+ ...invocation,
45145
+ path: `${stateful.callPathPrefix}@${invocation.path}`
45146
+ }, stateful.expressionMemory, {
45147
+ currentOutput: stateful.currentOutput,
45148
+ startedAtMs: stateful.startedAtMs,
45149
+ nowMs: now
45150
+ }) }
45151
+ });
45174
45152
  if (!result.ok) return {
45175
45153
  state: "unavailable",
45176
45154
  value: null,
@@ -45189,7 +45167,7 @@ function evaluateCompositionField(input) {
45189
45167
  const { source } = input;
45190
45168
  switch (source.kind) {
45191
45169
  case "from": return fromReading(input.read(source), source);
45192
- case "expression": return expressionOutcome(source, input.read, input.now);
45170
+ case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
45193
45171
  case "code": return {
45194
45172
  state: "unavailable",
45195
45173
  value: null,
@@ -45471,7 +45449,8 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
45471
45449
  return {
45472
45450
  problems: [...compatibility(def.name, tf, kinds.kinds, fieldAt), ...enumProblem === null ? [] : [enumProblem]],
45473
45451
  fields: [plan],
45474
- features: []
45452
+ features: [],
45453
+ events: []
45475
45454
  };
45476
45455
  }
45477
45456
  function planFeature(feature, featureIndex, target, lookupCap) {
@@ -45487,14 +45466,22 @@ function planFeature(feature, featureIndex, target, lookupCap) {
45487
45466
  }, target.mode, lookupCap));
45488
45467
  const items = feature.items === void 0 ? [] : [planItems(cap.def, feature, featureIndex, lookupCap, target.mode)];
45489
45468
  const all = [...perField, ...items];
45469
+ const fields = all.flatMap((result) => result.fields);
45470
+ const featurePlan = {
45471
+ featureIndex,
45472
+ cap: cap.def.name,
45473
+ mode: target.mode
45474
+ };
45475
+ const eventPlan = planCompositionEvents(cap.def, featurePlan, fields);
45490
45476
  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
- }]
45477
+ problems: [
45478
+ ...capProblems,
45479
+ ...all.flatMap((r) => r.problems),
45480
+ ...eventPlan.problems
45481
+ ],
45482
+ fields,
45483
+ features: [featurePlan],
45484
+ events: eventPlan.events
45498
45485
  };
45499
45486
  }
45500
45487
  /** A cap the device serves itself; one the composer grafted (an earlier ADD) is not native. */
@@ -45536,17 +45523,23 @@ function planComposition(composition, lookupCap, target) {
45536
45523
  const planTarget = planTargetOf(composition, target);
45537
45524
  if ("code" in planTarget) return refused(planTarget);
45538
45525
  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);
45526
+ 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);
45527
+ return require_composition.compositionFeatureEnabled(feature) ? result : {
45528
+ problems: result.problems,
45529
+ fields: [],
45530
+ features: [],
45531
+ events: []
45532
+ };
45541
45533
  });
45542
45534
  return {
45543
45535
  problems: results.flatMap((r) => r.problems),
45544
45536
  fields: results.flatMap((r) => r.fields),
45545
- features: results.flatMap((r) => r.features)
45537
+ features: results.flatMap((r) => r.features),
45538
+ events: results.flatMap((r) => r.events)
45546
45539
  };
45547
45540
  }
45548
45541
  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) : []);
45542
+ 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
45543
  return [...new Map(refs.map((r) => [require_composition.compositionSourceKey(r), r])).values()];
45551
45544
  }
45552
45545
  /**
@@ -45681,7 +45674,8 @@ function validateComposition(composition, ctx) {
45681
45674
  ok: problems.length === 0,
45682
45675
  problems,
45683
45676
  fields: [...plan.fields],
45684
- features: [...plan.features]
45677
+ features: [...plan.features],
45678
+ events: [...plan.events]
45685
45679
  };
45686
45680
  }
45687
45681
  //#endregion
@@ -64185,7 +64179,7 @@ var NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = "This rule belongs to the alarm,
64185
64179
  */
64186
64180
  /** Event kind → the boolean field of its cap slice that means "raised". */
64187
64181
  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];
64182
+ const field = require_composition.SOURCE_CAP_ACTIVE_FIELD[capName];
64189
64183
  if (field === void 0 || descriptor.category !== "sensor") return [];
64190
64184
  return [[descriptor.kind, field]];
64191
64185
  })));
@@ -68287,6 +68281,7 @@ exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = require_composition.COMPOSED_DEVICE_S
68287
68281
  exports.COMPOSED_ITEM_FIXED_FIELDS = COMPOSED_ITEM_FIXED_FIELDS;
68288
68282
  exports.COMPOSER_ADDON_ID = require_composition.COMPOSER_ADDON_ID;
68289
68283
  exports.COMPOSER_RUNNER_ID = COMPOSER_RUNNER_ID;
68284
+ exports.COMPOSITION_EVENT_CATEGORY = COMPOSITION_EVENT_CATEGORY;
68290
68285
  exports.COMPOSITION_ITEM_ARRAY_PATH = require_composition.COMPOSITION_ITEM_ARRAY_PATH;
68291
68286
  exports.COMPOSITION_ITEM_KEY_RE = require_composition.COMPOSITION_ITEM_KEY_RE;
68292
68287
  exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
@@ -68371,6 +68366,7 @@ exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
68371
68366
  exports.CompositionCodeSourceSchema = require_composition.CompositionCodeSourceSchema;
68372
68367
  exports.CompositionCommandTargetSchema = require_composition.CompositionCommandTargetSchema;
68373
68368
  exports.CompositionCustomizationReadSchema = CompositionCustomizationReadSchema;
68369
+ exports.CompositionEventPlanSchema = CompositionEventPlanSchema;
68374
68370
  exports.CompositionExistingTargetSchema = require_composition.CompositionExistingTargetSchema;
68375
68371
  exports.CompositionExpressionSourceSchema = require_composition.CompositionExpressionSourceSchema;
68376
68372
  exports.CompositionFeatureModeSchema = CompositionFeatureModeSchema;
@@ -68451,7 +68447,7 @@ exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
68451
68447
  exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
68452
68448
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
68453
68449
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
68454
- exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
68450
+ exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = require_composition.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
68455
68451
  exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
68456
68452
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
68457
68453
  exports.DEFAULT_OVERLAY_LAYERS = DEFAULT_OVERLAY_LAYERS;
@@ -69245,10 +69241,10 @@ exports.SCOPE_PRESETS = SCOPE_PRESETS;
69245
69241
  exports.SENSOR_FEATURES = SENSOR_FEATURES;
69246
69242
  exports.SENSOR_MAP = SENSOR_MAP;
69247
69243
  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;
69244
+ exports.SOURCE_CAPS = require_composition.SOURCE_CAPS;
69245
+ exports.SOURCE_CAP_ACTIVE_FIELD = require_composition.SOURCE_CAP_ACTIVE_FIELD;
69246
+ exports.SOURCE_CAP_CHANGED_AT_FIELD = require_composition.SOURCE_CAP_CHANGED_AT_FIELD;
69247
+ exports.SOURCE_DEVICE_TYPES = require_composition.SOURCE_DEVICE_TYPES;
69252
69248
  exports.SOURCE_INFO_METADATA_KEY = SOURCE_INFO_METADATA_KEY;
69253
69249
  exports.STATIONARY_OVERLAY_STYLE = STATIONARY_OVERLAY_STYLE;
69254
69250
  exports.STORAGE_ACCESS_FALLBACK = STORAGE_ACCESS_FALLBACK;
@@ -69560,6 +69556,7 @@ exports.climateControlCapability = climateControlCapability;
69560
69556
  exports.clipExportFailure = clipExportFailure;
69561
69557
  exports.clipExportFailureOf = clipExportFailureOf;
69562
69558
  exports.clipReasonHeaderValue = clipReasonHeaderValue;
69559
+ exports.cloneStatefulExpressionMemory = require_composition.cloneStatefulExpressionMemory;
69563
69560
  exports.clusterModelSettingKey = clusterModelSettingKey;
69564
69561
  exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
69565
69562
  exports.clusterStepSettingKey = clusterStepSettingKey;
@@ -69578,6 +69575,7 @@ exports.composedDeviceRef = require_composition.composedDeviceRef;
69578
69575
  exports.composedDeviceStableId = require_composition.composedDeviceStableId;
69579
69576
  exports.composerCapability = composerCapability;
69580
69577
  exports.compositionEdges = compositionEdges;
69578
+ exports.compositionFeatureEnabled = require_composition.compositionFeatureEnabled;
69581
69579
  exports.compositionFieldKey = compositionFieldKey;
69582
69580
  exports.compositionItemFieldPath = require_composition.compositionItemFieldPath;
69583
69581
  exports.compositionReadKey = require_composition.compositionReadKey;
@@ -69614,6 +69612,7 @@ exports.createLogChannelsProvider = createLogChannelsProvider;
69614
69612
  exports.createMirrorSource = require_sleep.createMirrorSource;
69615
69613
  exports.createRuntimeStateBridge = createRuntimeStateBridge;
69616
69614
  exports.createSliceHandle = require_sleep.createSliceHandle;
69615
+ exports.createStatefulExpressionMemory = require_composition.createStatefulExpressionMemory;
69617
69616
  exports.createSystemProxy = createSystemProxy;
69618
69617
  exports.customAction = require_sleep.customAction;
69619
69618
  exports.customModelRegistryCapability = customModelRegistryCapability;
@@ -69680,9 +69679,13 @@ exports.enumerateSchemaFields = enumerateSchemaFields;
69680
69679
  exports.errMsg = require_err_msg.errMsg;
69681
69680
  exports.evaluateAst = require_composition.evaluateAst;
69682
69681
  exports.evaluateCompositionField = evaluateCompositionField;
69682
+ exports.evaluateCount = require_composition.evaluateCount;
69683
69683
  exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
69684
69684
  exports.evaluatePoolMemory = evaluatePoolMemory;
69685
- exports.evaluateSensorEdge = evaluateSensorEdge;
69685
+ exports.evaluateRose = require_composition.evaluateRose;
69686
+ exports.evaluateSensorEdge = require_composition.evaluateSensorEdge;
69687
+ exports.evaluateSensorLevelEdge = require_composition.evaluateSensorLevelEdge;
69688
+ exports.evaluateStatefulExpressionCall = require_composition.evaluateStatefulExpressionCall;
69686
69689
  exports.evaluateZoneRules = evaluateZoneRules;
69687
69690
  exports.event = require_sleep.event;
69688
69691
  exports.eventEmitterCapability = eventEmitterCapability;
@@ -69692,6 +69695,7 @@ exports.expandAudioChunkToF32le = require_sleep.expandAudioChunkToF32le;
69692
69695
  exports.expandCapMethods = require_sleep.expandCapMethods;
69693
69696
  exports.expandContainer = expandContainer;
69694
69697
  exports.exportSubjectOf = exportSubjectOf;
69698
+ exports.expressionContainsBuiltinCall = expressionContainsBuiltinCall;
69695
69699
  exports.extensionSlotRef = extensionSlotRef;
69696
69700
  exports.extractNestedAddonId = extractNestedAddonId;
69697
69701
  exports.extractSourceInfoFromMetadata = extractSourceInfoFromMetadata;
@@ -69771,7 +69775,8 @@ exports.isSameAddonId = isSameAddonId;
69771
69775
  exports.isScheduleActive = isScheduleActive;
69772
69776
  exports.isSecretConfigField = isSecretConfigField;
69773
69777
  exports.isSoftwareDecode = require_composition.isSoftwareDecode;
69774
- exports.isSourceCap = isSourceCap;
69778
+ exports.isSourceCap = require_composition.isSourceCap;
69779
+ exports.isStatefulBuiltin = require_composition.isStatefulBuiltin;
69775
69780
  exports.isStorageLocationMode = isStorageLocationMode;
69776
69781
  exports.isSystemDelivery = isSystemDelivery;
69777
69782
  exports.isSystemEventFamily = isSystemEventFamily;
@@ -69887,6 +69892,7 @@ exports.pipelineExecutorCapability = pipelineExecutorCapability;
69887
69892
  exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;
69888
69893
  exports.pipelineRunnerCapability = pipelineRunnerCapability;
69889
69894
  exports.planComposition = planComposition;
69895
+ exports.planCompositionEvents = planCompositionEvents;
69890
69896
  exports.planItems = planItems;
69891
69897
  exports.plateGalleryCapability = plateGalleryCapability;
69892
69898
  exports.platformProbeCapability = platformProbeCapability;
@@ -69986,8 +69992,8 @@ exports.signalPercentFromRssi = signalPercentFromRssi;
69986
69992
  exports.siteZoneKey = siteZoneKey;
69987
69993
  exports.sleep = require_sleep.sleep;
69988
69994
  exports.sleepCancellable = require_sleep.sleepCancellable;
69989
- exports.sliceActiveValue = sliceActiveValue;
69990
- exports.sliceChangedAt = sliceChangedAt;
69995
+ exports.sliceActiveValue = require_composition.sliceActiveValue;
69996
+ exports.sliceChangedAt = require_composition.sliceChangedAt;
69991
69997
  exports.smokeCapability = smokeCapability;
69992
69998
  exports.smtpProviderCapability = smtpProviderCapability;
69993
69999
  exports.snapshotCapability = snapshotCapability;