@camstack/addon-pipeline 1.2.79 → 1.2.81
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-utils-BZQxAJ1G.js → addon-utils-CQFlZXSn.js} +1 -1
- package/dist/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +1 -1
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +2 -2
- package/dist/{dist-BUIpqu3E.js → dist-B57MztMq.js} +276 -14
- package/dist/{dist-BfTf6doa.mjs → dist-DGp0dRiq.mjs} +259 -15
- package/dist/{event-loop-stall-monitor-CmrHj0i9.mjs → event-loop-stall-monitor-8vYH44kg.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-CGLQP0by.js → event-loop-stall-monitor-DPA6Pu_h.js} +1 -1
- package/dist/{lazy-sharp-BZVhL9Lw.js → lazy-sharp-BMgRSV9x.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +26 -4
- package/dist/pipeline-runner/index.mjs +25 -3
- package/dist/recorder/index.js +62 -5
- package/dist/recorder/index.mjs +61 -4
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BohtrVou.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cb8ynph1.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B2scqOH7.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-Dxr14lIu.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DEps-9qh.mjs} +1 -1
- package/dist/stream-broker/{hostInit-pDANS0x0.mjs → hostInit-GJipMxBe.mjs} +2 -2
- package/dist/stream-broker/index.js +224 -1
- package/dist/stream-broker/index.mjs +224 -1
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-BaLcYcOo.js → worker-protocol-4L4SbSAo.js} +1 -1
- package/dist/{worker-protocol-BdOv9Ujl.mjs → worker-protocol-_e84lGuR.mjs} +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-y8ehJPoY.mjs +0 -26
|
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-B57MztMq.js");
|
|
6
6
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
7
|
-
const require_addon_utils = require("../addon-utils-
|
|
7
|
+
const require_addon_utils = require("../addon-utils-CQFlZXSn.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_dist.__toESM(node_path);
|
|
10
10
|
let node_fs = require("node:fs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, h as HF_BASE_URL, ht as hydrateSchema, it as errMsg, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, ut as BaseAddon } from "../dist-DGp0dRiq.mjs";
|
|
3
3
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
4
4
|
import { i as downloadFile } from "../addon-utils-A2S9D7pu.mjs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
5
|
+
const require_dist = require("../dist-B57MztMq.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DPA6Pu_h.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-BMgRSV9x.js");
|
|
8
8
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
9
|
+
const require_addon_utils = require("../addon-utils-CQFlZXSn.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $ as
|
|
3
|
-
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-
|
|
2
|
+
import { $ as runtimeDevices$1, B as enumerateInferenceDevices, Ct as sleep, Ft as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Nt as string, Pt as union, Tt as array, V as evaluateZoneRules, bt as parseJsonUnknown, d as DEVICE_BACKEND_TO_FORMAT, ht as hydrateSchema, it as errMsg, jt as object, mt as createEvent, nt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, ut as BaseAddon, w as YAMNET_TO_MACRO, yt as nodePin } from "../dist-DGp0dRiq.mjs";
|
|
3
|
+
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-8vYH44kg.mjs";
|
|
4
4
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
5
5
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
6
6
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-A2S9D7pu.mjs";
|
|
@@ -13727,6 +13727,18 @@ var LlmGenerateBaseInputSchema = object({
|
|
|
13727
13727
|
* Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
|
|
13728
13728
|
* watchdog — operator decision #3).
|
|
13729
13729
|
*/
|
|
13730
|
+
/**
|
|
13731
|
+
* A companion artifact that MUST land beside the main GGUF: the `mmproj`
|
|
13732
|
+
* projector of a vision model, or shards 2..N of a split GGUF. Carried on the
|
|
13733
|
+
* REF rather than looked up at install time, so what the operator approved in
|
|
13734
|
+
* the preview is exactly what the node downloads.
|
|
13735
|
+
*/
|
|
13736
|
+
var ManagedModelExtraFileSchema = object({
|
|
13737
|
+
url: string(),
|
|
13738
|
+
filename: string(),
|
|
13739
|
+
sizeBytes: number(),
|
|
13740
|
+
sha256: string().optional()
|
|
13741
|
+
});
|
|
13730
13742
|
var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
13731
13743
|
object({
|
|
13732
13744
|
kind: literal("catalog"),
|
|
@@ -13735,7 +13747,11 @@ var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
|
13735
13747
|
object({
|
|
13736
13748
|
kind: literal("url"),
|
|
13737
13749
|
url: string(),
|
|
13738
|
-
sha256: string().optional()
|
|
13750
|
+
sha256: string().optional(),
|
|
13751
|
+
/** Picker/status label; the file basename when absent. */
|
|
13752
|
+
label: string().optional(),
|
|
13753
|
+
sizeBytes: number().optional(),
|
|
13754
|
+
extraFiles: array(ManagedModelExtraFileSchema).optional()
|
|
13739
13755
|
}),
|
|
13740
13756
|
object({
|
|
13741
13757
|
kind: literal("path"),
|
|
@@ -13796,11 +13812,39 @@ var ManagedRuntimeConfigSchema = object({
|
|
|
13796
13812
|
"q4_1",
|
|
13797
13813
|
"q4_0"
|
|
13798
13814
|
]).optional(),
|
|
13815
|
+
/**
|
|
13816
|
+
* Escape hatch for llama-server flags this schema does NOT model — `--jinja`
|
|
13817
|
+
* (which most vision chat templates need and some language-only models
|
|
13818
|
+
* dislike), `--cont-batching`, `--rope-scaling`, …
|
|
13819
|
+
*
|
|
13820
|
+
* It is NOT a second place to set the flags above. A token that collides
|
|
13821
|
+
* with a typed field is REJECTED at start, naming the field that owns it
|
|
13822
|
+
* (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
|
|
13823
|
+
* the "two switches that disagree" failure this repo has already shipped
|
|
13824
|
+
* twice (D62).
|
|
13825
|
+
*/
|
|
13826
|
+
extraArgs: array(string()).default([]),
|
|
13799
13827
|
/** Else lazy: first generate boots it. */
|
|
13800
13828
|
autoStart: boolean().default(false),
|
|
13801
13829
|
/** 0 = never; frees RAM after quiet periods. */
|
|
13802
13830
|
idleStopMinutes: number().int().default(30)
|
|
13803
13831
|
});
|
|
13832
|
+
/**
|
|
13833
|
+
* Where a multi-GB install currently is. A single 0..1 fraction cannot answer
|
|
13834
|
+
* "is it stuck?" for an install that is three files (shards + mmproj) followed
|
|
13835
|
+
* by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
|
|
13836
|
+
* node looked hung. Phase + file + bytes is the smallest shape that does.
|
|
13837
|
+
*/
|
|
13838
|
+
var LlmDownloadProgressSchema = object({
|
|
13839
|
+
phase: _enum(["downloading", "verifying"]),
|
|
13840
|
+
/** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
|
|
13841
|
+
file: string(),
|
|
13842
|
+
fileIndex: number().int(),
|
|
13843
|
+
fileCount: number().int(),
|
|
13844
|
+
/** Across the WHOLE install, not the current file. */
|
|
13845
|
+
downloadedBytes: number(),
|
|
13846
|
+
totalBytes: number().optional()
|
|
13847
|
+
});
|
|
13804
13848
|
var LlmRuntimeStatusSchema = object({
|
|
13805
13849
|
/** Status is ALWAYS node-qualified. */
|
|
13806
13850
|
nodeId: string(),
|
|
@@ -13817,6 +13861,8 @@ var LlmRuntimeStatusSchema = object({
|
|
|
13817
13861
|
modelPath: string().optional(),
|
|
13818
13862
|
modelId: string().optional(),
|
|
13819
13863
|
downloadProgress: number().min(0).max(1).optional(),
|
|
13864
|
+
/** Detail behind `downloadProgress`; present for the same lifetime. */
|
|
13865
|
+
download: LlmDownloadProgressSchema.optional(),
|
|
13820
13866
|
lastError: string().optional(),
|
|
13821
13867
|
crashesInWindow: number(),
|
|
13822
13868
|
/** Child RSS (sampled best-effort). */
|
|
@@ -13827,7 +13873,14 @@ var LlmNodeModelSchema = object({
|
|
|
13827
13873
|
file: string(),
|
|
13828
13874
|
sizeBytes: number(),
|
|
13829
13875
|
catalogId: string().optional(),
|
|
13830
|
-
installedAt: number().optional()
|
|
13876
|
+
installedAt: number().optional(),
|
|
13877
|
+
/**
|
|
13878
|
+
* Absolute path on the node. Present so a file that is on disk but matches
|
|
13879
|
+
* no catalog entry — a custom Hugging Face install, or a GGUF the operator
|
|
13880
|
+
* copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
|
|
13881
|
+
* it the picker could list such a file and do nothing with it.
|
|
13882
|
+
*/
|
|
13883
|
+
path: string().optional()
|
|
13831
13884
|
});
|
|
13832
13885
|
var LlmRuntimeDiskUsageSchema = object({
|
|
13833
13886
|
nodeId: string(),
|
|
@@ -13973,6 +14026,36 @@ var ManagedModelCatalogEntrySchema = object({
|
|
|
13973
14026
|
/** Vision models: companion projector file. */
|
|
13974
14027
|
mmprojUrl: string().optional()
|
|
13975
14028
|
});
|
|
14029
|
+
/**
|
|
14030
|
+
* The outcome of turning one operator-typed Hugging Face reference into a
|
|
14031
|
+
* download plan. A RESULT, never a throw: "this repo has 24 quantizations and
|
|
14032
|
+
* I will not pick for you" is a normal answer the UI has to render, not an
|
|
14033
|
+
* exception.
|
|
14034
|
+
*
|
|
14035
|
+
* `candidates` is the whole reason the refusal is usable — every string in it
|
|
14036
|
+
* is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
|
|
14037
|
+
*/
|
|
14038
|
+
var HfModelResolutionSchema = discriminatedUnion("ok", [object({
|
|
14039
|
+
ok: literal(true),
|
|
14040
|
+
/** Ready to hand to `installModel` unchanged. */
|
|
14041
|
+
model: ManagedModelRefSchema,
|
|
14042
|
+
label: string(),
|
|
14043
|
+
repo: string(),
|
|
14044
|
+
quantization: string(),
|
|
14045
|
+
purpose: _enum(["text", "vision"]),
|
|
14046
|
+
totalBytes: number(),
|
|
14047
|
+
/** mmproj + shards, for the preview: an operator approving 23 GB should
|
|
14048
|
+
* see that 0.9 GB of it is a projector they did not name. */
|
|
14049
|
+
extraFilenames: array(string())
|
|
14050
|
+
}), object({
|
|
14051
|
+
ok: literal(false),
|
|
14052
|
+
code: string(),
|
|
14053
|
+
message: string(),
|
|
14054
|
+
candidates: array(string()).optional(),
|
|
14055
|
+
/** Set when the refusal was only the ceiling: re-calling with
|
|
14056
|
+
* `maxBytes: requiredBytes` is the operator's explicit override. */
|
|
14057
|
+
requiredBytes: number().optional()
|
|
14058
|
+
})]);
|
|
13976
14059
|
var LlmRuntimeNodeSchema = object({
|
|
13977
14060
|
nodeId: string(),
|
|
13978
14061
|
reachable: boolean(),
|
|
@@ -14009,6 +14092,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
|
|
|
14009
14092
|
consumer: string().optional(),
|
|
14010
14093
|
profileId: string().optional()
|
|
14011
14094
|
}), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
|
|
14095
|
+
/** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
|
|
14096
|
+
* `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
|
|
14097
|
+
ref: string(),
|
|
14098
|
+
/** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
|
|
14099
|
+
maxBytes: number().positive().optional()
|
|
14100
|
+
}), HfModelResolutionSchema, {
|
|
14101
|
+
kind: "mutation",
|
|
14102
|
+
auth: "admin"
|
|
14103
|
+
}), method(object({
|
|
14012
14104
|
nodeId: string(),
|
|
14013
14105
|
model: ManagedModelRefSchema
|
|
14014
14106
|
}), _void(), {
|
|
@@ -19636,6 +19728,17 @@ var maxSessionHoldMsField = {
|
|
|
19636
19728
|
default: 12e4,
|
|
19637
19729
|
step: 5e3
|
|
19638
19730
|
};
|
|
19731
|
+
/**
|
|
19732
|
+
* Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
|
|
19733
|
+
* 5s so a rearm can never degenerate into per-event stream churn; default 90s
|
|
19734
|
+
* comfortably outlives the gap between two PIR wakes on a battery camera.
|
|
19735
|
+
*/
|
|
19736
|
+
var audioMotionWindowMsField = {
|
|
19737
|
+
min: 5e3,
|
|
19738
|
+
max: 6e5,
|
|
19739
|
+
default: 9e4,
|
|
19740
|
+
step: 5e3
|
|
19741
|
+
};
|
|
19639
19742
|
var motionFpsField = {
|
|
19640
19743
|
min: 1,
|
|
19641
19744
|
max: 30,
|
|
@@ -19812,6 +19915,27 @@ var RunnerCameraConfigSchema = object({
|
|
|
19812
19915
|
* resolved `CameraDetectionConfig`.
|
|
19813
19916
|
*/
|
|
19814
19917
|
maxSessionHoldMs: number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
|
|
19918
|
+
/**
|
|
19919
|
+
* Orchestrator-side quiet period (ms) that closes an `audioMode:
|
|
19920
|
+
* 'on-motion'` audio window, measured from the LAST motion event.
|
|
19921
|
+
*
|
|
19922
|
+
* This exists because the falling edge cannot be relied on. Camera-native
|
|
19923
|
+
* providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
|
|
19924
|
+
* its email-push SMTP path both emit `detected: true` and never the
|
|
19925
|
+
* counterpart); only the frame-diff analyzer emits falls. So on an
|
|
19926
|
+
* onboard-only camera a window that closed only on `detected: false` never
|
|
19927
|
+
* closed at all, and `on-motion` silently behaved as `always-on` — on a
|
|
19928
|
+
* battery camera, the one failure mode the mode exists to prevent.
|
|
19929
|
+
*
|
|
19930
|
+
* Every motion event rearms this timer WITHOUT restarting the stream, so a
|
|
19931
|
+
* burst of re-fires costs nothing. A falling edge, when one does arrive,
|
|
19932
|
+
* still closes earlier via `motionCooldownMs` — whichever comes first wins.
|
|
19933
|
+
*
|
|
19934
|
+
* Not consumed by the runner: carried here so it shares the per-camera
|
|
19935
|
+
* device-settings surface with `motionCooldownMs`, exactly like
|
|
19936
|
+
* `maxSessionHoldMs`.
|
|
19937
|
+
*/
|
|
19938
|
+
audioMotionWindowMs: number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
|
|
19815
19939
|
motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
|
|
19816
19940
|
detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
|
|
19817
19941
|
motionStreamId: string(),
|
|
@@ -19907,7 +20031,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
19907
20031
|
*/
|
|
19908
20032
|
inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
|
|
19909
20033
|
});
|
|
19910
|
-
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
20034
|
+
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
19911
20035
|
/**
|
|
19912
20036
|
* Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
|
|
19913
20037
|
* load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
|
|
@@ -22682,6 +22806,25 @@ var BatteryStatusSchema = object({
|
|
|
22682
22806
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
22683
22807
|
lastUpdated: number(),
|
|
22684
22808
|
/**
|
|
22809
|
+
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
22810
|
+
* completed firmware round-trip, an observed wake, or an inbound push
|
|
22811
|
+
* (firmware event, email). `0`/absent = never since this slice was born.
|
|
22812
|
+
*
|
|
22813
|
+
* This is the ONLY input that separates "asleep" from "gone", and it is
|
|
22814
|
+
* fed exclusively by PASSIVE signals: nothing may write it by reaching
|
|
22815
|
+
* for the radio, because a poll that confirms reachability is the same
|
|
22816
|
+
* poll that drains the battery. See {@link deriveBatteryPresence} — the
|
|
22817
|
+
* single derivation every consumer must use; no surface computes its own.
|
|
22818
|
+
*
|
|
22819
|
+
* It is deliberately NOT a clock in the
|
|
22820
|
+
* `scripts/check-runtime-state-durability.ts` sense: it is the
|
|
22821
|
+
* observation itself, and it is the only thing a 30-hour silence is
|
|
22822
|
+
* visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
|
|
22823
|
+
* Reolink provider) so a value that means "recently" cannot cost a
|
|
22824
|
+
* SQLite commit per round-trip.
|
|
22825
|
+
*/
|
|
22826
|
+
lastContactAt: number().optional(),
|
|
22827
|
+
/**
|
|
22685
22828
|
* True when the source is a BINARY low-battery indicator (HA
|
|
22686
22829
|
* `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
|
|
22687
22830
|
* charge level — `percentage` is then a coarse stand-in (100 = normal,
|
|
@@ -22690,17 +22833,84 @@ var BatteryStatusSchema = object({
|
|
|
22690
22833
|
*/
|
|
22691
22834
|
binary: boolean().optional()
|
|
22692
22835
|
});
|
|
22693
|
-
|
|
22694
|
-
|
|
22695
|
-
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
|
|
22836
|
+
var batteryCapability = {
|
|
22837
|
+
name: "battery",
|
|
22838
|
+
scope: "device",
|
|
22839
|
+
deviceNative: true,
|
|
22840
|
+
mode: "singleton",
|
|
22841
|
+
deviceTypes: [
|
|
22842
|
+
DeviceType.Camera,
|
|
22843
|
+
DeviceType.Sensor,
|
|
22844
|
+
DeviceType.Button,
|
|
22845
|
+
DeviceType.Switch
|
|
22846
|
+
],
|
|
22847
|
+
methods: {
|
|
22848
|
+
/**
|
|
22849
|
+
* Explicitly wake the camera from low-power sleep ahead of a
|
|
22850
|
+
* streaming session start. Consumers that initiate a stream
|
|
22851
|
+
* against a sleeping battery cam (HomeKit Secure Video, Alexa
|
|
22852
|
+
* RTCSession, snapshot wrappers) call this with a short timeout
|
|
22853
|
+
* before establishing the media pipeline — the broker's own
|
|
22854
|
+
* passive wake-on-dial works but adds 5–7 seconds to first-frame,
|
|
22855
|
+
* during which the consumer renders a black screen. Pre-waking
|
|
22856
|
+
* compresses that gap.
|
|
22857
|
+
*
|
|
22858
|
+
* Returns `awoke: true` when the firmware acknowledged the wake
|
|
22859
|
+
* before `timeoutMs`. Returns `awoke: false` when it timed out OR
|
|
22860
|
+
* the cap surface is unavailable (no Baichuan / firmware
|
|
22861
|
+
* channel); the caller should still attempt the stream — the
|
|
22862
|
+
* passive broker wake remains as fallback.
|
|
22863
|
+
*/
|
|
22864
|
+
wakeForStream: method(object({
|
|
22865
|
+
deviceId: number(),
|
|
22866
|
+
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
22867
|
+
timeoutMs: number().int().min(500).max(3e4).default(8e3)
|
|
22868
|
+
}), object({
|
|
22869
|
+
awoke: boolean(),
|
|
22870
|
+
durationMs: number()
|
|
22871
|
+
}), { kind: "mutation" }) },
|
|
22872
|
+
events: {
|
|
22873
|
+
/**
|
|
22874
|
+
* Emitted whenever the cached status changes (firmware push OR
|
|
22875
|
+
* poll observes a delta). The DeviceEventPropagator mirrors this
|
|
22876
|
+
* event on the parent chain — subscribing to a camera's source
|
|
22877
|
+
* receives battery events from child accessories automatically.
|
|
22878
|
+
*/
|
|
22879
|
+
onStatusChanged: { data: object({
|
|
22880
|
+
deviceId: number(),
|
|
22881
|
+
status: BatteryStatusSchema
|
|
22882
|
+
}) } },
|
|
22883
|
+
status: {
|
|
22884
|
+
schema: BatteryStatusSchema,
|
|
22885
|
+
kind: "push",
|
|
22886
|
+
empty: {
|
|
22887
|
+
percentage: 0,
|
|
22888
|
+
charging: "none",
|
|
22889
|
+
sleeping: false,
|
|
22890
|
+
lastUpdated: 0
|
|
22891
|
+
}
|
|
22892
|
+
},
|
|
22893
|
+
/**
|
|
22894
|
+
* Runtime-state slice — every provider that registers this cap
|
|
22895
|
+
* stores the same shape under `device.runtimeState[battery]`.
|
|
22896
|
+
* Cross-provider uniformity: a Reolink Argus, a Frigate sensor
|
|
22897
|
+
* proxy, an ONVIF battery cam all read/write the same keys.
|
|
22898
|
+
* Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
|
|
22899
|
+
* via `device.runtimeState.getCapState('battery')` regardless of
|
|
22900
|
+
* the underlying driver.
|
|
22901
|
+
*/
|
|
22902
|
+
runtimeState: BatteryStatusSchema,
|
|
22903
|
+
/**
|
|
22904
|
+
* Runtime-state durability: **restored** — a sleeping battery camera may not report for hours; the restored percentage is the only thing the UI and the sleep gate have. Zero churn once `lastUpdated` is excluded — 526 writes, 0 value changes, in 25 minutes.
|
|
22905
|
+
*
|
|
22906
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
22907
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
22908
|
+
*/
|
|
22909
|
+
durability: "restored",
|
|
22910
|
+
/** Clock fields: written, but excluded from the compare that decides
|
|
22911
|
+
* whether persisting is worth a SQLite commit. */
|
|
22912
|
+
volatileStateFields: ["lastUpdated"]
|
|
22913
|
+
};
|
|
22704
22914
|
object({
|
|
22705
22915
|
on: boolean(),
|
|
22706
22916
|
/** Ms epoch of the last transition. 0 if never observed. */
|
|
@@ -27111,6 +27321,16 @@ var CamStreamDescriptorSchema = object({
|
|
|
27111
27321
|
/** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
|
|
27112
27322
|
metadata: record(string(), unknown()).optional()
|
|
27113
27323
|
});
|
|
27324
|
+
object({
|
|
27325
|
+
/** The descriptors as last built from a real camera response. Never a guess:
|
|
27326
|
+
* a failed or refused build writes NOTHING, so a restored catalog is always
|
|
27327
|
+
* one the camera itself once produced. */
|
|
27328
|
+
descriptors: array(CamStreamDescriptorSchema),
|
|
27329
|
+
/** Ms epoch of the build that produced {@link descriptors}. Lets the wake
|
|
27330
|
+
* path decide whether the camera's own awake window is worth spending on a
|
|
27331
|
+
* re-read. */
|
|
27332
|
+
lastFetchedAt: number()
|
|
27333
|
+
});
|
|
27114
27334
|
DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly());
|
|
27115
27335
|
/** One of the camera's stream profiles. */
|
|
27116
27336
|
var StreamProfileSchema = _enum([
|
|
@@ -27995,6 +28215,24 @@ AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, Accessor
|
|
|
27995
28215
|
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
27996
28216
|
new Set(Object.values(DeviceType));
|
|
27997
28217
|
DeviceFeature.BatteryOperated;
|
|
28218
|
+
/**
|
|
28219
|
+
* THE derivation. One crop rectangle, one presence verdict — see D52 for why
|
|
28220
|
+
* this repo insists a derived value has exactly one implementation.
|
|
28221
|
+
*
|
|
28222
|
+
* `undefined` status ⇒ `sleeping`. A device with no slice has made no claim,
|
|
28223
|
+
* and the caller decides separately whether it is even battery-operated
|
|
28224
|
+
* (`DeviceFeature.BatteryOperated`); this function never answers that
|
|
28225
|
+
* question, only what a battery device is doing.
|
|
28226
|
+
*/
|
|
28227
|
+
function deriveBatteryPresence(input) {
|
|
28228
|
+
const status = input.status;
|
|
28229
|
+
if (!status) return "sleeping";
|
|
28230
|
+
if (status.sleeping !== true) return "awake";
|
|
28231
|
+
const lastContactAt = status.lastContactAt;
|
|
28232
|
+
if (typeof lastContactAt !== "number" || lastContactAt <= 0) return "sleeping";
|
|
28233
|
+
const budget = input.unreachableAfterMs ?? 216e5;
|
|
28234
|
+
return input.nowMs - lastContactAt > budget ? "unreachable" : "sleeping";
|
|
28235
|
+
}
|
|
27998
28236
|
Object.freeze({
|
|
27999
28237
|
"accessories.setChildHidden": {
|
|
28000
28238
|
capName: "accessories",
|
|
@@ -30144,6 +30382,12 @@ Object.freeze({
|
|
|
30144
30382
|
addonId: null,
|
|
30145
30383
|
access: "view"
|
|
30146
30384
|
},
|
|
30385
|
+
"llm.resolveModelRef": {
|
|
30386
|
+
capName: "llm",
|
|
30387
|
+
capScope: "system",
|
|
30388
|
+
addonId: null,
|
|
30389
|
+
access: "create"
|
|
30390
|
+
},
|
|
30147
30391
|
"llm.setDefault": {
|
|
30148
30392
|
capName: "llm",
|
|
30149
30393
|
capScope: "system",
|
|
@@ -36330,6 +36574,12 @@ Object.defineProperty(exports, "BaseAddon", {
|
|
|
36330
36574
|
return BaseAddon;
|
|
36331
36575
|
}
|
|
36332
36576
|
});
|
|
36577
|
+
Object.defineProperty(exports, "BatteryStatusSchema", {
|
|
36578
|
+
enumerable: true,
|
|
36579
|
+
get: function() {
|
|
36580
|
+
return BatteryStatusSchema;
|
|
36581
|
+
}
|
|
36582
|
+
});
|
|
36333
36583
|
Object.defineProperty(exports, "CAM_PROFILE_ORDER", {
|
|
36334
36584
|
enumerable: true,
|
|
36335
36585
|
get: function() {
|
|
@@ -36522,6 +36772,12 @@ Object.defineProperty(exports, "audioAnalyzerCapability", {
|
|
|
36522
36772
|
return audioAnalyzerCapability;
|
|
36523
36773
|
}
|
|
36524
36774
|
});
|
|
36775
|
+
Object.defineProperty(exports, "batteryCapability", {
|
|
36776
|
+
enumerable: true,
|
|
36777
|
+
get: function() {
|
|
36778
|
+
return batteryCapability;
|
|
36779
|
+
}
|
|
36780
|
+
});
|
|
36525
36781
|
Object.defineProperty(exports, "boolean", {
|
|
36526
36782
|
enumerable: true,
|
|
36527
36783
|
get: function() {
|
|
@@ -36570,6 +36826,12 @@ Object.defineProperty(exports, "defineCustomActions", {
|
|
|
36570
36826
|
return defineCustomActions;
|
|
36571
36827
|
}
|
|
36572
36828
|
});
|
|
36829
|
+
Object.defineProperty(exports, "deriveBatteryPresence", {
|
|
36830
|
+
enumerable: true,
|
|
36831
|
+
get: function() {
|
|
36832
|
+
return deriveBatteryPresence;
|
|
36833
|
+
}
|
|
36834
|
+
});
|
|
36573
36835
|
Object.defineProperty(exports, "deriveDetailCropRect", {
|
|
36574
36836
|
enumerable: true,
|
|
36575
36837
|
get: function() {
|