@camstack/types 1.2.268 → 1.2.269
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +3 -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 +321 -324
- package/dist/index.mjs +299 -314
- 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"
|
|
@@ -44506,7 +44541,7 @@ function createDeviceExtensionProvider(options) {
|
|
|
44506
44541
|
var CompositionGraphError = class extends Error {};
|
|
44507
44542
|
/** `"cap.field"` of every field a peer writes — the same spelling as `compositionFieldKey`. */
|
|
44508
44543
|
function writtenFields(peer) {
|
|
44509
|
-
return new Set(peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
|
|
44544
|
+
return new Set(peer.composition.features.flatMap((feature) => !require_composition.compositionFeatureEnabled(feature) || feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath }) => `${feature.cap}.${fieldPath}`)));
|
|
44510
44545
|
}
|
|
44511
44546
|
/** A read of the peer's OWN device is an edge only when it reads the peer's own output (rule 5, D663). */
|
|
44512
44547
|
function readsComposedValue(peer, written, read) {
|
|
@@ -44516,7 +44551,7 @@ function readsComposedValue(peer, written, read) {
|
|
|
44516
44551
|
}
|
|
44517
44552
|
function peerEdges(peer) {
|
|
44518
44553
|
const written = writtenFields(peer);
|
|
44519
|
-
return peer.composition.features.flatMap((feature) => feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
|
|
44554
|
+
return peer.composition.features.flatMap((feature) => !require_composition.compositionFeatureEnabled(feature) || feature.kind !== "fields" ? [] : require_composition.featureFieldEntries(feature).map(({ fieldPath, source }) => [require_composition.compositionReadKey({
|
|
44520
44555
|
source: peer.target,
|
|
44521
44556
|
cap: feature.cap,
|
|
44522
44557
|
fieldPath
|
|
@@ -44642,118 +44677,6 @@ function findCandidateCycles(candidate, stored) {
|
|
|
44642
44677
|
});
|
|
44643
44678
|
}
|
|
44644
44679
|
//#endregion
|
|
44645
|
-
//#region src/device/schema-fields.ts
|
|
44646
|
-
/** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
|
|
44647
|
-
* Zod v4 exposes `.unwrap()` on all three wrapper classes. */
|
|
44648
|
-
function unwrapSchema(schema) {
|
|
44649
|
-
let s = schema;
|
|
44650
|
-
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
44651
|
-
return s;
|
|
44652
|
-
}
|
|
44653
|
-
function leafKind(schema) {
|
|
44654
|
-
const s = unwrapSchema(schema);
|
|
44655
|
-
if (s instanceof zod.z.ZodEnum) return {
|
|
44656
|
-
kind: "enum",
|
|
44657
|
-
enumValues: s.options
|
|
44658
|
-
};
|
|
44659
|
-
if (s instanceof zod.z.ZodNumber) return { kind: "number" };
|
|
44660
|
-
if (s instanceof zod.z.ZodString) return { kind: "string" };
|
|
44661
|
-
if (s instanceof zod.z.ZodBoolean) return { kind: "boolean" };
|
|
44662
|
-
return null;
|
|
44663
|
-
}
|
|
44664
|
-
/** Walk a cap status schema into flat wireable leaf fields (dotted paths).
|
|
44665
|
-
* Recurses into nested ZodObject (unwrapping nullable/optional/default first),
|
|
44666
|
-
* so fields with null live values are still offered. Arrays / unknown shapes
|
|
44667
|
-
* are skipped — never throws. */
|
|
44668
|
-
function enumerateSchemaFields(schema, prefix = "") {
|
|
44669
|
-
const root = unwrapSchema(schema);
|
|
44670
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
44671
|
-
const out = [];
|
|
44672
|
-
const shape = root.shape;
|
|
44673
|
-
for (const [key, field] of Object.entries(shape)) {
|
|
44674
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
44675
|
-
const inner = unwrapSchema(field);
|
|
44676
|
-
if (inner instanceof zod.z.ZodObject) {
|
|
44677
|
-
out.push(...enumerateSchemaFields(inner, path));
|
|
44678
|
-
continue;
|
|
44679
|
-
}
|
|
44680
|
-
const leaf = leafKind(field);
|
|
44681
|
-
if (leaf) out.push({
|
|
44682
|
-
path,
|
|
44683
|
-
kind: leaf.kind,
|
|
44684
|
-
...leaf.enumValues ? { enumValues: leaf.enumValues } : {}
|
|
44685
|
-
});
|
|
44686
|
-
}
|
|
44687
|
-
return out;
|
|
44688
|
-
}
|
|
44689
|
-
/** Enumerate the per-item wireable fields of an item-array cap (see
|
|
44690
|
-
* `CapabilityStatusItemArray`): the item schema's leaf fields, minus the
|
|
44691
|
-
* `keyField` (the key comes from the link's `itemKey`, never from a wired
|
|
44692
|
-
* source), each tagged `item: true` so the authoring UI collects an
|
|
44693
|
-
* `itemKey` alongside the field. Never throws. */
|
|
44694
|
-
function enumerateItemArrayFields(itemArray) {
|
|
44695
|
-
return enumerateSchemaFields(itemArray.itemSchema).filter((f) => f.path !== itemArray.keyField).map((f) => ({
|
|
44696
|
-
...f,
|
|
44697
|
-
item: true
|
|
44698
|
-
}));
|
|
44699
|
-
}
|
|
44700
|
-
//#endregion
|
|
44701
|
-
//#region src/composition/state-fields.ts
|
|
44702
|
-
/**
|
|
44703
|
-
* What a capability's state field IS: kind, nullability, whether required. The
|
|
44704
|
-
* validator needs nullability, which `enumerateSchemaFields` does not report,
|
|
44705
|
-
* and that decides a field's unavailable mode (D393).
|
|
44706
|
-
*/
|
|
44707
|
-
function fieldAt(schema, path) {
|
|
44708
|
-
let current = schema;
|
|
44709
|
-
for (const segment of path.split(".")) {
|
|
44710
|
-
const container = unwrapSchema(current);
|
|
44711
|
-
if (!(container instanceof zod.z.ZodObject)) return null;
|
|
44712
|
-
const next = container.shape[segment];
|
|
44713
|
-
if (!(next instanceof zod.z.ZodType)) return null;
|
|
44714
|
-
current = next;
|
|
44715
|
-
}
|
|
44716
|
-
return current;
|
|
44717
|
-
}
|
|
44718
|
-
function describeStateField(schema, path) {
|
|
44719
|
-
const leaf = enumerateSchemaFields(schema).find((f) => f.path === path);
|
|
44720
|
-
if (leaf === void 0) return null;
|
|
44721
|
-
const field = fieldAt(schema, path);
|
|
44722
|
-
if (field === null) return null;
|
|
44723
|
-
return {
|
|
44724
|
-
path,
|
|
44725
|
-
kind: leaf.kind,
|
|
44726
|
-
nullable: field.safeParse(null).success,
|
|
44727
|
-
required: !field.safeParse(void 0).success,
|
|
44728
|
-
...leaf.enumValues === void 0 ? {} : { enumValues: leaf.enumValues }
|
|
44729
|
-
};
|
|
44730
|
-
}
|
|
44731
|
-
function describeTopLevelStateFields(schema) {
|
|
44732
|
-
return new Map(enumerateSchemaFields(schema).filter((f) => !f.path.includes(".")).flatMap((f) => {
|
|
44733
|
-
const described = describeStateField(schema, f.path);
|
|
44734
|
-
return described === null ? [] : [[f.path, described]];
|
|
44735
|
-
}));
|
|
44736
|
-
}
|
|
44737
|
-
/** Top-level keys a value MUST carry: those whose schema refuses `undefined`. */
|
|
44738
|
-
function requiredTopLevelKeys(schema) {
|
|
44739
|
-
const root = unwrapSchema(schema);
|
|
44740
|
-
if (!(root instanceof zod.z.ZodObject)) return [];
|
|
44741
|
-
return Object.entries(root.shape).flatMap(([key, field]) => field instanceof zod.z.ZodType && !field.safeParse(void 0).success ? [key] : []);
|
|
44742
|
-
}
|
|
44743
|
-
/**
|
|
44744
|
-
* The proper prefixes of `path` whose schema accepts `undefined`: a required
|
|
44745
|
-
* leaf under one of them is required only once something writes that parent
|
|
44746
|
-
* (`remaining.unit` is required only when `remaining` is present).
|
|
44747
|
-
*/
|
|
44748
|
-
function optionalAncestors(schema, path) {
|
|
44749
|
-
const segments = path.split(".");
|
|
44750
|
-
return segments.slice(0, -1).flatMap((_, i) => {
|
|
44751
|
-
const prefix = segments.slice(0, i + 1).join(".");
|
|
44752
|
-
const field = fieldAt(schema, prefix);
|
|
44753
|
-
return field !== null && field.safeParse(void 0).success ? [prefix] : [];
|
|
44754
|
-
});
|
|
44755
|
-
}
|
|
44756
|
-
//#endregion
|
|
44757
44680
|
//#region src/composition/plan-result.ts
|
|
44758
44681
|
function problem(code, path, message) {
|
|
44759
44682
|
return {
|
|
@@ -44766,7 +44689,8 @@ function refused(...problems) {
|
|
|
44766
44689
|
return {
|
|
44767
44690
|
problems,
|
|
44768
44691
|
fields: [],
|
|
44769
|
-
features: []
|
|
44692
|
+
features: [],
|
|
44693
|
+
events: []
|
|
44770
44694
|
};
|
|
44771
44695
|
}
|
|
44772
44696
|
/** Where a planned field sits in the composition: `features[N].fields.<path>` or `features[N].items.<key>.fields.<path>`. */
|
|
@@ -44810,7 +44734,12 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
|
|
|
44810
44734
|
number: {
|
|
44811
44735
|
kind: "fixed",
|
|
44812
44736
|
result: ["number", "null"]
|
|
44813
|
-
}
|
|
44737
|
+
},
|
|
44738
|
+
rose: {
|
|
44739
|
+
kind: "fixed",
|
|
44740
|
+
result: ["number", "null"]
|
|
44741
|
+
},
|
|
44742
|
+
count: NUMBER
|
|
44814
44743
|
});
|
|
44815
44744
|
var KindInferenceError = class extends Error {};
|
|
44816
44745
|
function kindOfValue(value) {
|
|
@@ -44869,6 +44798,21 @@ function kindsOf(node, bindings) {
|
|
|
44869
44798
|
case "call": return callKinds(node.callee, node.args.map((a) => kindsOf(a, bindings)));
|
|
44870
44799
|
}
|
|
44871
44800
|
}
|
|
44801
|
+
function nodeContainsCall(node, callee) {
|
|
44802
|
+
switch (node.kind) {
|
|
44803
|
+
case "literal":
|
|
44804
|
+
case "identifier": return false;
|
|
44805
|
+
case "unary": return nodeContainsCall(node.operand, callee);
|
|
44806
|
+
case "binary":
|
|
44807
|
+
case "logical": return nodeContainsCall(node.left, callee) || nodeContainsCall(node.right, callee);
|
|
44808
|
+
case "conditional": return nodeContainsCall(node.test, callee) || nodeContainsCall(node.consequent, callee) || nodeContainsCall(node.alternate, callee);
|
|
44809
|
+
case "call": return node.callee === callee || node.args.some((arg) => nodeContainsCall(arg, callee));
|
|
44810
|
+
}
|
|
44811
|
+
}
|
|
44812
|
+
function expressionContainsBuiltinCall(expr, callee) {
|
|
44813
|
+
const compiled = require_composition.compileExpressionSafe(expr);
|
|
44814
|
+
return compiled.ok && nodeContainsCall(compiled.parsed.ast, callee);
|
|
44815
|
+
}
|
|
44872
44816
|
function inferExpressionKinds(input) {
|
|
44873
44817
|
const compiled = require_composition.compileExpressionSafe(input.expr);
|
|
44874
44818
|
if (!compiled.ok) return {
|
|
@@ -44991,6 +44935,7 @@ function enumLiteralProblem(cap, target, source, at) {
|
|
|
44991
44935
|
}
|
|
44992
44936
|
function roleOf(source) {
|
|
44993
44937
|
if (source.kind !== "expression") return "derived";
|
|
44938
|
+
if (expressionContainsBuiltinCall(source.expr, "count")) return "accumulator";
|
|
44994
44939
|
if (require_composition.fieldReads(source).length > 0) return "derived";
|
|
44995
44940
|
const compiled = require_composition.compileExpressionSafe(source.expr);
|
|
44996
44941
|
return compiled.ok && compiled.parsed.identifiers.has("now") ? "clock" : "constant";
|
|
@@ -45002,13 +44947,13 @@ function roleOf(source) {
|
|
|
45002
44947
|
* field that READS a source never gets `offline`.
|
|
45003
44948
|
*/
|
|
45004
44949
|
function unavailableFor(tf, role, mode, cap, at) {
|
|
45005
|
-
if (mode === "
|
|
44950
|
+
if (mode === "replace" && (role === "derived" || role === "accumulator")) return {
|
|
45006
44951
|
ok: true,
|
|
45007
|
-
unavailable:
|
|
44952
|
+
unavailable: "release"
|
|
45008
44953
|
};
|
|
45009
|
-
if (mode === "
|
|
44954
|
+
if (mode === "new" || role !== "derived") return {
|
|
45010
44955
|
ok: true,
|
|
45011
|
-
unavailable: "
|
|
44956
|
+
unavailable: tf.nullable ? "null" : "offline"
|
|
45012
44957
|
};
|
|
45013
44958
|
if (tf.nullable) return {
|
|
45014
44959
|
ok: true,
|
|
@@ -45083,7 +45028,8 @@ function planItemField(ctx, leaf) {
|
|
|
45083
45028
|
return {
|
|
45084
45029
|
problems: [...compatibility(capName, tf, kinds.kinds, at), ...enumProblem === null ? [] : [enumProblem]],
|
|
45085
45030
|
fields: [plan],
|
|
45086
|
-
features: []
|
|
45031
|
+
features: [],
|
|
45032
|
+
events: []
|
|
45087
45033
|
};
|
|
45088
45034
|
}
|
|
45089
45035
|
function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
@@ -45102,7 +45048,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
|
45102
45048
|
const results = Object.entries(feature.items ?? {}).flatMap(([key, item]) => [{
|
|
45103
45049
|
problems: missingLeaves(ctx, item, `${at}.${key}`),
|
|
45104
45050
|
fields: [],
|
|
45105
|
-
features: []
|
|
45051
|
+
features: [],
|
|
45052
|
+
events: []
|
|
45106
45053
|
}, ...Object.entries(item.fields).map(([path, source]) => planItemField(ctx, {
|
|
45107
45054
|
key,
|
|
45108
45055
|
label: item.label,
|
|
@@ -45112,7 +45059,8 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
|
45112
45059
|
return {
|
|
45113
45060
|
problems: results.flatMap((r) => r.problems),
|
|
45114
45061
|
fields: results.flatMap((r) => r.fields),
|
|
45115
|
-
features: []
|
|
45062
|
+
features: [],
|
|
45063
|
+
events: []
|
|
45116
45064
|
};
|
|
45117
45065
|
}
|
|
45118
45066
|
//#endregion
|
|
@@ -45138,7 +45086,7 @@ function fromReading(reading, read) {
|
|
|
45138
45086
|
deadline: null
|
|
45139
45087
|
};
|
|
45140
45088
|
}
|
|
45141
|
-
function expressionOutcome(source, read, now) {
|
|
45089
|
+
function expressionOutcome(source, read, now, stateful) {
|
|
45142
45090
|
const values = {};
|
|
45143
45091
|
const staleReasons = [];
|
|
45144
45092
|
let fatalUnavailable = null;
|
|
@@ -45167,10 +45115,31 @@ function expressionOutcome(source, read, now) {
|
|
|
45167
45115
|
values[name] = reading.value;
|
|
45168
45116
|
if (reading.state === "stale") staleReasons.push(`\`${name}\`: ${reading.reason}`);
|
|
45169
45117
|
}
|
|
45170
|
-
|
|
45171
|
-
if (
|
|
45118
|
+
const unavailable = fatalUnavailable ?? nonFatalUnavailable;
|
|
45119
|
+
if (unavailable !== null) {
|
|
45120
|
+
if (stateful !== void 0 && stateful.currentOutput !== void 0 && expressionContainsBuiltinCall(source.expr, "count")) return {
|
|
45121
|
+
state: "stale",
|
|
45122
|
+
value: require_composition.evaluateCount(null, {
|
|
45123
|
+
kind: "count",
|
|
45124
|
+
highWater: null
|
|
45125
|
+
}, stateful.currentOutput),
|
|
45126
|
+
reason: `${unavailable.reason}; holding the last accumulator value`,
|
|
45127
|
+
deadline: null
|
|
45128
|
+
};
|
|
45129
|
+
return unavailable;
|
|
45130
|
+
}
|
|
45172
45131
|
const deadlines = [];
|
|
45173
|
-
const result = require_composition.evaluateExpressionSource(source.expr, values, now, {
|
|
45132
|
+
const result = require_composition.evaluateExpressionSource(source.expr, values, now, {
|
|
45133
|
+
hooks: { noteDeadline: (at) => deadlines.push(at) },
|
|
45134
|
+
...stateful === void 0 ? {} : { invokeStateful: (invocation) => require_composition.evaluateStatefulExpressionCall(stateful.callPathPrefix === void 0 ? invocation : {
|
|
45135
|
+
...invocation,
|
|
45136
|
+
path: `${stateful.callPathPrefix}@${invocation.path}`
|
|
45137
|
+
}, stateful.expressionMemory, {
|
|
45138
|
+
currentOutput: stateful.currentOutput,
|
|
45139
|
+
startedAtMs: stateful.startedAtMs,
|
|
45140
|
+
nowMs: now
|
|
45141
|
+
}) }
|
|
45142
|
+
});
|
|
45174
45143
|
if (!result.ok) return {
|
|
45175
45144
|
state: "unavailable",
|
|
45176
45145
|
value: null,
|
|
@@ -45189,7 +45158,7 @@ function evaluateCompositionField(input) {
|
|
|
45189
45158
|
const { source } = input;
|
|
45190
45159
|
switch (source.kind) {
|
|
45191
45160
|
case "from": return fromReading(input.read(source), source);
|
|
45192
|
-
case "expression": return expressionOutcome(source, input.read, input.now);
|
|
45161
|
+
case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
|
|
45193
45162
|
case "code": return {
|
|
45194
45163
|
state: "unavailable",
|
|
45195
45164
|
value: null,
|
|
@@ -45471,7 +45440,8 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
|
|
|
45471
45440
|
return {
|
|
45472
45441
|
problems: [...compatibility(def.name, tf, kinds.kinds, fieldAt), ...enumProblem === null ? [] : [enumProblem]],
|
|
45473
45442
|
fields: [plan],
|
|
45474
|
-
features: []
|
|
45443
|
+
features: [],
|
|
45444
|
+
events: []
|
|
45475
45445
|
};
|
|
45476
45446
|
}
|
|
45477
45447
|
function planFeature(feature, featureIndex, target, lookupCap) {
|
|
@@ -45487,14 +45457,22 @@ function planFeature(feature, featureIndex, target, lookupCap) {
|
|
|
45487
45457
|
}, target.mode, lookupCap));
|
|
45488
45458
|
const items = feature.items === void 0 ? [] : [planItems(cap.def, feature, featureIndex, lookupCap, target.mode)];
|
|
45489
45459
|
const all = [...perField, ...items];
|
|
45460
|
+
const fields = all.flatMap((result) => result.fields);
|
|
45461
|
+
const featurePlan = {
|
|
45462
|
+
featureIndex,
|
|
45463
|
+
cap: cap.def.name,
|
|
45464
|
+
mode: target.mode
|
|
45465
|
+
};
|
|
45466
|
+
const eventPlan = planCompositionEvents(cap.def, featurePlan, fields);
|
|
45490
45467
|
return {
|
|
45491
|
-
problems: [
|
|
45492
|
-
|
|
45493
|
-
|
|
45494
|
-
|
|
45495
|
-
|
|
45496
|
-
|
|
45497
|
-
|
|
45468
|
+
problems: [
|
|
45469
|
+
...capProblems,
|
|
45470
|
+
...all.flatMap((r) => r.problems),
|
|
45471
|
+
...eventPlan.problems
|
|
45472
|
+
],
|
|
45473
|
+
fields,
|
|
45474
|
+
features: [featurePlan],
|
|
45475
|
+
events: eventPlan.events
|
|
45498
45476
|
};
|
|
45499
45477
|
}
|
|
45500
45478
|
/** A cap the device serves itself; one the composer grafted (an earlier ADD) is not native. */
|
|
@@ -45536,17 +45514,23 @@ function planComposition(composition, lookupCap, target) {
|
|
|
45536
45514
|
const planTarget = planTargetOf(composition, target);
|
|
45537
45515
|
if ("code" in planTarget) return refused(planTarget);
|
|
45538
45516
|
const results = composition.features.map((feature, index) => {
|
|
45539
|
-
|
|
45540
|
-
return
|
|
45517
|
+
const result = feature.kind === "passthrough" ? refused(problem("reserved-variant", `features[${index}]`, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`)) : planFeature(feature, index, featureTargetOf(planTarget, feature.cap), lookupCap);
|
|
45518
|
+
return require_composition.compositionFeatureEnabled(feature) ? result : {
|
|
45519
|
+
problems: result.problems,
|
|
45520
|
+
fields: [],
|
|
45521
|
+
features: [],
|
|
45522
|
+
events: []
|
|
45523
|
+
};
|
|
45541
45524
|
});
|
|
45542
45525
|
return {
|
|
45543
45526
|
problems: results.flatMap((r) => r.problems),
|
|
45544
45527
|
fields: results.flatMap((r) => r.fields),
|
|
45545
|
-
features: results.flatMap((r) => r.features)
|
|
45528
|
+
features: results.flatMap((r) => r.features),
|
|
45529
|
+
events: results.flatMap((r) => r.events)
|
|
45546
45530
|
};
|
|
45547
45531
|
}
|
|
45548
45532
|
function compositionSourceRefs(composition) {
|
|
45549
|
-
const refs = composition.features.flatMap((f) => f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
|
|
45533
|
+
const refs = composition.features.flatMap((f) => require_composition.compositionFeatureEnabled(f) && f.kind === "fields" ? require_composition.featureSources(f).flatMap(require_composition.fieldReads).map((r) => r.source) : []);
|
|
45550
45534
|
return [...new Map(refs.map((r) => [require_composition.compositionSourceKey(r), r])).values()];
|
|
45551
45535
|
}
|
|
45552
45536
|
/**
|
|
@@ -45681,7 +45665,8 @@ function validateComposition(composition, ctx) {
|
|
|
45681
45665
|
ok: problems.length === 0,
|
|
45682
45666
|
problems,
|
|
45683
45667
|
fields: [...plan.fields],
|
|
45684
|
-
features: [...plan.features]
|
|
45668
|
+
features: [...plan.features],
|
|
45669
|
+
events: [...plan.events]
|
|
45685
45670
|
};
|
|
45686
45671
|
}
|
|
45687
45672
|
//#endregion
|
|
@@ -64185,7 +64170,7 @@ var NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = "This rule belongs to the alarm,
|
|
|
64185
64170
|
*/
|
|
64186
64171
|
/** Event kind → the boolean field of its cap slice that means "raised". */
|
|
64187
64172
|
var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
|
|
64188
|
-
const field = SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
64173
|
+
const field = require_composition.SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
64189
64174
|
if (field === void 0 || descriptor.category !== "sensor") return [];
|
|
64190
64175
|
return [[descriptor.kind, field]];
|
|
64191
64176
|
})));
|
|
@@ -68287,6 +68272,7 @@ exports.COMPOSED_DEVICE_STABLE_ID_PREFIX = require_composition.COMPOSED_DEVICE_S
|
|
|
68287
68272
|
exports.COMPOSED_ITEM_FIXED_FIELDS = COMPOSED_ITEM_FIXED_FIELDS;
|
|
68288
68273
|
exports.COMPOSER_ADDON_ID = require_composition.COMPOSER_ADDON_ID;
|
|
68289
68274
|
exports.COMPOSER_RUNNER_ID = COMPOSER_RUNNER_ID;
|
|
68275
|
+
exports.COMPOSITION_EVENT_CATEGORY = COMPOSITION_EVENT_CATEGORY;
|
|
68290
68276
|
exports.COMPOSITION_ITEM_ARRAY_PATH = require_composition.COMPOSITION_ITEM_ARRAY_PATH;
|
|
68291
68277
|
exports.COMPOSITION_ITEM_KEY_RE = require_composition.COMPOSITION_ITEM_KEY_RE;
|
|
68292
68278
|
exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
|
|
@@ -68371,6 +68357,7 @@ exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
|
|
|
68371
68357
|
exports.CompositionCodeSourceSchema = require_composition.CompositionCodeSourceSchema;
|
|
68372
68358
|
exports.CompositionCommandTargetSchema = require_composition.CompositionCommandTargetSchema;
|
|
68373
68359
|
exports.CompositionCustomizationReadSchema = CompositionCustomizationReadSchema;
|
|
68360
|
+
exports.CompositionEventPlanSchema = CompositionEventPlanSchema;
|
|
68374
68361
|
exports.CompositionExistingTargetSchema = require_composition.CompositionExistingTargetSchema;
|
|
68375
68362
|
exports.CompositionExpressionSourceSchema = require_composition.CompositionExpressionSourceSchema;
|
|
68376
68363
|
exports.CompositionFeatureModeSchema = CompositionFeatureModeSchema;
|
|
@@ -68451,7 +68438,7 @@ exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
|
|
|
68451
68438
|
exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
|
|
68452
68439
|
exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
|
|
68453
68440
|
exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
|
|
68454
|
-
exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
|
|
68441
|
+
exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = require_composition.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
|
|
68455
68442
|
exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
|
|
68456
68443
|
exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
|
|
68457
68444
|
exports.DEFAULT_OVERLAY_LAYERS = DEFAULT_OVERLAY_LAYERS;
|
|
@@ -69245,10 +69232,10 @@ exports.SCOPE_PRESETS = SCOPE_PRESETS;
|
|
|
69245
69232
|
exports.SENSOR_FEATURES = SENSOR_FEATURES;
|
|
69246
69233
|
exports.SENSOR_MAP = SENSOR_MAP;
|
|
69247
69234
|
exports.SHARE_VIEW_KINDS = require_sleep.SHARE_VIEW_KINDS;
|
|
69248
|
-
exports.SOURCE_CAPS = SOURCE_CAPS;
|
|
69249
|
-
exports.SOURCE_CAP_ACTIVE_FIELD = SOURCE_CAP_ACTIVE_FIELD;
|
|
69250
|
-
exports.SOURCE_CAP_CHANGED_AT_FIELD = SOURCE_CAP_CHANGED_AT_FIELD;
|
|
69251
|
-
exports.SOURCE_DEVICE_TYPES = SOURCE_DEVICE_TYPES;
|
|
69235
|
+
exports.SOURCE_CAPS = require_composition.SOURCE_CAPS;
|
|
69236
|
+
exports.SOURCE_CAP_ACTIVE_FIELD = require_composition.SOURCE_CAP_ACTIVE_FIELD;
|
|
69237
|
+
exports.SOURCE_CAP_CHANGED_AT_FIELD = require_composition.SOURCE_CAP_CHANGED_AT_FIELD;
|
|
69238
|
+
exports.SOURCE_DEVICE_TYPES = require_composition.SOURCE_DEVICE_TYPES;
|
|
69252
69239
|
exports.SOURCE_INFO_METADATA_KEY = SOURCE_INFO_METADATA_KEY;
|
|
69253
69240
|
exports.STATIONARY_OVERLAY_STYLE = STATIONARY_OVERLAY_STYLE;
|
|
69254
69241
|
exports.STORAGE_ACCESS_FALLBACK = STORAGE_ACCESS_FALLBACK;
|
|
@@ -69560,6 +69547,7 @@ exports.climateControlCapability = climateControlCapability;
|
|
|
69560
69547
|
exports.clipExportFailure = clipExportFailure;
|
|
69561
69548
|
exports.clipExportFailureOf = clipExportFailureOf;
|
|
69562
69549
|
exports.clipReasonHeaderValue = clipReasonHeaderValue;
|
|
69550
|
+
exports.cloneStatefulExpressionMemory = require_composition.cloneStatefulExpressionMemory;
|
|
69563
69551
|
exports.clusterModelSettingKey = clusterModelSettingKey;
|
|
69564
69552
|
exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
|
|
69565
69553
|
exports.clusterStepSettingKey = clusterStepSettingKey;
|
|
@@ -69578,6 +69566,7 @@ exports.composedDeviceRef = require_composition.composedDeviceRef;
|
|
|
69578
69566
|
exports.composedDeviceStableId = require_composition.composedDeviceStableId;
|
|
69579
69567
|
exports.composerCapability = composerCapability;
|
|
69580
69568
|
exports.compositionEdges = compositionEdges;
|
|
69569
|
+
exports.compositionFeatureEnabled = require_composition.compositionFeatureEnabled;
|
|
69581
69570
|
exports.compositionFieldKey = compositionFieldKey;
|
|
69582
69571
|
exports.compositionItemFieldPath = require_composition.compositionItemFieldPath;
|
|
69583
69572
|
exports.compositionReadKey = require_composition.compositionReadKey;
|
|
@@ -69614,6 +69603,7 @@ exports.createLogChannelsProvider = createLogChannelsProvider;
|
|
|
69614
69603
|
exports.createMirrorSource = require_sleep.createMirrorSource;
|
|
69615
69604
|
exports.createRuntimeStateBridge = createRuntimeStateBridge;
|
|
69616
69605
|
exports.createSliceHandle = require_sleep.createSliceHandle;
|
|
69606
|
+
exports.createStatefulExpressionMemory = require_composition.createStatefulExpressionMemory;
|
|
69617
69607
|
exports.createSystemProxy = createSystemProxy;
|
|
69618
69608
|
exports.customAction = require_sleep.customAction;
|
|
69619
69609
|
exports.customModelRegistryCapability = customModelRegistryCapability;
|
|
@@ -69680,9 +69670,13 @@ exports.enumerateSchemaFields = enumerateSchemaFields;
|
|
|
69680
69670
|
exports.errMsg = require_err_msg.errMsg;
|
|
69681
69671
|
exports.evaluateAst = require_composition.evaluateAst;
|
|
69682
69672
|
exports.evaluateCompositionField = evaluateCompositionField;
|
|
69673
|
+
exports.evaluateCount = require_composition.evaluateCount;
|
|
69683
69674
|
exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
|
|
69684
69675
|
exports.evaluatePoolMemory = evaluatePoolMemory;
|
|
69685
|
-
exports.
|
|
69676
|
+
exports.evaluateRose = require_composition.evaluateRose;
|
|
69677
|
+
exports.evaluateSensorEdge = require_composition.evaluateSensorEdge;
|
|
69678
|
+
exports.evaluateSensorLevelEdge = require_composition.evaluateSensorLevelEdge;
|
|
69679
|
+
exports.evaluateStatefulExpressionCall = require_composition.evaluateStatefulExpressionCall;
|
|
69686
69680
|
exports.evaluateZoneRules = evaluateZoneRules;
|
|
69687
69681
|
exports.event = require_sleep.event;
|
|
69688
69682
|
exports.eventEmitterCapability = eventEmitterCapability;
|
|
@@ -69692,6 +69686,7 @@ exports.expandAudioChunkToF32le = require_sleep.expandAudioChunkToF32le;
|
|
|
69692
69686
|
exports.expandCapMethods = require_sleep.expandCapMethods;
|
|
69693
69687
|
exports.expandContainer = expandContainer;
|
|
69694
69688
|
exports.exportSubjectOf = exportSubjectOf;
|
|
69689
|
+
exports.expressionContainsBuiltinCall = expressionContainsBuiltinCall;
|
|
69695
69690
|
exports.extensionSlotRef = extensionSlotRef;
|
|
69696
69691
|
exports.extractNestedAddonId = extractNestedAddonId;
|
|
69697
69692
|
exports.extractSourceInfoFromMetadata = extractSourceInfoFromMetadata;
|
|
@@ -69771,7 +69766,8 @@ exports.isSameAddonId = isSameAddonId;
|
|
|
69771
69766
|
exports.isScheduleActive = isScheduleActive;
|
|
69772
69767
|
exports.isSecretConfigField = isSecretConfigField;
|
|
69773
69768
|
exports.isSoftwareDecode = require_composition.isSoftwareDecode;
|
|
69774
|
-
exports.isSourceCap = isSourceCap;
|
|
69769
|
+
exports.isSourceCap = require_composition.isSourceCap;
|
|
69770
|
+
exports.isStatefulBuiltin = require_composition.isStatefulBuiltin;
|
|
69775
69771
|
exports.isStorageLocationMode = isStorageLocationMode;
|
|
69776
69772
|
exports.isSystemDelivery = isSystemDelivery;
|
|
69777
69773
|
exports.isSystemEventFamily = isSystemEventFamily;
|
|
@@ -69887,6 +69883,7 @@ exports.pipelineExecutorCapability = pipelineExecutorCapability;
|
|
|
69887
69883
|
exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;
|
|
69888
69884
|
exports.pipelineRunnerCapability = pipelineRunnerCapability;
|
|
69889
69885
|
exports.planComposition = planComposition;
|
|
69886
|
+
exports.planCompositionEvents = planCompositionEvents;
|
|
69890
69887
|
exports.planItems = planItems;
|
|
69891
69888
|
exports.plateGalleryCapability = plateGalleryCapability;
|
|
69892
69889
|
exports.platformProbeCapability = platformProbeCapability;
|
|
@@ -69986,8 +69983,8 @@ exports.signalPercentFromRssi = signalPercentFromRssi;
|
|
|
69986
69983
|
exports.siteZoneKey = siteZoneKey;
|
|
69987
69984
|
exports.sleep = require_sleep.sleep;
|
|
69988
69985
|
exports.sleepCancellable = require_sleep.sleepCancellable;
|
|
69989
|
-
exports.sliceActiveValue = sliceActiveValue;
|
|
69990
|
-
exports.sliceChangedAt = sliceChangedAt;
|
|
69986
|
+
exports.sliceActiveValue = require_composition.sliceActiveValue;
|
|
69987
|
+
exports.sliceChangedAt = require_composition.sliceChangedAt;
|
|
69991
69988
|
exports.smokeCapability = smokeCapability;
|
|
69992
69989
|
exports.smtpProviderCapability = smtpProviderCapability;
|
|
69993
69990
|
exports.snapshotCapability = snapshotCapability;
|