@camstack/addon-pipeline 1.1.24 → 1.1.26
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/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/audio-codec-ffmpeg/index.js +1 -1
- package/dist/audio-codec-ffmpeg/index.mjs +1 -1
- package/dist/decoder-ffmpeg/index.js +84 -12
- package/dist/decoder-ffmpeg/index.mjs +84 -12
- package/dist/detection-pipeline/index.js +149 -27
- package/dist/detection-pipeline/index.mjs +149 -27
- package/dist/{dist-pd_-3C0T.mjs → dist-CgEP_0OL.mjs} +794 -16
- package/dist/{dist-CE3a05qT.js → dist-DAIlCdAx.js} +799 -15
- package/dist/frame-handle-plane-Dq20KtKL.mjs +636 -0
- package/dist/frame-handle-plane-DtTRX_0n.js +647 -0
- package/dist/hub-hostname-DAJXlOgV.js +54 -0
- package/dist/hub-hostname-cCknRYKj.mjs +49 -0
- package/dist/{model-download-service-C-IHWnXx-BnQ_awK4.js → model-download-service-C-IHWnXx-DxM2DSns.js} +1 -2
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +341 -17
- package/dist/pipeline-runner/index.mjs +341 -17
- package/dist/recorder/index.js +267 -65
- package/dist/recorder/index.mjs +267 -65
- package/dist/stream-broker/_stub.js +39 -39
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BVFAEkIB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-5tQlh9h4.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CkOPfV8r.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BJK0-svt.mjs +26 -0
- package/dist/stream-broker/{hostInit-DHej3Ep9.mjs → hostInit-DyLqyJaS.mjs} +2 -2
- package/dist/stream-broker/index.js +7 -639
- package/dist/stream-broker/index.mjs +5 -637
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-BqXU75it.js → MaskShapeCanvas-DI4BY7W2-BDLNwJ_F.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-Ct2fpgCd.js → MotionZonesSettings-NcxxQN8r-CoLjNiUN.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-a9eFVPPl.js → PrivacyMaskSettings-APgPLF7p-DJE3OU-q.js} +1 -1
- package/embed-dist/assets/index-C-pL8ETk.js +81 -0
- package/embed-dist/assets/index-DrJ0ee3f.css +2 -0
- package/embed-dist/index.html +2 -2
- package/package.json +1 -1
- package/python/inference_pool.py +522 -27
- package/python/test_inference_pool_backpressure.py +121 -0
- package/python/test_inference_pool_coreml_cache.py +416 -0
- package/python/test_inference_pool_device_selection.py +256 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BFeBlYRQ.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BC1Jt6G8.mjs +0 -26
- package/embed-dist/assets/index-C7SSikPl.css +0 -2
- package/embed-dist/assets/index-DhdVxWXL.js +0 -80
- package/dist/{model-download-service-C-IHWnXx-3Mmeob3l.mjs → model-download-service-C-IHWnXx-BPy6aoAx.mjs} +1 -1
|
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4627
4627
|
return inst;
|
|
4628
4628
|
}
|
|
4629
4629
|
//#endregion
|
|
4630
|
-
//#region ../types/dist/sleep-
|
|
4630
|
+
//#region ../types/dist/sleep-BO1nweKv.mjs
|
|
4631
4631
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4632
4632
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4633
4633
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -6923,6 +6923,25 @@ var ConvertResultSchema = object({
|
|
|
6923
6923
|
})).readonly()
|
|
6924
6924
|
});
|
|
6925
6925
|
/**
|
|
6926
|
+
* THE canonical event-clip pad: the time window a single-timestamp analytics
|
|
6927
|
+
* event expands to when joined with footage (clip window = `[timestamp - preMs,
|
|
6928
|
+
* timestamp + postMs]`). Matches the admin-ui clip window (−5s/+10s).
|
|
6929
|
+
*
|
|
6930
|
+
* Every consumer derives from this ONE constant so event↔footage boundaries
|
|
6931
|
+
* agree everywhere (C1):
|
|
6932
|
+
* - the `videoclips` default provider (addon-post-analysis) pads its clip
|
|
6933
|
+
* windows with it;
|
|
6934
|
+
* - the recorder's ephemeral in-RAM `EventMap` markers (addon-pipeline) pad
|
|
6935
|
+
* their `startMs/endMs` with it.
|
|
6936
|
+
*
|
|
6937
|
+
* NOTE: this is a UI/JOIN convention, NOT the `events`-band keep/discard gate —
|
|
6938
|
+
* that uses the per-device `preBufferSec`/`postBufferSec` config.
|
|
6939
|
+
*/
|
|
6940
|
+
var EVENT_PAD_MS = {
|
|
6941
|
+
preMs: 5e3,
|
|
6942
|
+
postMs: 1e4
|
|
6943
|
+
};
|
|
6944
|
+
/**
|
|
6926
6945
|
* Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
|
|
6927
6946
|
* Named `RecordingWeekday` to avoid collision with the string-union
|
|
6928
6947
|
* `Weekday` exported from `interfaces/timezones.ts`.
|
|
@@ -8113,6 +8132,601 @@ function mapAudioLabelToMacro(label) {
|
|
|
8113
8132
|
return _macroLookup.get(label.toLowerCase()) ?? null;
|
|
8114
8133
|
}
|
|
8115
8134
|
/**
|
|
8135
|
+
* Error types for the safe expression engine. Two distinct classes so callers
|
|
8136
|
+
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
8137
|
+
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
8138
|
+
*/
|
|
8139
|
+
/** Thrown by the tokenizer / parser. Carries a 0-based source `position` when
|
|
8140
|
+
* the failure is anchored to a character (author-facing inline feedback). */
|
|
8141
|
+
var ExpressionParseError = class extends Error {
|
|
8142
|
+
position;
|
|
8143
|
+
constructor(message, position) {
|
|
8144
|
+
super(message);
|
|
8145
|
+
this.name = "ExpressionParseError";
|
|
8146
|
+
this.position = position;
|
|
8147
|
+
}
|
|
8148
|
+
};
|
|
8149
|
+
/** Thrown by the evaluator (unknown identifier, type mismatch, non-finite
|
|
8150
|
+
* result, unknown builtin, step-budget exceeded). */
|
|
8151
|
+
var ExpressionEvalError = class extends Error {
|
|
8152
|
+
constructor(message) {
|
|
8153
|
+
super(message);
|
|
8154
|
+
this.name = "ExpressionEvalError";
|
|
8155
|
+
}
|
|
8156
|
+
};
|
|
8157
|
+
/**
|
|
8158
|
+
* Resource-bound constants for the safe expression engine.
|
|
8159
|
+
*
|
|
8160
|
+
* Every bound is defense-in-depth: the grammar is non-Turing-complete (no
|
|
8161
|
+
* loops, recursion, lambdas or member access — see `ast.ts`), so evaluation is
|
|
8162
|
+
* O(nodeCount) by construction. These caps merely put a hard ceiling on the
|
|
8163
|
+
* work a single author-supplied expression can request, so a hostile or
|
|
8164
|
+
* accidental pathological string can never spend unbounded CPU/memory.
|
|
8165
|
+
*/
|
|
8166
|
+
/** Max source length (chars) — checked BEFORE tokenizing so a huge string is
|
|
8167
|
+
* rejected without allocation. */
|
|
8168
|
+
var MAX_EXPRESSION_SOURCE_LENGTH = 2048;
|
|
8169
|
+
/** A legal binding / identifier name. */
|
|
8170
|
+
var EXPRESSION_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8171
|
+
/** Binding names an author may NOT use: `now` is auto-injected; the literal
|
|
8172
|
+
* keywords lex as values, not identifiers, so binding to them is meaningless. */
|
|
8173
|
+
var RESERVED_BINDING_NAMES = new Set([
|
|
8174
|
+
"now",
|
|
8175
|
+
"true",
|
|
8176
|
+
"false",
|
|
8177
|
+
"null"
|
|
8178
|
+
]);
|
|
8179
|
+
/**
|
|
8180
|
+
* Tokenizer for the safe expression mini-language. Hand-rolled, single-pass,
|
|
8181
|
+
* zero-dependency. The grammar is deliberately boring: decimal numbers,
|
|
8182
|
+
* single/double-quoted strings with a tiny escape set, identifiers, the three
|
|
8183
|
+
* value keywords (`true`/`false`/`null`) and a fixed punctuator set. Anything
|
|
8184
|
+
* outside that — a bare `.`, `=`, `[`, `]`, `{`, `}`, `;`, backtick, `&`, `|` —
|
|
8185
|
+
* is a parse error with a source position, so member access / assignment /
|
|
8186
|
+
* template literals are lexically impossible.
|
|
8187
|
+
*/
|
|
8188
|
+
var KEYWORDS = new Set([
|
|
8189
|
+
"true",
|
|
8190
|
+
"false",
|
|
8191
|
+
"null"
|
|
8192
|
+
]);
|
|
8193
|
+
function isDigit(ch) {
|
|
8194
|
+
return ch >= "0" && ch <= "9";
|
|
8195
|
+
}
|
|
8196
|
+
function isIdentStart(ch) {
|
|
8197
|
+
return ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z" || ch === "_";
|
|
8198
|
+
}
|
|
8199
|
+
function isIdentPart(ch) {
|
|
8200
|
+
return isIdentStart(ch) || isDigit(ch);
|
|
8201
|
+
}
|
|
8202
|
+
function isWhitespace(ch) {
|
|
8203
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
|
|
8204
|
+
}
|
|
8205
|
+
/** Tokenize `source` into a flat token list ending with a single `eof` token.
|
|
8206
|
+
* Throws `ExpressionParseError` on any illegal character or unterminated
|
|
8207
|
+
* string. */
|
|
8208
|
+
function tokenize(source) {
|
|
8209
|
+
if (source.length > 2048) throw new ExpressionParseError(`expression too long (${source.length} > ${MAX_EXPRESSION_SOURCE_LENGTH} chars)`, 0);
|
|
8210
|
+
const tokens = [];
|
|
8211
|
+
let i = 0;
|
|
8212
|
+
const n = source.length;
|
|
8213
|
+
while (i < n) {
|
|
8214
|
+
const ch = source[i];
|
|
8215
|
+
if (isWhitespace(ch)) {
|
|
8216
|
+
i += 1;
|
|
8217
|
+
continue;
|
|
8218
|
+
}
|
|
8219
|
+
if (isDigit(ch)) {
|
|
8220
|
+
const start = i;
|
|
8221
|
+
while (i < n && isDigit(source[i])) i += 1;
|
|
8222
|
+
if (i < n && source[i] === ".") {
|
|
8223
|
+
if (i + 1 >= n || !isDigit(source[i + 1])) throw new ExpressionParseError("malformed number: decimal point needs a digit", i);
|
|
8224
|
+
i += 1;
|
|
8225
|
+
while (i < n && isDigit(source[i])) i += 1;
|
|
8226
|
+
}
|
|
8227
|
+
const text = source.slice(start, i);
|
|
8228
|
+
const value = Number(text);
|
|
8229
|
+
if (!Number.isFinite(value)) throw new ExpressionParseError(`malformed number: '${text}'`, start);
|
|
8230
|
+
tokens.push({
|
|
8231
|
+
type: "number",
|
|
8232
|
+
value,
|
|
8233
|
+
pos: start
|
|
8234
|
+
});
|
|
8235
|
+
continue;
|
|
8236
|
+
}
|
|
8237
|
+
if (ch === "'" || ch === "\"") {
|
|
8238
|
+
const quote = ch;
|
|
8239
|
+
const start = i;
|
|
8240
|
+
i += 1;
|
|
8241
|
+
let out = "";
|
|
8242
|
+
let closed = false;
|
|
8243
|
+
while (i < n) {
|
|
8244
|
+
const c = source[i];
|
|
8245
|
+
if (c === "\\") {
|
|
8246
|
+
const next = i + 1 < n ? source[i + 1] : "";
|
|
8247
|
+
if (next === "\\" || next === "'" || next === "\"") {
|
|
8248
|
+
out += next;
|
|
8249
|
+
i += 2;
|
|
8250
|
+
continue;
|
|
8251
|
+
}
|
|
8252
|
+
throw new ExpressionParseError(`invalid string escape: '\\${next}'`, i);
|
|
8253
|
+
}
|
|
8254
|
+
if (c === quote) {
|
|
8255
|
+
closed = true;
|
|
8256
|
+
i += 1;
|
|
8257
|
+
break;
|
|
8258
|
+
}
|
|
8259
|
+
out += c;
|
|
8260
|
+
i += 1;
|
|
8261
|
+
}
|
|
8262
|
+
if (!closed) throw new ExpressionParseError("unterminated string literal", start);
|
|
8263
|
+
tokens.push({
|
|
8264
|
+
type: "string",
|
|
8265
|
+
value: out,
|
|
8266
|
+
pos: start
|
|
8267
|
+
});
|
|
8268
|
+
continue;
|
|
8269
|
+
}
|
|
8270
|
+
if (isIdentStart(ch)) {
|
|
8271
|
+
const start = i;
|
|
8272
|
+
while (i < n && isIdentPart(source[i])) i += 1;
|
|
8273
|
+
const text = source.slice(start, i);
|
|
8274
|
+
if (KEYWORDS.has(text)) tokens.push({
|
|
8275
|
+
type: "keyword",
|
|
8276
|
+
keyword: keywordOf(text),
|
|
8277
|
+
pos: start
|
|
8278
|
+
});
|
|
8279
|
+
else tokens.push({
|
|
8280
|
+
type: "identifier",
|
|
8281
|
+
name: text,
|
|
8282
|
+
pos: start
|
|
8283
|
+
});
|
|
8284
|
+
continue;
|
|
8285
|
+
}
|
|
8286
|
+
const two = i + 1 < n ? source.slice(i, i + 2) : "";
|
|
8287
|
+
if (two === "<=" || two === ">=" || two === "==" || two === "!=" || two === "&&" || two === "||") {
|
|
8288
|
+
tokens.push({
|
|
8289
|
+
type: "punct",
|
|
8290
|
+
punct: two,
|
|
8291
|
+
pos: i
|
|
8292
|
+
});
|
|
8293
|
+
i += 2;
|
|
8294
|
+
continue;
|
|
8295
|
+
}
|
|
8296
|
+
if (isSinglePunct(ch)) {
|
|
8297
|
+
tokens.push({
|
|
8298
|
+
type: "punct",
|
|
8299
|
+
punct: ch,
|
|
8300
|
+
pos: i
|
|
8301
|
+
});
|
|
8302
|
+
i += 1;
|
|
8303
|
+
continue;
|
|
8304
|
+
}
|
|
8305
|
+
throw new ExpressionParseError(`unexpected character '${ch}'`, i);
|
|
8306
|
+
}
|
|
8307
|
+
tokens.push({
|
|
8308
|
+
type: "eof",
|
|
8309
|
+
pos: n
|
|
8310
|
+
});
|
|
8311
|
+
return tokens;
|
|
8312
|
+
}
|
|
8313
|
+
function keywordOf(text) {
|
|
8314
|
+
if (text === "true") return "true";
|
|
8315
|
+
if (text === "false") return "false";
|
|
8316
|
+
return "null";
|
|
8317
|
+
}
|
|
8318
|
+
function isSinglePunct(ch) {
|
|
8319
|
+
return ch === "(" || ch === ")" || ch === "," || ch === "?" || ch === ":" || ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%" || ch === "!" || ch === "<" || ch === ">";
|
|
8320
|
+
}
|
|
8321
|
+
/**
|
|
8322
|
+
* Frozen, null-prototype builtin function table for the expression engine
|
|
8323
|
+
* (spec §4 rule 4). The table is the SOLE surface of callable functions: the
|
|
8324
|
+
* parser rejects any callee not in it, and the evaluator gates each call on an
|
|
8325
|
+
* own-property check against it.
|
|
8326
|
+
*
|
|
8327
|
+
* Because the object has a NULL prototype AND is `Object.freeze`d:
|
|
8328
|
+
* - it cannot be polluted (no `__proto__` / `constructor` write reaches it);
|
|
8329
|
+
* - a lookup for `toString` / `hasOwnProperty` / `constructor` finds NOTHING
|
|
8330
|
+
* (there is no `Object.prototype` in the chain), so those names are not
|
|
8331
|
+
* callable — they are simply "unknown function" at parse time.
|
|
8332
|
+
*
|
|
8333
|
+
* Every numeric argument is validated as a finite number and every numeric
|
|
8334
|
+
* RESULT is re-checked finite, so `/0`, `sqrt(-1)` (→ NaN) and overflow
|
|
8335
|
+
* (`pow(10,400)` → Infinity) all raise `ExpressionEvalError` and fail the link
|
|
8336
|
+
* closed rather than emitting a garbage value.
|
|
8337
|
+
*/
|
|
8338
|
+
function asFiniteNumber(value, name, index) {
|
|
8339
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a finite number`);
|
|
8340
|
+
return value;
|
|
8341
|
+
}
|
|
8342
|
+
function asString$1(value, name, index) {
|
|
8343
|
+
if (typeof value !== "string") throw new ExpressionEvalError(`${name}: argument ${index + 1} must be a string`);
|
|
8344
|
+
return value;
|
|
8345
|
+
}
|
|
8346
|
+
function finiteResult(value, name) {
|
|
8347
|
+
if (!Number.isFinite(value)) throw new ExpressionEvalError(`${name}: produced a non-finite result`);
|
|
8348
|
+
return value;
|
|
8349
|
+
}
|
|
8350
|
+
function allFiniteNumbers(args, name) {
|
|
8351
|
+
return args.map((a, idx) => asFiniteNumber(a, name, idx));
|
|
8352
|
+
}
|
|
8353
|
+
var INF = Number.POSITIVE_INFINITY;
|
|
8354
|
+
var table = {
|
|
8355
|
+
min: {
|
|
8356
|
+
minArgs: 1,
|
|
8357
|
+
maxArgs: INF,
|
|
8358
|
+
apply: (args) => finiteResult(Math.min(...allFiniteNumbers(args, "min")), "min")
|
|
8359
|
+
},
|
|
8360
|
+
max: {
|
|
8361
|
+
minArgs: 1,
|
|
8362
|
+
maxArgs: INF,
|
|
8363
|
+
apply: (args) => finiteResult(Math.max(...allFiniteNumbers(args, "max")), "max")
|
|
8364
|
+
},
|
|
8365
|
+
abs: {
|
|
8366
|
+
minArgs: 1,
|
|
8367
|
+
maxArgs: 1,
|
|
8368
|
+
apply: (args) => finiteResult(Math.abs(asFiniteNumber(args[0], "abs", 0)), "abs")
|
|
8369
|
+
},
|
|
8370
|
+
floor: {
|
|
8371
|
+
minArgs: 1,
|
|
8372
|
+
maxArgs: 1,
|
|
8373
|
+
apply: (args) => finiteResult(Math.floor(asFiniteNumber(args[0], "floor", 0)), "floor")
|
|
8374
|
+
},
|
|
8375
|
+
ceil: {
|
|
8376
|
+
minArgs: 1,
|
|
8377
|
+
maxArgs: 1,
|
|
8378
|
+
apply: (args) => finiteResult(Math.ceil(asFiniteNumber(args[0], "ceil", 0)), "ceil")
|
|
8379
|
+
},
|
|
8380
|
+
sqrt: {
|
|
8381
|
+
minArgs: 1,
|
|
8382
|
+
maxArgs: 1,
|
|
8383
|
+
apply: (args) => finiteResult(Math.sqrt(asFiniteNumber(args[0], "sqrt", 0)), "sqrt")
|
|
8384
|
+
},
|
|
8385
|
+
round: {
|
|
8386
|
+
minArgs: 1,
|
|
8387
|
+
maxArgs: 2,
|
|
8388
|
+
apply: (args) => {
|
|
8389
|
+
const x = asFiniteNumber(args[0], "round", 0);
|
|
8390
|
+
const digits = args.length > 1 ? Math.trunc(asFiniteNumber(args[1], "round", 1)) : 0;
|
|
8391
|
+
if (digits < 0 || digits > 100) throw new ExpressionEvalError("round: digits must be between 0 and 100");
|
|
8392
|
+
const factor = 10 ** digits;
|
|
8393
|
+
return finiteResult(Math.round(x * factor) / factor, "round");
|
|
8394
|
+
}
|
|
8395
|
+
},
|
|
8396
|
+
pow: {
|
|
8397
|
+
minArgs: 2,
|
|
8398
|
+
maxArgs: 2,
|
|
8399
|
+
apply: (args) => finiteResult(asFiniteNumber(args[0], "pow", 0) ** asFiniteNumber(args[1], "pow", 1), "pow")
|
|
8400
|
+
},
|
|
8401
|
+
clamp: {
|
|
8402
|
+
minArgs: 3,
|
|
8403
|
+
maxArgs: 3,
|
|
8404
|
+
apply: (args) => {
|
|
8405
|
+
const x = asFiniteNumber(args[0], "clamp", 0);
|
|
8406
|
+
const lo = asFiniteNumber(args[1], "clamp", 1);
|
|
8407
|
+
const hi = asFiniteNumber(args[2], "clamp", 2);
|
|
8408
|
+
if (lo > hi) throw new ExpressionEvalError("clamp: lower bound is greater than upper bound");
|
|
8409
|
+
return finiteResult(Math.min(hi, Math.max(lo, x)), "clamp");
|
|
8410
|
+
}
|
|
8411
|
+
},
|
|
8412
|
+
avg: {
|
|
8413
|
+
minArgs: 1,
|
|
8414
|
+
maxArgs: INF,
|
|
8415
|
+
apply: (args) => {
|
|
8416
|
+
const nums = allFiniteNumbers(args, "avg");
|
|
8417
|
+
return finiteResult(nums.reduce((acc, v) => acc + v, 0) / nums.length, "avg");
|
|
8418
|
+
}
|
|
8419
|
+
},
|
|
8420
|
+
sum: {
|
|
8421
|
+
minArgs: 1,
|
|
8422
|
+
maxArgs: INF,
|
|
8423
|
+
apply: (args) => finiteResult(allFiniteNumbers(args, "sum").reduce((acc, v) => acc + v, 0), "sum")
|
|
8424
|
+
},
|
|
8425
|
+
coalesce: {
|
|
8426
|
+
minArgs: 1,
|
|
8427
|
+
maxArgs: INF,
|
|
8428
|
+
apply: (args) => {
|
|
8429
|
+
for (const a of args) if (a !== null) return a;
|
|
8430
|
+
return null;
|
|
8431
|
+
}
|
|
8432
|
+
},
|
|
8433
|
+
age: {
|
|
8434
|
+
minArgs: 2,
|
|
8435
|
+
maxArgs: 2,
|
|
8436
|
+
apply: (args) => finiteResult(asFiniteNumber(args[0], "age", 0) - asFiniteNumber(args[1], "age", 1), "age")
|
|
8437
|
+
},
|
|
8438
|
+
convert: {
|
|
8439
|
+
minArgs: 3,
|
|
8440
|
+
maxArgs: 3,
|
|
8441
|
+
apply: (args, hooks) => {
|
|
8442
|
+
const x = asFiniteNumber(args[0], "convert", 0);
|
|
8443
|
+
const from = asString$1(args[1], "convert", 1).trim();
|
|
8444
|
+
const to = asString$1(args[2], "convert", 2).trim();
|
|
8445
|
+
if (hooks.convert) {
|
|
8446
|
+
const out = hooks.convert(x, from, to);
|
|
8447
|
+
if (out === null) throw new ExpressionEvalError(`convert: cannot convert '${from}' to '${to}'`);
|
|
8448
|
+
return finiteResult(out, "convert");
|
|
8449
|
+
}
|
|
8450
|
+
if (from === to) return x;
|
|
8451
|
+
throw new ExpressionEvalError("convert: unit conversion table not installed");
|
|
8452
|
+
}
|
|
8453
|
+
}
|
|
8454
|
+
};
|
|
8455
|
+
Object.freeze(Object.assign(Object.create(null), table));
|
|
8456
|
+
/** The set of valid builtin names — used by the parser to reject unknown
|
|
8457
|
+
* callees at parse time (immediate author feedback). */
|
|
8458
|
+
var EXPRESSION_BUILTIN_NAMES = new Set(Object.keys(table));
|
|
8459
|
+
/**
|
|
8460
|
+
* Pratt (precedence-climbing) parser for the safe expression mini-language.
|
|
8461
|
+
*
|
|
8462
|
+
* Precedence (low → high): ternary `?:` (right-assoc) → `||` → `&&` → equality
|
|
8463
|
+
* → relational → additive → multiplicative → unary `! -` → call / primary.
|
|
8464
|
+
* Calls are ONLY `IDENT '(' args? ')'` at primary position — the callee is a
|
|
8465
|
+
* string validated against the builtin table at parse time, so an unknown
|
|
8466
|
+
* function is rejected immediately (author feedback) and a persisted expression
|
|
8467
|
+
* that references a since-removed builtin degrades at read.
|
|
8468
|
+
*
|
|
8469
|
+
* A node counter caps total AST size (`MAX_EXPRESSION_AST_NODES`) and call
|
|
8470
|
+
* arity is capped (`MAX_EXPRESSION_CALL_ARGS`) — both raise `ExpressionParseError`.
|
|
8471
|
+
*/
|
|
8472
|
+
/** Binary/logical operator precedence (higher binds tighter). */
|
|
8473
|
+
var BINARY_PRECEDENCE = {
|
|
8474
|
+
"||": 1,
|
|
8475
|
+
"&&": 2,
|
|
8476
|
+
"==": 3,
|
|
8477
|
+
"!=": 3,
|
|
8478
|
+
"<": 4,
|
|
8479
|
+
"<=": 4,
|
|
8480
|
+
">": 4,
|
|
8481
|
+
">=": 4,
|
|
8482
|
+
"+": 5,
|
|
8483
|
+
"-": 5,
|
|
8484
|
+
"*": 6,
|
|
8485
|
+
"/": 6,
|
|
8486
|
+
"%": 6
|
|
8487
|
+
};
|
|
8488
|
+
function isLogicalOp(op) {
|
|
8489
|
+
return op === "&&" || op === "||";
|
|
8490
|
+
}
|
|
8491
|
+
function isBinaryOp(op) {
|
|
8492
|
+
return op === "+" || op === "-" || op === "*" || op === "/" || op === "%" || op === "==" || op === "!=" || op === "<" || op === "<=" || op === ">" || op === ">=";
|
|
8493
|
+
}
|
|
8494
|
+
var Parser = class {
|
|
8495
|
+
tokens;
|
|
8496
|
+
pos = 0;
|
|
8497
|
+
nodeCount = 0;
|
|
8498
|
+
identifiers = /* @__PURE__ */ new Set();
|
|
8499
|
+
callees = /* @__PURE__ */ new Set();
|
|
8500
|
+
constructor(tokens) {
|
|
8501
|
+
this.tokens = tokens;
|
|
8502
|
+
}
|
|
8503
|
+
parse() {
|
|
8504
|
+
const ast = this.parseTernary();
|
|
8505
|
+
const tok = this.peek();
|
|
8506
|
+
if (tok.type !== "eof") throw new ExpressionParseError("unexpected trailing input", tok.pos);
|
|
8507
|
+
return {
|
|
8508
|
+
ast,
|
|
8509
|
+
identifiers: this.identifiers,
|
|
8510
|
+
callees: this.callees,
|
|
8511
|
+
nodeCount: this.nodeCount
|
|
8512
|
+
};
|
|
8513
|
+
}
|
|
8514
|
+
peek() {
|
|
8515
|
+
return this.tokens[this.pos];
|
|
8516
|
+
}
|
|
8517
|
+
next() {
|
|
8518
|
+
return this.tokens[this.pos++];
|
|
8519
|
+
}
|
|
8520
|
+
/** Consume a punctuator token, erroring if the next token isn't it. */
|
|
8521
|
+
expectPunct(punct) {
|
|
8522
|
+
const tok = this.peek();
|
|
8523
|
+
if (tok.type !== "punct" || tok.punct !== punct) throw new ExpressionParseError(`expected '${punct}'`, tok.pos);
|
|
8524
|
+
this.pos += 1;
|
|
8525
|
+
}
|
|
8526
|
+
matchPunct(punct) {
|
|
8527
|
+
const tok = this.peek();
|
|
8528
|
+
if (tok.type === "punct" && tok.punct === punct) {
|
|
8529
|
+
this.pos += 1;
|
|
8530
|
+
return true;
|
|
8531
|
+
}
|
|
8532
|
+
return false;
|
|
8533
|
+
}
|
|
8534
|
+
countNode() {
|
|
8535
|
+
this.nodeCount += 1;
|
|
8536
|
+
if (this.nodeCount > 256) throw new ExpressionParseError("expression too complex", this.peek().pos);
|
|
8537
|
+
}
|
|
8538
|
+
parseTernary() {
|
|
8539
|
+
const test = this.parseBinary(1);
|
|
8540
|
+
if (this.matchPunct("?")) {
|
|
8541
|
+
const consequent = this.parseTernary();
|
|
8542
|
+
this.expectPunct(":");
|
|
8543
|
+
const alternate = this.parseTernary();
|
|
8544
|
+
this.countNode();
|
|
8545
|
+
return {
|
|
8546
|
+
kind: "conditional",
|
|
8547
|
+
test,
|
|
8548
|
+
consequent,
|
|
8549
|
+
alternate
|
|
8550
|
+
};
|
|
8551
|
+
}
|
|
8552
|
+
return test;
|
|
8553
|
+
}
|
|
8554
|
+
parseBinary(minPrec) {
|
|
8555
|
+
let left = this.parseUnary();
|
|
8556
|
+
for (;;) {
|
|
8557
|
+
const tok = this.peek();
|
|
8558
|
+
if (tok.type !== "punct") break;
|
|
8559
|
+
const prec = BINARY_PRECEDENCE[tok.punct];
|
|
8560
|
+
if (prec === void 0 || prec < minPrec) break;
|
|
8561
|
+
const op = tok.punct;
|
|
8562
|
+
this.pos += 1;
|
|
8563
|
+
const right = this.parseBinary(prec + 1);
|
|
8564
|
+
this.countNode();
|
|
8565
|
+
if (isLogicalOp(op)) left = {
|
|
8566
|
+
kind: "logical",
|
|
8567
|
+
op,
|
|
8568
|
+
left,
|
|
8569
|
+
right
|
|
8570
|
+
};
|
|
8571
|
+
else if (isBinaryOp(op)) left = {
|
|
8572
|
+
kind: "binary",
|
|
8573
|
+
op,
|
|
8574
|
+
left,
|
|
8575
|
+
right
|
|
8576
|
+
};
|
|
8577
|
+
else throw new ExpressionParseError(`unexpected operator '${op}'`, tok.pos);
|
|
8578
|
+
}
|
|
8579
|
+
return left;
|
|
8580
|
+
}
|
|
8581
|
+
parseUnary() {
|
|
8582
|
+
const tok = this.peek();
|
|
8583
|
+
if (tok.type === "punct" && (tok.punct === "!" || tok.punct === "-")) {
|
|
8584
|
+
const op = tok.punct;
|
|
8585
|
+
this.pos += 1;
|
|
8586
|
+
const operand = this.parseUnary();
|
|
8587
|
+
this.countNode();
|
|
8588
|
+
return {
|
|
8589
|
+
kind: "unary",
|
|
8590
|
+
op,
|
|
8591
|
+
operand
|
|
8592
|
+
};
|
|
8593
|
+
}
|
|
8594
|
+
return this.parsePrimary();
|
|
8595
|
+
}
|
|
8596
|
+
parsePrimary() {
|
|
8597
|
+
const tok = this.next();
|
|
8598
|
+
switch (tok.type) {
|
|
8599
|
+
case "number":
|
|
8600
|
+
this.countNode();
|
|
8601
|
+
return {
|
|
8602
|
+
kind: "literal",
|
|
8603
|
+
value: tok.value
|
|
8604
|
+
};
|
|
8605
|
+
case "string":
|
|
8606
|
+
this.countNode();
|
|
8607
|
+
return {
|
|
8608
|
+
kind: "literal",
|
|
8609
|
+
value: tok.value
|
|
8610
|
+
};
|
|
8611
|
+
case "keyword":
|
|
8612
|
+
this.countNode();
|
|
8613
|
+
return {
|
|
8614
|
+
kind: "literal",
|
|
8615
|
+
value: tok.keyword === "null" ? null : tok.keyword === "true"
|
|
8616
|
+
};
|
|
8617
|
+
case "identifier": {
|
|
8618
|
+
const nextTok = this.peek();
|
|
8619
|
+
if (nextTok.type === "punct" && nextTok.punct === "(") return this.parseCall(tok.name, tok.pos);
|
|
8620
|
+
this.identifiers.add(tok.name);
|
|
8621
|
+
this.countNode();
|
|
8622
|
+
return {
|
|
8623
|
+
kind: "identifier",
|
|
8624
|
+
name: tok.name
|
|
8625
|
+
};
|
|
8626
|
+
}
|
|
8627
|
+
case "punct":
|
|
8628
|
+
if (tok.punct === "(") {
|
|
8629
|
+
const inner = this.parseTernary();
|
|
8630
|
+
this.expectPunct(")");
|
|
8631
|
+
return inner;
|
|
8632
|
+
}
|
|
8633
|
+
throw new ExpressionParseError(`unexpected token '${tok.punct}'`, tok.pos);
|
|
8634
|
+
case "eof": throw new ExpressionParseError("unexpected end of expression", tok.pos);
|
|
8635
|
+
}
|
|
8636
|
+
}
|
|
8637
|
+
parseCall(callee, pos) {
|
|
8638
|
+
if (!EXPRESSION_BUILTIN_NAMES.has(callee)) throw new ExpressionParseError(`unknown function '${callee}'`, pos);
|
|
8639
|
+
this.expectPunct("(");
|
|
8640
|
+
const args = [];
|
|
8641
|
+
if (!this.matchPunct(")")) for (;;) {
|
|
8642
|
+
args.push(this.parseTernary());
|
|
8643
|
+
if (args.length > 16) throw new ExpressionParseError(`too many arguments to '${callee}'`, pos);
|
|
8644
|
+
if (this.matchPunct(",")) continue;
|
|
8645
|
+
this.expectPunct(")");
|
|
8646
|
+
break;
|
|
8647
|
+
}
|
|
8648
|
+
this.callees.add(callee);
|
|
8649
|
+
this.countNode();
|
|
8650
|
+
return {
|
|
8651
|
+
kind: "call",
|
|
8652
|
+
callee,
|
|
8653
|
+
args
|
|
8654
|
+
};
|
|
8655
|
+
}
|
|
8656
|
+
};
|
|
8657
|
+
/** Tokenize + parse `source` into a validated `ParsedExpression`. Throws
|
|
8658
|
+
* `ExpressionParseError` on any lexical or grammatical failure. */
|
|
8659
|
+
function parseExpression(source) {
|
|
8660
|
+
return new Parser(tokenize(source)).parse();
|
|
8661
|
+
}
|
|
8662
|
+
Object.freeze({});
|
|
8663
|
+
/**
|
|
8664
|
+
* LRU compile cache for parsed expressions (spec §2.4 "parse once … LRU keyed
|
|
8665
|
+
* by expr"). The cache stores BOTH successes and failures (negative caching),
|
|
8666
|
+
* so a corrupt persisted string costs exactly one tokenize+parse total — not
|
|
8667
|
+
* one per read on a hot resolve path.
|
|
8668
|
+
*
|
|
8669
|
+
* The cache is a module-level singleton: entries are pure, content-addressed
|
|
8670
|
+
* ASTs keyed by the raw source string, so sharing one instance across all
|
|
8671
|
+
* callers is safe and maximises hit rate.
|
|
8672
|
+
*/
|
|
8673
|
+
var cache = /* @__PURE__ */ new Map();
|
|
8674
|
+
function getCached(source) {
|
|
8675
|
+
const hit = cache.get(source);
|
|
8676
|
+
if (hit !== void 0) {
|
|
8677
|
+
cache.delete(source);
|
|
8678
|
+
cache.set(source, hit);
|
|
8679
|
+
return hit;
|
|
8680
|
+
}
|
|
8681
|
+
let result;
|
|
8682
|
+
try {
|
|
8683
|
+
result = {
|
|
8684
|
+
ok: true,
|
|
8685
|
+
parsed: parseExpression(source)
|
|
8686
|
+
};
|
|
8687
|
+
} catch (err) {
|
|
8688
|
+
result = {
|
|
8689
|
+
ok: false,
|
|
8690
|
+
error: err instanceof ExpressionParseError ? err.message : String(err)
|
|
8691
|
+
};
|
|
8692
|
+
}
|
|
8693
|
+
cache.set(source, result);
|
|
8694
|
+
if (cache.size > 256) {
|
|
8695
|
+
const oldest = cache.keys().next().value;
|
|
8696
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
8697
|
+
}
|
|
8698
|
+
return result;
|
|
8699
|
+
}
|
|
8700
|
+
/** Compile `source`, returning a discriminated result instead of throwing.
|
|
8701
|
+
* Used by read paths that must degrade rather than raise. LRU/negative-cached. */
|
|
8702
|
+
function compileExpressionSafe(source) {
|
|
8703
|
+
return getCached(source);
|
|
8704
|
+
}
|
|
8705
|
+
/**
|
|
8706
|
+
* Author-time validation. Returns `null` when the source is valid, else a
|
|
8707
|
+
* human-readable error message. Checks: the expression compiles; binding count
|
|
8708
|
+
* is within `MAX_EXPRESSION_BINDINGS`; every binding name is a legal identifier,
|
|
8709
|
+
* is not reserved (`now`/keywords) and does not shadow a builtin; and every
|
|
8710
|
+
* FREE identifier of the AST is covered by a binding or the injected `now`.
|
|
8711
|
+
*/
|
|
8712
|
+
function validateExpressionSource(src) {
|
|
8713
|
+
const names = Object.keys(src.bindings);
|
|
8714
|
+
if (names.length > 32) return `too many bindings (${names.length} > 32)`;
|
|
8715
|
+
for (const name of names) {
|
|
8716
|
+
if (!EXPRESSION_IDENTIFIER_RE.test(name)) return `invalid binding name '${name}'`;
|
|
8717
|
+
if (RESERVED_BINDING_NAMES.has(name)) return `binding name '${name}' is reserved`;
|
|
8718
|
+
if (EXPRESSION_BUILTIN_NAMES.has(name)) return `binding name '${name}' shadows a builtin function`;
|
|
8719
|
+
}
|
|
8720
|
+
const compiled = compileExpressionSafe(src.expr);
|
|
8721
|
+
if (!compiled.ok) return compiled.error;
|
|
8722
|
+
const bound = new Set(names);
|
|
8723
|
+
for (const id of compiled.parsed.identifiers) {
|
|
8724
|
+
if (id === "now") continue;
|
|
8725
|
+
if (!bound.has(id)) return `expression references unbound identifier '${id}'`;
|
|
8726
|
+
}
|
|
8727
|
+
return null;
|
|
8728
|
+
}
|
|
8729
|
+
/**
|
|
8116
8730
|
* Accessory device helpers — shared across drivers.
|
|
8117
8731
|
*
|
|
8118
8732
|
* Many vendor-specific drivers register accessory child devices on
|
|
@@ -10813,6 +11427,31 @@ var ReportMotionInputSchema = object({
|
|
|
10813
11427
|
regions: array(MotionRegionSchema).readonly().optional()
|
|
10814
11428
|
});
|
|
10815
11429
|
/**
|
|
11430
|
+
* Where a runner gets a camera's decoded frames (cross-node Phase 2,
|
|
11431
|
+
* restream-owner model — P2c).
|
|
11432
|
+
*
|
|
11433
|
+
* - `local-broker` (DEFAULT): today's path — subscribe to the co-located
|
|
11434
|
+
* stream-broker's shm frame plane. Every pre-P2c attach payload (no
|
|
11435
|
+
* `frameSource` key) parses to this, so the field is additive with zero
|
|
11436
|
+
* behavior change.
|
|
11437
|
+
* - `remote-restream`: the detect node is NOT the camera's source-owner.
|
|
11438
|
+
* The runner acquires the owner's COMPRESSED passthrough restream
|
|
11439
|
+
* (`streamBroker.getStreamWithCodec({video:'copy'})` — refcounted, the
|
|
11440
|
+
* double-pull guard) and decodes LOCALLY via a satellite frame plane +
|
|
11441
|
+
* pull-mode decoder session pinned to its own node. The shm ring stays
|
|
11442
|
+
* node-local; only H.264/H.265 packets cross the wire.
|
|
11443
|
+
* `hubHostnameOverride` mirrors the recorder's `recordingHubHostname`:
|
|
11444
|
+
* when set it overrides the `CAMSTACK_HUB_URL`-derived host the runner
|
|
11445
|
+
* dials for the owner's restream.
|
|
11446
|
+
*/
|
|
11447
|
+
var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal("local-broker") }), object({
|
|
11448
|
+
kind: literal("remote-restream"),
|
|
11449
|
+
/** The camera's source-owner node (slice 1: always the hub). */
|
|
11450
|
+
ownerNodeId: string(),
|
|
11451
|
+
/** Operator override for the owner host the runner dials. */
|
|
11452
|
+
hubHostnameOverride: string().optional()
|
|
11453
|
+
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
11454
|
+
/**
|
|
10816
11455
|
* Camera assignment payload sent by `addon-pipeline-orchestrator` to a
|
|
10817
11456
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
10818
11457
|
* runner needs to subscribe to the local broker and execute inference.
|
|
@@ -10910,7 +11549,15 @@ var RunnerCameraConfigSchema = object({
|
|
|
10910
11549
|
*/
|
|
10911
11550
|
onboardMotionDrivesAnalyzer: boolean().default(true),
|
|
10912
11551
|
occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
|
|
10913
|
-
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default)
|
|
11552
|
+
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
|
|
11553
|
+
/**
|
|
11554
|
+
* Where this runner gets the camera's decoded frames (P2c). Defaulted so
|
|
11555
|
+
* every existing payload behaves as `local-broker` — the pre-Phase-2 path.
|
|
11556
|
+
* Populated with `remote-restream` by the orchestrator ONLY when the
|
|
11557
|
+
* camera's detect node differs from its source-owner (P2d, gated by the
|
|
11558
|
+
* `remoteSourcingNodes` rollout setting).
|
|
11559
|
+
*/
|
|
11560
|
+
frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
|
|
10914
11561
|
});
|
|
10915
11562
|
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
10916
11563
|
/**
|
|
@@ -13782,14 +14429,63 @@ var ChildLayoutEntrySchema = object({
|
|
|
13782
14429
|
collapsed: boolean().optional()
|
|
13783
14430
|
});
|
|
13784
14431
|
/** Cap-wire shape of a DeviceLink — structurally mirrors `DeviceLink` in
|
|
13785
|
-
* `device-management.ts`.
|
|
14432
|
+
* `device-management.ts`. Source is a union: a FIELD source copies a sibling
|
|
14433
|
+
* accessory's status field (`kind` optional/absent for wire compat); a
|
|
14434
|
+
* LITERAL source carries a per-device constant (no sibling is read); a
|
|
14435
|
+
* GLOBAL source (P2e) copies ANY device's status field, addressed by the
|
|
14436
|
+
* source device's full re-sync-stable `stableId`. */
|
|
14437
|
+
var DeviceLinkFieldSourceSchema = object({
|
|
14438
|
+
kind: literal("field").optional(),
|
|
14439
|
+
sourceKey: string(),
|
|
14440
|
+
cap: string(),
|
|
14441
|
+
fieldPath: string()
|
|
14442
|
+
});
|
|
14443
|
+
var DeviceLinkLiteralSourceSchema = object({
|
|
14444
|
+
kind: literal("literal"),
|
|
14445
|
+
value: union([
|
|
14446
|
+
string(),
|
|
14447
|
+
number(),
|
|
14448
|
+
boolean(),
|
|
14449
|
+
_null()
|
|
14450
|
+
])
|
|
14451
|
+
});
|
|
14452
|
+
var DeviceLinkGlobalSourceSchema = object({
|
|
14453
|
+
kind: literal("global"),
|
|
14454
|
+
sourceStableId: string(),
|
|
14455
|
+
cap: string(),
|
|
14456
|
+
fieldPath: string()
|
|
14457
|
+
});
|
|
14458
|
+
/** Expression source (Stage X): compute the target field from N named bindings
|
|
14459
|
+
* via the safe expression engine. Bindings are field | literal | global — never
|
|
14460
|
+
* another expression (no nesting). The `superRefine` runs the SAME author-time
|
|
14461
|
+
* validation as `validateExpressionSource` (compiles the expr, checks binding
|
|
14462
|
+
* names + identifier coverage) so every wire boundary that parses a DeviceLink
|
|
14463
|
+
* (tRPC mount, kernel create pre-seed, projection output) validates-at-write.
|
|
14464
|
+
* Compiles are LRU-cached, so repeated validation of the same expr is a hit. */
|
|
14465
|
+
var DeviceLinkExpressionSourceSchema = object({
|
|
14466
|
+
kind: literal("expression"),
|
|
14467
|
+
expr: string().min(1).max(MAX_EXPRESSION_SOURCE_LENGTH),
|
|
14468
|
+
bindings: record(string().regex(EXPRESSION_IDENTIFIER_RE), union([
|
|
14469
|
+
DeviceLinkFieldSourceSchema,
|
|
14470
|
+
DeviceLinkLiteralSourceSchema,
|
|
14471
|
+
DeviceLinkGlobalSourceSchema
|
|
14472
|
+
]))
|
|
14473
|
+
}).superRefine((src, ctx) => {
|
|
14474
|
+
const err = validateExpressionSource(src);
|
|
14475
|
+
if (err !== null) ctx.addIssue({
|
|
14476
|
+
code: "custom",
|
|
14477
|
+
message: err,
|
|
14478
|
+
path: ["expr"]
|
|
14479
|
+
});
|
|
14480
|
+
});
|
|
13786
14481
|
var DeviceLinkSchema = object({
|
|
13787
14482
|
id: string(),
|
|
13788
|
-
source:
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
14483
|
+
source: union([
|
|
14484
|
+
DeviceLinkFieldSourceSchema,
|
|
14485
|
+
DeviceLinkLiteralSourceSchema,
|
|
14486
|
+
DeviceLinkGlobalSourceSchema,
|
|
14487
|
+
DeviceLinkExpressionSourceSchema
|
|
14488
|
+
]),
|
|
13793
14489
|
target: object({
|
|
13794
14490
|
cap: string(),
|
|
13795
14491
|
fieldPath: string(),
|
|
@@ -13818,6 +14514,31 @@ var DeviceLinkSchema = object({
|
|
|
13818
14514
|
})
|
|
13819
14515
|
]).optional()
|
|
13820
14516
|
});
|
|
14517
|
+
/** Cap-wire shape of a per-cap display refinement — mirrors
|
|
14518
|
+
* `DeviceCapDisplayOverride` in `device-management.ts`. */
|
|
14519
|
+
var DeviceCapDisplayOverrideSchema = object({
|
|
14520
|
+
unit: string().min(1).optional(),
|
|
14521
|
+
precision: number().int().min(0).max(10).optional()
|
|
14522
|
+
});
|
|
14523
|
+
/** Cap-wire shape of an operator-authored per-device display override —
|
|
14524
|
+
* mirrors `DeviceDisplayOverride` in `device-management.ts`. `precision`
|
|
14525
|
+
* bounds mirror `numeric-sensor.cap.ts` (`int 0-10`). */
|
|
14526
|
+
var DeviceDisplayOverrideSchema = object({
|
|
14527
|
+
icon: string().min(1).optional(),
|
|
14528
|
+
label: string().min(1).optional(),
|
|
14529
|
+
unit: string().min(1).optional(),
|
|
14530
|
+
precision: number().int().min(0).max(10).optional(),
|
|
14531
|
+
hidden: boolean().optional(),
|
|
14532
|
+
perCap: record(string(), DeviceCapDisplayOverrideSchema).optional()
|
|
14533
|
+
});
|
|
14534
|
+
/** Cap-wire shape of a per-role display default — mirrors `RoleDisplayDefault`
|
|
14535
|
+
* in `device-management.ts`. Keyed by `DeviceRole` string (role strings cross
|
|
14536
|
+
* the wire as plain strings everywhere else — cf. `DeviceInfoSchema.role`). */
|
|
14537
|
+
var RoleDisplayDefaultSchema = object({
|
|
14538
|
+
unit: string().min(1).optional(),
|
|
14539
|
+
precision: number().int().min(0).max(10).optional(),
|
|
14540
|
+
icon: string().min(1).optional()
|
|
14541
|
+
});
|
|
13821
14542
|
/**
|
|
13822
14543
|
* Serializable projection of a live IDevice.
|
|
13823
14544
|
* Returned by listAll, getDevice, getChildren.
|
|
@@ -13873,7 +14594,9 @@ var DeviceInfoSchema = object({
|
|
|
13873
14594
|
* `DeviceMeta.childLayout`. Absent ⇒ no layout declared. */
|
|
13874
14595
|
childLayout: array(ChildLayoutEntrySchema).readonly().optional(),
|
|
13875
14596
|
/** Operator-authored cross-device field wirings. See `DeviceMeta.deviceLinks`. */
|
|
13876
|
-
deviceLinks: array(DeviceLinkSchema).readonly().optional()
|
|
14597
|
+
deviceLinks: array(DeviceLinkSchema).readonly().optional(),
|
|
14598
|
+
/** Operator-authored per-device display override. See `DeviceMeta.display`. */
|
|
14599
|
+
display: DeviceDisplayOverrideSchema.optional()
|
|
13877
14600
|
});
|
|
13878
14601
|
var ConfigEntrySchema = object({
|
|
13879
14602
|
key: string(),
|
|
@@ -13938,7 +14661,9 @@ var DeviceMetaSchema = object({
|
|
|
13938
14661
|
deviceLinks: array(DeviceLinkSchema).readonly().optional(),
|
|
13939
14662
|
/** Semantic role string (`DeviceRole`) — propagated from the spawn pre-seed.
|
|
13940
14663
|
* Optional: only present for accessory children that carry a known role. */
|
|
13941
|
-
role: string().nullable().optional()
|
|
14664
|
+
role: string().nullable().optional(),
|
|
14665
|
+
/** Operator-authored per-device display override. See `DeviceMeta.display`. */
|
|
14666
|
+
display: DeviceDisplayOverrideSchema.optional()
|
|
13942
14667
|
});
|
|
13943
14668
|
/** ConfigUISchema passed through as unknown — mirrors device-provider's CreationSchemaOutputSchema */
|
|
13944
14669
|
var ConfigUISchemaOutput = unknown().nullable();
|
|
@@ -14032,7 +14757,19 @@ method(object({
|
|
|
14032
14757
|
}), _void(), {
|
|
14033
14758
|
kind: "mutation",
|
|
14034
14759
|
auth: "admin"
|
|
14035
|
-
}), method(object({
|
|
14760
|
+
}), method(object({
|
|
14761
|
+
deviceId: number(),
|
|
14762
|
+
display: DeviceDisplayOverrideSchema.nullable()
|
|
14763
|
+
}), _void(), {
|
|
14764
|
+
kind: "mutation",
|
|
14765
|
+
auth: "admin"
|
|
14766
|
+
}), method(object({}), object({ defaults: record(string(), RoleDisplayDefaultSchema) }), { kind: "query" }), method(object({ defaults: record(string(), RoleDisplayDefaultSchema) }), _void(), {
|
|
14767
|
+
kind: "mutation",
|
|
14768
|
+
auth: "admin"
|
|
14769
|
+
}), method(object({
|
|
14770
|
+
deviceId: number(),
|
|
14771
|
+
includeSynthesizable: boolean().optional()
|
|
14772
|
+
}), object({ caps: array(object({
|
|
14036
14773
|
cap: string(),
|
|
14037
14774
|
fields: array(object({
|
|
14038
14775
|
path: string(),
|
|
@@ -14042,8 +14779,13 @@ method(object({
|
|
|
14042
14779
|
"boolean",
|
|
14043
14780
|
"enum"
|
|
14044
14781
|
]),
|
|
14045
|
-
enumValues: array(string()).optional()
|
|
14046
|
-
|
|
14782
|
+
enumValues: array(string()).optional(),
|
|
14783
|
+
item: boolean().optional()
|
|
14784
|
+
})).readonly(),
|
|
14785
|
+
itemArray: object({
|
|
14786
|
+
path: string(),
|
|
14787
|
+
keyField: string()
|
|
14788
|
+
}).optional()
|
|
14047
14789
|
})).readonly() }), { kind: "query" }), method(object({
|
|
14048
14790
|
deviceId: number(),
|
|
14049
14791
|
role: string().nullable()
|
|
@@ -14113,7 +14855,11 @@ method(object({
|
|
|
14113
14855
|
deviceId: number(),
|
|
14114
14856
|
entries: array(object({
|
|
14115
14857
|
capName: string(),
|
|
14116
|
-
kind: _enum([
|
|
14858
|
+
kind: _enum([
|
|
14859
|
+
"native",
|
|
14860
|
+
"wrapped",
|
|
14861
|
+
"linked"
|
|
14862
|
+
]),
|
|
14117
14863
|
providerAddonId: string(),
|
|
14118
14864
|
providerNodeId: string(),
|
|
14119
14865
|
nativeAddonId: string()
|
|
@@ -14122,7 +14868,11 @@ method(object({
|
|
|
14122
14868
|
deviceId: number(),
|
|
14123
14869
|
entries: array(object({
|
|
14124
14870
|
capName: string(),
|
|
14125
|
-
kind: _enum([
|
|
14871
|
+
kind: _enum([
|
|
14872
|
+
"native",
|
|
14873
|
+
"wrapped",
|
|
14874
|
+
"linked"
|
|
14875
|
+
]),
|
|
14126
14876
|
providerAddonId: string(),
|
|
14127
14877
|
providerNodeId: string(),
|
|
14128
14878
|
nativeAddonId: string()
|
|
@@ -18144,6 +18894,16 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
|
|
|
18144
18894
|
kind: "mutation",
|
|
18145
18895
|
auth: "admin"
|
|
18146
18896
|
});
|
|
18897
|
+
/**
|
|
18898
|
+
* `recording` cap — footage availability + HLS playback manifests + per-device
|
|
18899
|
+
* recording config. NOTE on events (source of truth, R5/C3): this cap carries
|
|
18900
|
+
* NO event surface — `getPlaybackManifest` returns playlist URLs only. Timeline
|
|
18901
|
+
* events (motion/object/audio) come from `pipelineAnalytics` (durable SQLite
|
|
18902
|
+
* rows); the recorder's internal EventMap markers are ephemeral in-RAM
|
|
18903
|
+
* annotations that are not exposed here and must not be treated as an event
|
|
18904
|
+
* feed. Event<->footage joins are by time, padded with the shared `EVENT_PAD_MS`
|
|
18905
|
+
* (`interfaces/recording-config.ts`).
|
|
18906
|
+
*/
|
|
18147
18907
|
var RecordingStatusSchema = object({
|
|
18148
18908
|
deviceId: number(),
|
|
18149
18909
|
enabled: boolean(),
|
|
@@ -19813,6 +20573,12 @@ Object.freeze({
|
|
|
19813
20573
|
addonId: null,
|
|
19814
20574
|
access: "view"
|
|
19815
20575
|
},
|
|
20576
|
+
"deviceManager.getRoleDisplayDefaults": {
|
|
20577
|
+
capName: "device-manager",
|
|
20578
|
+
capScope: "system",
|
|
20579
|
+
addonId: null,
|
|
20580
|
+
access: "view"
|
|
20581
|
+
},
|
|
19816
20582
|
"deviceManager.getSettingsSchema": {
|
|
19817
20583
|
capName: "device-manager",
|
|
19818
20584
|
capScope: "system",
|
|
@@ -19963,6 +20729,12 @@ Object.freeze({
|
|
|
19963
20729
|
addonId: null,
|
|
19964
20730
|
access: "create"
|
|
19965
20731
|
},
|
|
20732
|
+
"deviceManager.setDisplay": {
|
|
20733
|
+
capName: "device-manager",
|
|
20734
|
+
capScope: "system",
|
|
20735
|
+
addonId: null,
|
|
20736
|
+
access: "create"
|
|
20737
|
+
},
|
|
19966
20738
|
"deviceManager.setIntegrationId": {
|
|
19967
20739
|
capName: "device-manager",
|
|
19968
20740
|
capScope: "system",
|
|
@@ -20005,6 +20777,12 @@ Object.freeze({
|
|
|
20005
20777
|
addonId: null,
|
|
20006
20778
|
access: "create"
|
|
20007
20779
|
},
|
|
20780
|
+
"deviceManager.setRoleDisplayDefaults": {
|
|
20781
|
+
capName: "device-manager",
|
|
20782
|
+
capScope: "system",
|
|
20783
|
+
addonId: null,
|
|
20784
|
+
access: "create"
|
|
20785
|
+
},
|
|
20008
20786
|
"deviceManager.setStreamProfileMap": {
|
|
20009
20787
|
capName: "device-manager",
|
|
20010
20788
|
capScope: "system",
|
|
@@ -23203,4 +23981,4 @@ function defaultDeviceFor(id) {
|
|
|
23203
23981
|
return def(id).defaultDevice;
|
|
23204
23982
|
}
|
|
23205
23983
|
//#endregion
|
|
23206
|
-
export {
|
|
23984
|
+
export { parseProfileBrokerId as $, motionDetectionCapability as A, errMsg as B, defineCustomActions as C, mapAudioLabelToMacro as D, hfModelUrl as E, runtimeDevices as F, EventCategory as G, CAM_PROFILE_ORDER as H, storageEvictableCapability as I, createEvent as J, asJsonObject as K, streamBrokerCapability as L, pipelineExecutorCapability as M, pipelineRunnerCapability as N, maskUrlCredentials as O, recordingCapability as P, parseJsonUnknown as Q, supportedRuntimes as R, defaultDeviceFor as S, evaluateZoneRules as T, DeviceFeature as U, BaseAddon as V, DeviceType as W, makeProfileBrokerId as X, hydrateSchema as Y, makeSourceBrokerId as Z, audioAnalyzerCapability as _, COCO_TO_MACRO as a, discriminatedUnion as at, customAction as b, EVENT_PAD_MS as c, number as ct, HWACCEL_OPTIONS as d, string as dt, selectAssignedProfileSlots as et, RecordingConfigSchema as f, union as ft, audioAnalysisCapability as g, addonWidgetsSourceCapability as h, COCO_80_LABELS as i, boolean as it, nodePin as j, migrateConfigToBands as k, EncodeProfileSchema as l, object as lt, YAMNET_TO_MACRO as m, AUDIO_BACKEND_CHOICES as n, _enum as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, lazy as ot, RingBuffer as p, createDurableState as q, AUDIO_MACRO_LABELS as r, array as rt, DEFAULT_DECODER_HWACCEL_CONFIG as s, literal as st, APPLE_SA_TO_MACRO as t, sleep as tt, HF_BASE_URL as u, record as ut, audioCodecCapability as v, detectionPipelineCapability as w, decoderCapability as x, cameraStreamsCapability as y, webrtcSessionCapability as z };
|