@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.
- package/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/capabilities/capability-definition.d.ts +8 -1
- package/dist/capabilities/composer.cap.d.ts +6 -0
- package/dist/capabilities/core-blocks.cap.d.ts +54 -3
- package/dist/capabilities/device-manager.cap.d.ts +4 -4
- package/dist/capabilities/doorbell.cap.d.ts +4 -0
- package/dist/capabilities/media-player.cap.d.ts +4 -4
- package/dist/capabilities/recording-archive.cap.d.ts +5 -3
- package/dist/catalogs/sensor-active-state.d.ts +25 -1
- package/dist/composition/composition-events.d.ts +42 -0
- package/dist/composition/composition-report.d.ts +22 -10
- package/dist/composition/composition.d.ts +8 -0
- package/dist/composition/evaluate-field.d.ts +8 -0
- package/dist/composition/expression-kinds.d.ts +1 -0
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/plan-result.d.ts +2 -0
- package/dist/{composition-QlOB7QTG.js → composition-BAH3n-zq.js} +412 -14
- package/dist/{composition-CPFIlFfw.mjs → composition-D5BQywfe.mjs} +311 -15
- package/dist/expression/ast.d.ts +2 -0
- package/dist/expression/builtins.d.ts +9 -0
- package/dist/expression/evaluator.d.ts +8 -2
- package/dist/expression/expression-source.d.ts +26 -4
- package/dist/expression/index.d.ts +6 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +335 -329
- package/dist/index.mjs +313 -319
- package/dist/interfaces/recording-config.d.ts +3 -3
- package/dist/node.js +1 -1
- package/dist/node.mjs +1 -1
- package/dist/{sleep-BSzia-xT.js → sleep-Bg0IB7gg.js} +4 -15
- package/dist/{sleep-jkRQgtSc.mjs → sleep-E6eD4yQS.mjs} +4 -15
- 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-
|
|
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-
|
|
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: {
|
|
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:
|
|
39631
|
-
*
|
|
39632
|
-
*
|
|
39633
|
-
*
|
|
39634
|
-
*
|
|
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 === "
|
|
44959
|
+
if (mode === "replace" && (role === "derived" || role === "accumulator")) return {
|
|
45006
44960
|
ok: true,
|
|
45007
|
-
unavailable:
|
|
44961
|
+
unavailable: "release"
|
|
45008
44962
|
};
|
|
45009
|
-
if (mode === "
|
|
44963
|
+
if (mode === "new" || role !== "derived") return {
|
|
45010
44964
|
ok: true,
|
|
45011
|
-
unavailable: "
|
|
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
|
-
|
|
45171
|
-
if (
|
|
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, {
|
|
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: [
|
|
45492
|
-
|
|
45493
|
-
|
|
45494
|
-
|
|
45495
|
-
|
|
45496
|
-
|
|
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
|
-
|
|
45540
|
-
return
|
|
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.
|
|
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;
|