@camstack/addon-decoder-nodeav 1.1.8 → 1.1.10
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/index.js +687 -532
- package/dist/index.mjs +673 -528
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,276 +5,6 @@ Object.defineProperties(exports, {
|
|
|
5
5
|
let _camstack_shm_ring = require("@camstack/shm-ring");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
|
-
//#region src/frame-ring-sink.ts
|
|
9
|
-
/**
|
|
10
|
-
* `DecoderFrameRingSink` — the decoder's shared-memory write side (Phase 5 / D9).
|
|
11
|
-
*
|
|
12
|
-
* When a decoder session is configured with `frameSink: 'shm'`, the decoder
|
|
13
|
-
* **owns** the shared-memory ring segment for that stream: it creates the
|
|
14
|
-
* segment on the first decoded frame (when the output geometry is known),
|
|
15
|
-
* writes every subsequent decoded frame into the ring via a `FrameRingWriter`,
|
|
16
|
-
* and closes + unlinks the segment when the session is destroyed.
|
|
17
|
-
*
|
|
18
|
-
* What leaves the decoder is no longer the pixel `Buffer` — it is a tiny,
|
|
19
|
-
* serialisable `FrameHandle` (`FrameRingWriter.writeFrame`'s return value).
|
|
20
|
-
* Same-host consumers (motion, detection, the WebRTC encoder) open the same
|
|
21
|
-
* segment with a `FrameRingReader` and read the pixels zero-copy.
|
|
22
|
-
*
|
|
23
|
-
* ## Lazy segment creation
|
|
24
|
-
*
|
|
25
|
-
* The segment cannot be sized until the first frame: `slotByteLength` is
|
|
26
|
-
* `width × height × bytesPerPixel`, and the output dimensions are only known
|
|
27
|
-
* once the scaler has produced its first `dstFrame`. So `writeFrame` is a
|
|
28
|
-
* no-op-until-armed: the first call sizes + creates the segment, every later
|
|
29
|
-
* call writes into it.
|
|
30
|
-
*
|
|
31
|
-
* ## Resolution-change decision
|
|
32
|
-
*
|
|
33
|
-
* A live camera stream can change resolution mid-stream (the decoder's scaler
|
|
34
|
-
* is rebuilt on a config toggle, or the source renegotiates). The slot is
|
|
35
|
-
* sized for the **first** frame's geometry. A later frame that no longer fits
|
|
36
|
-
* the slot triggers a **segment re-create**: the old segment is closed +
|
|
37
|
-
* unlinked and a fresh, larger segment is created under a new generation-tagged
|
|
38
|
-
* name. This is simpler and leak-free versus over-allocating slots for a
|
|
39
|
-
* worst-case 4K frame on every stream; resolution changes on a live camera are
|
|
40
|
-
* rare, and a brief gap while consumers re-open the segment is acceptable
|
|
41
|
-
* (latest-wins — a missed frame is correct behaviour).
|
|
42
|
-
*/
|
|
43
|
-
/**
|
|
44
|
-
* Per-ring shared-memory budget (MB) — the slot count is derived per-resolution
|
|
45
|
-
* from this budget via {@link deriveSlotCount}, so a 360p stream gets many
|
|
46
|
-
* slots and a 4K stream a few, both inside the same memory footprint.
|
|
47
|
-
*
|
|
48
|
-
* Read ONCE at module load from `CAMSTACK_SHM_RING_BUDGET_MB`; a non-finite or
|
|
49
|
-
* non-positive value falls back to the 16 MB default.
|
|
50
|
-
*
|
|
51
|
-
* The default is deliberately small (16 MB) so many concurrent per-camera rings
|
|
52
|
-
* fit inside a bounded `/dev/shm`. The decoder output is capped at 640px wide, so
|
|
53
|
-
* a slot is ≤ ~920 KB and 16 MB still yields ~17–70 latest-wins slots. A ring
|
|
54
|
-
* segment larger than the container's `/dev/shm` tmpfs backing (Docker default is
|
|
55
|
-
* only 64 MB) faults an **uncatchable SIGBUS** on write past `st_size` — the old
|
|
56
|
-
* 128 MB default overflowed a 64 MB `/dev/shm` and crashed the decoder on 8MP
|
|
57
|
-
* streams. Pair this with a `--shm-size` that scales with concurrent-decode load.
|
|
58
|
-
*/
|
|
59
|
-
var RING_BUDGET_MB = (() => {
|
|
60
|
-
const raw = Number(process.env["CAMSTACK_SHM_RING_BUDGET_MB"]);
|
|
61
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 16;
|
|
62
|
-
})();
|
|
63
|
-
/** {@link RING_BUDGET_MB} in bytes — the budget passed to `deriveSlotCount`. */
|
|
64
|
-
var RING_BUDGET_BYTES = RING_BUDGET_MB * 1024 * 1024;
|
|
65
|
-
/** A unique, stable shared-memory segment name for a decoder stream.
|
|
66
|
-
*
|
|
67
|
-
* macOS POSIX shm names are capped at ~31 characters (`PSHMNAMLEN`). A
|
|
68
|
-
* `camstack.frames.<deviceId>.<streamId>` scheme overflows that for realistic
|
|
69
|
-
* ids, so the sink uses a short, collision-resistant scheme instead:
|
|
70
|
-
* `csf.<base36 hash>.<gen>`. The hash folds the device id, the session tag
|
|
71
|
-
* and a per-process random salt; the generation suffix makes a re-created
|
|
72
|
-
* segment (resolution change) a distinct name so a stale consumer mapping is
|
|
73
|
-
* never silently reused.
|
|
74
|
-
*/
|
|
75
|
-
/**
|
|
76
|
-
* Shared prefix for every decoder shm segment name. Startup orphan reclamation
|
|
77
|
-
* (`purgeOrphanSegments`) keys off this to find segments left behind by a
|
|
78
|
-
* crashed prior instance.
|
|
79
|
-
*/
|
|
80
|
-
var SEGMENT_NAME_PREFIX = "csf.";
|
|
81
|
-
function makeSegmentName(seed, generation) {
|
|
82
|
-
let hash = 5381;
|
|
83
|
-
for (let i = 0; i < seed.length; i += 1) hash = (hash << 5) + hash + seed.charCodeAt(i) | 0;
|
|
84
|
-
return `${SEGMENT_NAME_PREFIX}${(hash >>> 0).toString(36)}.${generation}`;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* The decoder-side owner of one stream's shared-memory frame ring.
|
|
88
|
-
*
|
|
89
|
-
* Not constructed until a session actually uses the shm sink; the segment
|
|
90
|
-
* itself is created lazily on the first `writeFrame`.
|
|
91
|
-
*/
|
|
92
|
-
var DecoderFrameRingSink = class {
|
|
93
|
-
seed;
|
|
94
|
-
logger;
|
|
95
|
-
nodeId;
|
|
96
|
-
segment = null;
|
|
97
|
-
writer = null;
|
|
98
|
-
segmentName = null;
|
|
99
|
-
slotByteLength = 0;
|
|
100
|
-
generation = 0;
|
|
101
|
-
destroyed = false;
|
|
102
|
-
/** Frames committed into the ring across this sink's lifetime (all generations). */
|
|
103
|
-
framesWritten = 0;
|
|
104
|
-
constructor(options) {
|
|
105
|
-
const salt = Math.random().toString(36).slice(2, 8);
|
|
106
|
-
this.seed = `${options.seed}.${salt}`;
|
|
107
|
-
this.logger = options.logger;
|
|
108
|
-
this.nodeId = options.nodeId;
|
|
109
|
-
}
|
|
110
|
-
/** Whether a segment has been created (i.e. at least one frame written). */
|
|
111
|
-
get isArmed() {
|
|
112
|
-
return this.writer !== null;
|
|
113
|
-
}
|
|
114
|
-
/** The current segment name, or `null` before the first frame. */
|
|
115
|
-
get currentSegmentName() {
|
|
116
|
-
return this.segmentName;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Write one decoded frame into the ring and return its `FrameHandle`.
|
|
120
|
-
*
|
|
121
|
-
* On the first call (or after a geometry change that overflows the current
|
|
122
|
-
* slot) the segment is created / re-created sized for this frame. Returns
|
|
123
|
-
* `null` only when the sink has been destroyed.
|
|
124
|
-
*
|
|
125
|
-
* This is the copy-in convenience form (it copies `pixels` into the slot).
|
|
126
|
-
* The decoder's hot path uses the zero-copy {@link beginFrame} /
|
|
127
|
-
* {@link commitFrame} scatter-write pair instead — the scaler produces its
|
|
128
|
-
* packed output directly into the slot, eliminating the write-side memcpy.
|
|
129
|
-
*/
|
|
130
|
-
writeFrame(pixels, meta) {
|
|
131
|
-
if (this.destroyed) return null;
|
|
132
|
-
if (this.writer === null || (0, _camstack_shm_ring.computeSlotByteLength)(meta.width, meta.height, meta.format) > this.slotByteLength) this.recreateSegment((0, _camstack_shm_ring.computeSlotByteLength)(meta.width, meta.height, meta.format));
|
|
133
|
-
const writer = this.writer;
|
|
134
|
-
if (writer === null) return null;
|
|
135
|
-
const handle = writer.writeFrame(pixels, meta);
|
|
136
|
-
this.framesWritten += 1;
|
|
137
|
-
return handle;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Reserve a ring slot for a frame of the given geometry — the **zero-copy**
|
|
141
|
-
* scatter-write entry point (Phase 5 / D9 Task 7c).
|
|
142
|
-
*
|
|
143
|
-
* The segment is created / re-created here if this is the first frame or the
|
|
144
|
-
* geometry overflows the current slot capacity, so the slot is correctly
|
|
145
|
-
* sized before the caller fills it. The returned `buffer` is a writable view
|
|
146
|
-
* **directly over the mapped segment** — the node-av scaler scatters its
|
|
147
|
-
* packed output straight into it, with no intermediate copy. The caller MUST
|
|
148
|
-
* call {@link commitFrame} with the returned `slot` once the slot is filled.
|
|
149
|
-
*
|
|
150
|
-
* Returns `null` when the sink is destroyed or the segment cannot be created.
|
|
151
|
-
*/
|
|
152
|
-
beginFrame(width, height, format) {
|
|
153
|
-
if (this.destroyed) return null;
|
|
154
|
-
const requiredSlotBytes = (0, _camstack_shm_ring.computeSlotByteLength)(width, height, format);
|
|
155
|
-
if (this.writer === null || requiredSlotBytes > this.slotByteLength) this.recreateSegment(requiredSlotBytes);
|
|
156
|
-
const writer = this.writer;
|
|
157
|
-
if (writer === null) return null;
|
|
158
|
-
const { slot, buffer } = writer.beginFrame();
|
|
159
|
-
return {
|
|
160
|
-
slot,
|
|
161
|
-
buffer
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Publish the frame whose slot was reserved by {@link beginFrame} and filled
|
|
166
|
-
* in place by the caller. `slot` MUST be the value from the matching
|
|
167
|
-
* `beginFrame`. Returns the published `FrameHandle`, or `null` if the sink
|
|
168
|
-
* was destroyed (or the segment lost) between begin and commit.
|
|
169
|
-
*/
|
|
170
|
-
commitFrame(slot, meta) {
|
|
171
|
-
if (this.destroyed) return null;
|
|
172
|
-
const writer = this.writer;
|
|
173
|
-
if (writer === null) return null;
|
|
174
|
-
const handle = writer.commitFrame(slot, meta);
|
|
175
|
-
this.framesWritten += 1;
|
|
176
|
-
return handle;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Current shm ring usage — `null` until the first frame arms the segment.
|
|
180
|
-
* Surfaced through `decoder.getShmStats` so a downstream consumer can
|
|
181
|
-
* observe ring pressure (slot depth, byte budget, frames written).
|
|
182
|
-
*/
|
|
183
|
-
getShmStats() {
|
|
184
|
-
if (this.writer === null) return null;
|
|
185
|
-
return {
|
|
186
|
-
slotCount: this.writer.slotCount,
|
|
187
|
-
slotByteLength: this.slotByteLength,
|
|
188
|
-
segmentBytes: (0, _camstack_shm_ring.computeSegmentSize)(this.writer.slotCount, this.slotByteLength),
|
|
189
|
-
framesWritten: this.framesWritten
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Abandon a slot reserved by {@link beginFrame} **without publishing it** —
|
|
194
|
-
* the degenerate-path counterpart of {@link commitFrame}.
|
|
195
|
-
*
|
|
196
|
-
* A caller that reserved a slot but then could not produce valid pixels (no
|
|
197
|
-
* decoded source planes, or the scaler threw) MUST call this instead of
|
|
198
|
-
* `commitFrame`: it closes the open seqlock without advancing `writeIndex`,
|
|
199
|
-
* so no reader ever sees the slot's uninitialised bytes as a real frame, and
|
|
200
|
-
* no `FrameHandle` is handed downstream. `slot` MUST be the value from the
|
|
201
|
-
* matching `beginFrame`. A no-op if the sink was destroyed (or the segment
|
|
202
|
-
* lost) between begin and abort.
|
|
203
|
-
*/
|
|
204
|
-
abortFrame(slot) {
|
|
205
|
-
if (this.destroyed) return;
|
|
206
|
-
const writer = this.writer;
|
|
207
|
-
if (writer === null) return;
|
|
208
|
-
writer.abortFrame(slot);
|
|
209
|
-
}
|
|
210
|
-
/** Close + unlink the segment. Idempotent. */
|
|
211
|
-
destroy() {
|
|
212
|
-
if (this.destroyed) return;
|
|
213
|
-
this.destroyed = true;
|
|
214
|
-
this.releaseSegment();
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Create a fresh segment sized for at least `slotByteLength` bytes per slot,
|
|
218
|
-
* replacing any prior one. A re-create bumps the generation so the new
|
|
219
|
-
* segment has a distinct name — a consumer holding the old mapping is never
|
|
220
|
-
* silently handed a resized segment.
|
|
221
|
-
*/
|
|
222
|
-
recreateSegment(slotByteLength) {
|
|
223
|
-
this.releaseSegment();
|
|
224
|
-
this.generation += 1;
|
|
225
|
-
const name = makeSegmentName(this.seed, this.generation);
|
|
226
|
-
const slotCount = (0, _camstack_shm_ring.deriveSlotCount)(RING_BUDGET_BYTES, slotByteLength);
|
|
227
|
-
if (slotCount === _camstack_shm_ring.MIN_RING_SLOTS && _camstack_shm_ring.MIN_RING_SLOTS * slotByteLength > RING_BUDGET_BYTES) this.logger.warn("decoder shm ring: budget too small for resolution — using MIN slots", { meta: {
|
|
228
|
-
slotByteLength,
|
|
229
|
-
budgetMb: RING_BUDGET_MB
|
|
230
|
-
} });
|
|
231
|
-
const totalBytes = (0, _camstack_shm_ring.computeSegmentSize)(slotCount, slotByteLength);
|
|
232
|
-
try {
|
|
233
|
-
const segment = (0, _camstack_shm_ring.createSegment)(name, totalBytes);
|
|
234
|
-
this.segment = segment;
|
|
235
|
-
this.segmentName = name;
|
|
236
|
-
this.slotByteLength = slotByteLength;
|
|
237
|
-
this.writer = new _camstack_shm_ring.FrameRingWriter(segment.buffer, name, slotCount, slotByteLength, this.nodeId);
|
|
238
|
-
this.logger.info("decoder shm ring: segment created", { meta: {
|
|
239
|
-
segment: name,
|
|
240
|
-
slotCount,
|
|
241
|
-
slotByteLength,
|
|
242
|
-
totalBytes,
|
|
243
|
-
generation: this.generation
|
|
244
|
-
} });
|
|
245
|
-
} catch (err) {
|
|
246
|
-
this.segment = null;
|
|
247
|
-
this.writer = null;
|
|
248
|
-
this.segmentName = null;
|
|
249
|
-
this.slotByteLength = 0;
|
|
250
|
-
this.logger.error("decoder shm ring: segment create failed", { meta: {
|
|
251
|
-
segment: name,
|
|
252
|
-
slotByteLength,
|
|
253
|
-
error: err instanceof Error ? err.message : String(err)
|
|
254
|
-
} });
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/** Unmap + unlink the current segment, if any. */
|
|
258
|
-
releaseSegment() {
|
|
259
|
-
const segment = this.segment;
|
|
260
|
-
if (segment === null) return;
|
|
261
|
-
this.segment = null;
|
|
262
|
-
this.writer = null;
|
|
263
|
-
const name = this.segmentName;
|
|
264
|
-
this.segmentName = null;
|
|
265
|
-
try {
|
|
266
|
-
segment.close();
|
|
267
|
-
segment.unlink();
|
|
268
|
-
this.logger.info("decoder shm ring: segment released", { meta: { segment: name } });
|
|
269
|
-
} catch (err) {
|
|
270
|
-
this.logger.warn("decoder shm ring: segment release failed", { meta: {
|
|
271
|
-
segment: name,
|
|
272
|
-
error: err instanceof Error ? err.message : String(err)
|
|
273
|
-
} });
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
//#endregion
|
|
278
8
|
//#region ../../node_modules/zod/v4/core/core.js
|
|
279
9
|
var _a$1;
|
|
280
10
|
function $constructor(name, initializer, params) {
|
|
@@ -4904,7 +4634,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4904
4634
|
return inst;
|
|
4905
4635
|
}
|
|
4906
4636
|
//#endregion
|
|
4907
|
-
//#region ../types/dist/sleep-
|
|
4637
|
+
//#region ../types/dist/sleep-BC9Yqte7.mjs
|
|
4908
4638
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4909
4639
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4910
4640
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5090,6 +4820,18 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
5090
4820
|
*/
|
|
5091
4821
|
EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
|
|
5092
4822
|
/**
|
|
4823
|
+
* The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
|
|
4824
|
+
* Emitted by addon-pipeline-orchestrator whenever it (re)derives node
|
|
4825
|
+
* capabilities — at boot, on agent online/offline, and on an ingest-node
|
|
4826
|
+
* flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
|
|
4827
|
+
* keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
|
|
4828
|
+
* cross-process `getIngestOwner` query (push the authority's decision instead
|
|
4829
|
+
* of polling it on the hot path). Idempotent state — re-emitted on every
|
|
4830
|
+
* topology change, so a dropped event self-heals on the next one (plus the
|
|
4831
|
+
* broker's long backstop reconcile query).
|
|
4832
|
+
*/
|
|
4833
|
+
EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
|
|
4834
|
+
/**
|
|
5093
4835
|
* Periodic snapshot of per-node pipeline-runner load
|
|
5094
4836
|
* (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
|
|
5095
4837
|
* subscribe instead of polling `pipelineRunner.getLocalLoad`.
|
|
@@ -5613,10 +5355,6 @@ function hydrateField(field, values) {
|
|
|
5613
5355
|
};
|
|
5614
5356
|
}
|
|
5615
5357
|
const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
|
|
5616
|
-
if (field.type === "password") return {
|
|
5617
|
-
...field,
|
|
5618
|
-
value: ""
|
|
5619
|
-
};
|
|
5620
5358
|
const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
|
|
5621
5359
|
return {
|
|
5622
5360
|
...field,
|
|
@@ -7000,6 +6738,21 @@ function method(input, output, options) {
|
|
|
7000
6738
|
timeoutMs: options?.timeoutMs
|
|
7001
6739
|
};
|
|
7002
6740
|
}
|
|
6741
|
+
/**
|
|
6742
|
+
* A wrapper/system-only method: served exclusively by the cap's system-level
|
|
6743
|
+
* provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
|
|
6744
|
+
* driver natives don't stub out a wrapper concern (e.g. a cross-device cache
|
|
6745
|
+
* overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
|
|
6746
|
+
*/
|
|
6747
|
+
function systemMethod(input, output, options) {
|
|
6748
|
+
return {
|
|
6749
|
+
...method(input, output, options),
|
|
6750
|
+
systemOnly: true
|
|
6751
|
+
};
|
|
6752
|
+
}
|
|
6753
|
+
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
6754
|
+
var VersionOutputSchema$1 = object({ version: string() });
|
|
6755
|
+
method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
|
|
7003
6756
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
7004
6757
|
var VersionOutputSchema = object({ version: string() });
|
|
7005
6758
|
method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
|
|
@@ -7181,6 +6934,36 @@ var ModelFormatsSchema = object({
|
|
|
7181
6934
|
tflite: ModelFormatEntrySchema.optional(),
|
|
7182
6935
|
pt: ModelFormatEntrySchema.optional()
|
|
7183
6936
|
});
|
|
6937
|
+
/**
|
|
6938
|
+
* Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
|
|
6939
|
+
* the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
|
|
6940
|
+
* grouped Family→Tier→Variant picker renders identically in the config UI and
|
|
6941
|
+
* in the pipeline/device steppers. The flat `id` stays the source of truth for
|
|
6942
|
+
* resolution/download/persistence; this is a presentation overlay resolved back
|
|
6943
|
+
* to an `id`.
|
|
6944
|
+
*/
|
|
6945
|
+
var ModelVariantGroupSchema = object({
|
|
6946
|
+
/** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
|
|
6947
|
+
family: string(),
|
|
6948
|
+
/** Size within the family, e.g. `n` | `s` | `m` | `l`. */
|
|
6949
|
+
tier: string(),
|
|
6950
|
+
/** Quantization axis. Omit ⇒ the fp32 base build. */
|
|
6951
|
+
precision: _enum(["fp32", "int8"]).optional(),
|
|
6952
|
+
/**
|
|
6953
|
+
* Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
|
|
6954
|
+
* latency-optimized export (e.g. ReLU-activation variant) — the slot the
|
|
6955
|
+
* future performance variants plug into.
|
|
6956
|
+
*/
|
|
6957
|
+
optimization: _enum(["standard", "fast"]).optional(),
|
|
6958
|
+
/**
|
|
6959
|
+
* Input-resolution axis (square input side, px). Omit ⇒ the family's native
|
|
6960
|
+
* resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
|
|
6961
|
+
* cheap latency lever — especially on Apple ANE and the Intel N100 — at a
|
|
6962
|
+
* small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
|
|
6963
|
+
* the group so the selector can offer it as a variant axis.
|
|
6964
|
+
*/
|
|
6965
|
+
resolution: number().int().positive().optional()
|
|
6966
|
+
});
|
|
7184
6967
|
var ModelCatalogEntrySchema = object({
|
|
7185
6968
|
id: string(),
|
|
7186
6969
|
name: string(),
|
|
@@ -7210,7 +6993,43 @@ var ModelCatalogEntrySchema = object({
|
|
|
7210
6993
|
* Auxiliary files required at runtime (labels JSON, charset dict, etc.).
|
|
7211
6994
|
* Downloaded into the same modelsDir alongside the model file.
|
|
7212
6995
|
*/
|
|
7213
|
-
extraFiles: array(ModelExtraFileSchema).readonly().optional()
|
|
6996
|
+
extraFiles: array(ModelExtraFileSchema).readonly().optional(),
|
|
6997
|
+
/**
|
|
6998
|
+
* LEGACY entry — retained in the catalog so a persisted operator selection
|
|
6999
|
+
* still RESOLVES (and can be re-activated), but hidden from the selectable
|
|
7000
|
+
* model list and excluded from the auto format-default pick. Set on the
|
|
7001
|
+
* superseded / consolidated models (older lineages, redundant fp16 IRs) so
|
|
7002
|
+
* the active lineup stays the coherent curated ladder without deleting a
|
|
7003
|
+
* model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
|
|
7004
|
+
* an explicit legacy id that has a build for the node's format.
|
|
7005
|
+
*/
|
|
7006
|
+
legacy: boolean().optional(),
|
|
7007
|
+
/**
|
|
7008
|
+
* Measured quality/latency metadata — populated from the benchmark addon on
|
|
7009
|
+
* the real node classes. Absent = not yet measured (most entries today; the
|
|
7010
|
+
* catalog historically carried only `sizeMB`, a poor cross-architecture
|
|
7011
|
+
* speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
|
|
7012
|
+
*/
|
|
7013
|
+
metrics: object({
|
|
7014
|
+
map50: number().optional(),
|
|
7015
|
+
p95LatencyMs: record(string(), number()).optional()
|
|
7016
|
+
}).optional(),
|
|
7017
|
+
/**
|
|
7018
|
+
* SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
|
|
7019
|
+
* YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
|
|
7020
|
+
* the retraining addon and any future commercial distribution.
|
|
7021
|
+
*/
|
|
7022
|
+
license: string().optional(),
|
|
7023
|
+
/**
|
|
7024
|
+
* Variant-selector grouping. The UI groups models by `family` + `tier` and
|
|
7025
|
+
* offers `precision` / `optimization` as variant axes WITHIN a tier — so all
|
|
7026
|
+
* of a family's sizes and quantizations collapse into one grouped picker
|
|
7027
|
+
* instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
|
|
7028
|
+
* (legacy / custom models) — never shown in the grouped selector. The flat
|
|
7029
|
+
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
7030
|
+
* is a presentation overlay resolved back to an `id`.
|
|
7031
|
+
*/
|
|
7032
|
+
group: ModelVariantGroupSchema.optional()
|
|
7214
7033
|
});
|
|
7215
7034
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
7216
7035
|
format: literal("openvino"),
|
|
@@ -7271,8 +7090,8 @@ var RecordingModeSchema = _enum([
|
|
|
7271
7090
|
"onAudioThreshold"
|
|
7272
7091
|
]);
|
|
7273
7092
|
/**
|
|
7274
|
-
* First-class, authoritative per-camera storage mode — the
|
|
7275
|
-
* reads directly (never inferred from `rules`):
|
|
7093
|
+
* First-class, authoritative per-camera storage mode — the explicit choice the
|
|
7094
|
+
* UI reads directly (never inferred from `rules`):
|
|
7276
7095
|
* - `off` — not recording.
|
|
7277
7096
|
* - `events` — record only around triggers (motion / audio threshold),
|
|
7278
7097
|
* with pre/post-buffer.
|
|
@@ -8920,26 +8739,13 @@ DeviceType.Light, method(object({
|
|
|
8920
8739
|
percentage: number().min(0).max(100),
|
|
8921
8740
|
lastChangedAt: number()
|
|
8922
8741
|
});
|
|
8742
|
+
/** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
|
|
8923
8743
|
var StreamFormatSchema = _enum([
|
|
8924
8744
|
"webrtc",
|
|
8925
8745
|
"hls",
|
|
8926
8746
|
"mjpeg",
|
|
8927
8747
|
"rtsp"
|
|
8928
8748
|
]);
|
|
8929
|
-
var StreamInfoSchema = object({
|
|
8930
|
-
streamId: string(),
|
|
8931
|
-
format: StreamFormatSchema,
|
|
8932
|
-
url: string().nullable(),
|
|
8933
|
-
active: boolean()
|
|
8934
|
-
});
|
|
8935
|
-
method(object({
|
|
8936
|
-
streamId: string(),
|
|
8937
|
-
sourceUrl: string(),
|
|
8938
|
-
codec: string().optional()
|
|
8939
|
-
}), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
8940
|
-
streamId: string(),
|
|
8941
|
-
format: StreamFormatSchema
|
|
8942
|
-
}), string().nullable()), method(_void(), array(StreamInfoSchema));
|
|
8943
8749
|
var RtspRestreamEntrySchema = object({
|
|
8944
8750
|
brokerId: string(),
|
|
8945
8751
|
url: string(),
|
|
@@ -9604,7 +9410,7 @@ var ConsumablesStatusSchema = object({
|
|
|
9604
9410
|
})),
|
|
9605
9411
|
lastChangedAt: number()
|
|
9606
9412
|
});
|
|
9607
|
-
|
|
9413
|
+
Object.values(DeviceType), method(object({
|
|
9608
9414
|
deviceId: number().int().nonnegative(),
|
|
9609
9415
|
key: string().min(1)
|
|
9610
9416
|
}), _void(), {
|
|
@@ -10519,7 +10325,7 @@ var BoundingBoxSchema = object({
|
|
|
10519
10325
|
w: number(),
|
|
10520
10326
|
h: number()
|
|
10521
10327
|
});
|
|
10522
|
-
|
|
10328
|
+
object({
|
|
10523
10329
|
class: string(),
|
|
10524
10330
|
originalClass: string(),
|
|
10525
10331
|
score: number(),
|
|
@@ -10654,7 +10460,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
|
|
|
10654
10460
|
enabled: boolean(),
|
|
10655
10461
|
modelId: string(),
|
|
10656
10462
|
children: array(PipelineDefaultStepSchema).readonly(),
|
|
10657
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
10658
10463
|
group: string().optional(),
|
|
10659
10464
|
settings: record(string(), unknown()).optional()
|
|
10660
10465
|
}));
|
|
@@ -10679,7 +10484,9 @@ var PipelineModelOptionSchema = object({
|
|
|
10679
10484
|
formats: record(string(), object({
|
|
10680
10485
|
downloaded: boolean(),
|
|
10681
10486
|
sizeMB: number()
|
|
10682
|
-
}))
|
|
10487
|
+
})),
|
|
10488
|
+
group: ModelVariantGroupSchema.optional(),
|
|
10489
|
+
legacy: boolean().optional()
|
|
10683
10490
|
});
|
|
10684
10491
|
var ConfigFieldBridge = custom();
|
|
10685
10492
|
var PipelineAddonSchemaSchema = object({
|
|
@@ -10693,6 +10500,7 @@ var PipelineAddonSchemaSchema = object({
|
|
|
10693
10500
|
defaultModelId: string(),
|
|
10694
10501
|
defaultModelIdByFormat: record(string(), string()).optional(),
|
|
10695
10502
|
enabledByDefault: boolean().optional(),
|
|
10503
|
+
backfillIntoExistingOverrides: boolean().optional(),
|
|
10696
10504
|
defaultConfidence: number(),
|
|
10697
10505
|
group: string().optional(),
|
|
10698
10506
|
configSchema: array(ConfigFieldBridge).readonly().optional()
|
|
@@ -10709,11 +10517,6 @@ var PipelineSchemaSchema = object({
|
|
|
10709
10517
|
selectedEngine: PipelineEngineChoiceSchema,
|
|
10710
10518
|
slots: array(PipelineSlotSchemaSchema).readonly()
|
|
10711
10519
|
});
|
|
10712
|
-
var DetectorOutputSchema = object({
|
|
10713
|
-
detections: array(SpatialDetectionSchema).readonly(),
|
|
10714
|
-
inferenceMs: number(),
|
|
10715
|
-
modelId: string()
|
|
10716
|
-
});
|
|
10717
10520
|
var EngineProvisioningSchema = object({
|
|
10718
10521
|
runtimeId: _enum([
|
|
10719
10522
|
"onnx",
|
|
@@ -10730,15 +10533,42 @@ var EngineProvisioningSchema = object({
|
|
|
10730
10533
|
]),
|
|
10731
10534
|
progress: number().optional(),
|
|
10732
10535
|
error: string().optional(),
|
|
10733
|
-
nextRetryAt: number().optional()
|
|
10536
|
+
nextRetryAt: number().optional(),
|
|
10537
|
+
/**
|
|
10538
|
+
* Gate A (config-correctness gate at engine change): human-readable
|
|
10539
|
+
* config issues surfaced EAGERLY when the node's engine changes — model
|
|
10540
|
+
* substitutions ("chose X, running Y") and zero-build steps ("no model
|
|
10541
|
+
* has a <format> build"). Additive/optional: informational only, never
|
|
10542
|
+
* enforced here — `assertEngineReady` (readiness) still gates inference.
|
|
10543
|
+
* Absent/empty when the node-default tree resolves cleanly.
|
|
10544
|
+
*/
|
|
10545
|
+
configIssues: array(string()).optional()
|
|
10734
10546
|
});
|
|
10735
10547
|
var PipelineStepInputSchema = lazy(() => object({
|
|
10736
10548
|
addonId: string(),
|
|
10737
|
-
modelId: string(),
|
|
10549
|
+
modelId: string().optional(),
|
|
10738
10550
|
enabled: boolean().default(true),
|
|
10739
10551
|
children: array(PipelineStepInputSchema).optional(),
|
|
10740
10552
|
settings: record(string(), unknown()).optional()
|
|
10741
10553
|
}));
|
|
10554
|
+
var ModelSubstitutionSchema = object({
|
|
10555
|
+
addonId: string(),
|
|
10556
|
+
chosen: string(),
|
|
10557
|
+
running: string(),
|
|
10558
|
+
format: string()
|
|
10559
|
+
});
|
|
10560
|
+
var PipelineValidationIssueSchema = object({
|
|
10561
|
+
addonId: string(),
|
|
10562
|
+
kind: _enum(["unknown-addon", "no-format-build"]),
|
|
10563
|
+
detail: string()
|
|
10564
|
+
});
|
|
10565
|
+
var PipelineValidationResultSchema = object({
|
|
10566
|
+
ok: boolean(),
|
|
10567
|
+
issues: array(PipelineValidationIssueSchema).readonly(),
|
|
10568
|
+
substitutions: array(ModelSubstitutionSchema).readonly(),
|
|
10569
|
+
/** The node's `currentEngine.format` this validation ran against. */
|
|
10570
|
+
format: string()
|
|
10571
|
+
});
|
|
10742
10572
|
var ReferenceImageEntrySchema = object({
|
|
10743
10573
|
filename: string(),
|
|
10744
10574
|
stepIds: array(string()).readonly().optional()
|
|
@@ -10809,7 +10639,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
10809
10639
|
})) }), object({ success: literal(true) }), {
|
|
10810
10640
|
kind: "mutation",
|
|
10811
10641
|
auth: "admin"
|
|
10812
|
-
}), method(
|
|
10642
|
+
}), method(object({ nodeId: string() }), object({
|
|
10643
|
+
success: literal(true),
|
|
10644
|
+
clearedDevices: number()
|
|
10645
|
+
}), {
|
|
10646
|
+
kind: "mutation",
|
|
10647
|
+
auth: "admin"
|
|
10648
|
+
}), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
|
|
10813
10649
|
name: string(),
|
|
10814
10650
|
steps: array(PipelineTemplateStepSchema).readonly(),
|
|
10815
10651
|
engine: PipelineEngineChoiceSchema
|
|
@@ -10826,10 +10662,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
10826
10662
|
modelId: string(),
|
|
10827
10663
|
format: ModelFormatSchema$1
|
|
10828
10664
|
}), object({ success: literal(true) }), { kind: "mutation" }), method(object({
|
|
10829
|
-
addonId: string(),
|
|
10830
|
-
frame: FrameInputSchema,
|
|
10831
|
-
config: record(string(), unknown()).optional()
|
|
10832
|
-
}), DetectorOutputSchema), method(object({
|
|
10833
10665
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
10834
10666
|
steps: array(PipelineStepInputSchema).min(1),
|
|
10835
10667
|
frame: FrameInputSchema.optional(),
|
|
@@ -10975,6 +10807,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(ZoneSchema).read
|
|
|
10975
10807
|
auth: "admin"
|
|
10976
10808
|
}), object({ zones: array(ZoneSchema).readonly() });
|
|
10977
10809
|
/**
|
|
10810
|
+
* A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
|
|
10811
|
+
* decode worker resolves it against the RETAINED native frame's real pixel dims,
|
|
10812
|
+
* so the caller supplies only the detection-res bbox divided by the detection
|
|
10813
|
+
* dims — no native resolution to plumb.
|
|
10814
|
+
*/
|
|
10815
|
+
var NativeCropBboxSchema = object({
|
|
10816
|
+
x: number(),
|
|
10817
|
+
y: number(),
|
|
10818
|
+
w: number(),
|
|
10819
|
+
h: number()
|
|
10820
|
+
});
|
|
10821
|
+
/** Result of a best-effort native-resolution crop (`getNativeCrop`). */
|
|
10822
|
+
var NativeCropResultSchema = object({
|
|
10823
|
+
/** Packed rgb (24-bit) pixels of the crop. */
|
|
10824
|
+
bytes: _instanceof(Uint8Array),
|
|
10825
|
+
width: number().int().positive(),
|
|
10826
|
+
height: number().int().positive()
|
|
10827
|
+
});
|
|
10828
|
+
/**
|
|
10978
10829
|
* Per-camera tunable ranges + defaults. Single source of truth used
|
|
10979
10830
|
* by both the Zod data schema (validation + default fallback) and
|
|
10980
10831
|
* the device settings UI (slider min/max/step). Touch one place and
|
|
@@ -11069,6 +10920,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
11069
10920
|
kind: literal("remote-restream"),
|
|
11070
10921
|
/** The camera's source-owner node (slice 1: always the hub). */
|
|
11071
10922
|
ownerNodeId: string(),
|
|
10923
|
+
/**
|
|
10924
|
+
* The owner's LAN-reachable host, resolved by the orchestrator from the
|
|
10925
|
+
* per-node `reachableHost` override (Cluster UI). When present the runner
|
|
10926
|
+
* dials THIS host for the owner's restream, in preference to the
|
|
10927
|
+
* `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
|
|
10928
|
+
*/
|
|
10929
|
+
ownerReachableHost: string().optional(),
|
|
11072
10930
|
/** Operator override for the owner host the runner dials. */
|
|
11073
10931
|
hubHostnameOverride: string().optional()
|
|
11074
10932
|
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
@@ -11077,13 +10935,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
11077
10935
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
11078
10936
|
* runner needs to subscribe to the local broker and execute inference.
|
|
11079
10937
|
*
|
|
11080
|
-
* Stateless-pipeline model: the
|
|
11081
|
-
*
|
|
11082
|
-
*
|
|
11083
|
-
*
|
|
11084
|
-
*
|
|
11085
|
-
* `engine`/`steps`/`audio` are optional during the additive migration
|
|
11086
|
-
* window; once orchestrator + UI are migrated they become required.
|
|
10938
|
+
* Stateless-pipeline model: the pipeline content (`steps`, optional
|
|
10939
|
+
* `audio`) travels with the attach payload. The runner keeps it in RAM
|
|
10940
|
+
* for the lifetime of the attach — on rebalance, edit, or restart the
|
|
10941
|
+
* orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
|
|
10942
|
+
* node-local, resolved by the executing runner at dispatch time.
|
|
11087
10943
|
*/
|
|
11088
10944
|
var RunnerCameraConfigSchema = object({
|
|
11089
10945
|
deviceId: number(),
|
|
@@ -11134,14 +10990,11 @@ var RunnerCameraConfigSchema = object({
|
|
|
11134
10990
|
*/
|
|
11135
10991
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
11136
10992
|
pipelineEnabled: boolean().default(true),
|
|
11137
|
-
/** Engine choice for video steps (runtime+backend+format). */
|
|
11138
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
11139
10993
|
/** Ordered tree of video steps. Absent → runner skips video detection. */
|
|
11140
10994
|
steps: array(PipelineStepInputSchema).readonly().optional(),
|
|
11141
10995
|
/** Audio classification branch. `enabled:false` disables, null skips. */
|
|
11142
10996
|
audio: object({
|
|
11143
|
-
|
|
11144
|
-
modelId: string(),
|
|
10997
|
+
modelId: string().optional(),
|
|
11145
10998
|
enabled: boolean()
|
|
11146
10999
|
}).nullable().optional(),
|
|
11147
11000
|
/**
|
|
@@ -11228,7 +11081,11 @@ var RunnerLocalMetricsSchema = object({
|
|
|
11228
11081
|
avgInferenceTimeMs: number(),
|
|
11229
11082
|
queueDepth: number()
|
|
11230
11083
|
});
|
|
11231
|
-
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly())
|
|
11084
|
+
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
|
|
11085
|
+
handle: FrameHandleSchema,
|
|
11086
|
+
bbox: NativeCropBboxSchema,
|
|
11087
|
+
maxWidth: number().int().positive().optional()
|
|
11088
|
+
}), NativeCropResultSchema.nullable());
|
|
11232
11089
|
object({
|
|
11233
11090
|
detected: boolean(),
|
|
11234
11091
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
@@ -12522,7 +12379,9 @@ var AddonPageDeclarationSchema$1 = object({
|
|
|
12522
12379
|
icon: string(),
|
|
12523
12380
|
path: string(),
|
|
12524
12381
|
remoteName: string(),
|
|
12525
|
-
bundle: string()
|
|
12382
|
+
bundle: string(),
|
|
12383
|
+
section: string().optional(),
|
|
12384
|
+
sectionLabel: string().optional()
|
|
12526
12385
|
});
|
|
12527
12386
|
var AddonPageInfoSchema = object({
|
|
12528
12387
|
addonId: string(),
|
|
@@ -12562,7 +12421,18 @@ var AddonPageDeclarationSchema = object({
|
|
|
12562
12421
|
* the static-file route can compute an mtime-based cache-buster URL
|
|
12563
12422
|
* without a separate filesystem stat.
|
|
12564
12423
|
*/
|
|
12565
|
-
bundle: string()
|
|
12424
|
+
bundle: string(),
|
|
12425
|
+
/**
|
|
12426
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
12427
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
12428
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
12429
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
12430
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
12431
|
+
* "Addon Pages" group.
|
|
12432
|
+
*/
|
|
12433
|
+
section: string().optional(),
|
|
12434
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
12435
|
+
sectionLabel: string().optional()
|
|
12566
12436
|
});
|
|
12567
12437
|
method(_void(), array(AddonPageDeclarationSchema).readonly());
|
|
12568
12438
|
var AddonHttpRouteSchema = object({
|
|
@@ -12778,6 +12648,17 @@ var WidgetMetadataSchema = object({
|
|
|
12778
12648
|
deviceContext: boolean().default(false),
|
|
12779
12649
|
integrationContext: boolean().default(false)
|
|
12780
12650
|
}),
|
|
12651
|
+
/**
|
|
12652
|
+
* Loadable BEFORE authentication. The normal widget registry listing
|
|
12653
|
+
* (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
|
|
12654
|
+
* (the login page) cannot discover a widget through it. A widget that
|
|
12655
|
+
* declares `preAuth: true` marks itself as safe to mount on a pre-auth
|
|
12656
|
+
* screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
|
|
12657
|
+
* login-method contribution channel (see `login-method.cap.ts`) rather
|
|
12658
|
+
* than the authenticated registry, and its bundle is served by the
|
|
12659
|
+
* public `/api/addon-widgets/:addonId/*` static route. Defaults false.
|
|
12660
|
+
*/
|
|
12661
|
+
preAuth: boolean().optional().default(false),
|
|
12781
12662
|
/** Dashboard placement HINTS (operator can override per instance). */
|
|
12782
12663
|
defaultSize: WidgetSizeEnum.default("md"),
|
|
12783
12664
|
allowedSizes: array(WidgetSizeEnum).readonly().default([
|
|
@@ -13116,6 +12997,66 @@ method(object({
|
|
|
13116
12997
|
password: string()
|
|
13117
12998
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
13118
12999
|
/**
|
|
13000
|
+
* `login-method` — collection cap through which auth addons contribute
|
|
13001
|
+
* their pre-auth login surfaces to the login page. This is the SINGLE,
|
|
13002
|
+
* generic mechanism that supersedes the dead `auth.listProviders` reader:
|
|
13003
|
+
* every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
|
|
13004
|
+
* `login-method` provider and the PUBLIC `auth.listLoginMethods`
|
|
13005
|
+
* procedure aggregates them for the unauthenticated login page.
|
|
13006
|
+
*
|
|
13007
|
+
* A contribution is a discriminated union on `kind`:
|
|
13008
|
+
*
|
|
13009
|
+
* - `redirect` — a declarative button. The login page renders a generic
|
|
13010
|
+
* button that navigates to `startUrl` (an addon-owned HTTP route).
|
|
13011
|
+
* Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
|
|
13012
|
+
* ZERO shell-side JS. A future SSO addon plugs in the same way — the
|
|
13013
|
+
* login page needs NO change.
|
|
13014
|
+
*
|
|
13015
|
+
* - `widget` — a Module-Federation widget the login page mounts (via
|
|
13016
|
+
* `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
|
|
13017
|
+
* login ceremony, which must run `@simplewebauthn/browser` INSIDE the
|
|
13018
|
+
* addon bundle. The referenced widget also declares `preAuth: true` in
|
|
13019
|
+
* its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
|
|
13020
|
+
* stamps a public `bundleUrl` from `addonId` + `bundle`.
|
|
13021
|
+
*
|
|
13022
|
+
* Every contribution carries a `stage`:
|
|
13023
|
+
* - `primary` — shown on the first credentials screen (OIDC /
|
|
13024
|
+
* magic-link buttons; a future usernameless passkey).
|
|
13025
|
+
* - `second-factor` — shown AFTER the password leg, gated on the
|
|
13026
|
+
* returned `factors` (passkey-as-2FA today).
|
|
13027
|
+
*
|
|
13028
|
+
* `mount: skip` — the cap is read server-side by the core auth router
|
|
13029
|
+
* (`registry.getCollection('login-method')`), never mounted as its own
|
|
13030
|
+
* tRPC router.
|
|
13031
|
+
*/
|
|
13032
|
+
/** When a login method renders in the two-phase login flow. */
|
|
13033
|
+
var LoginStageEnum = _enum(["primary", "second-factor"]);
|
|
13034
|
+
/** One login-method contribution — redirect button OR pre-auth widget. */
|
|
13035
|
+
var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
|
|
13036
|
+
kind: literal("redirect"),
|
|
13037
|
+
/** Stable id within the login-method set (e.g. `auth-oidc/google`). */
|
|
13038
|
+
id: string(),
|
|
13039
|
+
/** Operator-facing button label. */
|
|
13040
|
+
label: string(),
|
|
13041
|
+
/** lucide-react icon name. */
|
|
13042
|
+
icon: string().optional(),
|
|
13043
|
+
/** Addon-owned HTTP route the button navigates to (GET). */
|
|
13044
|
+
startUrl: string(),
|
|
13045
|
+
stage: LoginStageEnum
|
|
13046
|
+
}), object({
|
|
13047
|
+
kind: literal("widget"),
|
|
13048
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
|
|
13049
|
+
id: string(),
|
|
13050
|
+
/** Owning addon id — drives the public bundle URL + the MF namespace. */
|
|
13051
|
+
addonId: string(),
|
|
13052
|
+
/** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
|
|
13053
|
+
bundle: string(),
|
|
13054
|
+
/** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
|
|
13055
|
+
remote: WidgetRemoteSchema,
|
|
13056
|
+
stage: LoginStageEnum
|
|
13057
|
+
})]);
|
|
13058
|
+
method(_void(), array(LoginMethodContributionSchema).readonly());
|
|
13059
|
+
/**
|
|
13119
13060
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
13120
13061
|
* `id = <addonId>:<subId>` from its provider lookup so consumers
|
|
13121
13062
|
* (admin UI, restore flow) see one canonical key.
|
|
@@ -15312,7 +15253,17 @@ var TrackSchema = object({
|
|
|
15312
15253
|
/** Cumulative normalized distance travelled (0..1 units = full frame width). */
|
|
15313
15254
|
totalDistance: number(),
|
|
15314
15255
|
state: TrackStateSchema,
|
|
15315
|
-
active: boolean()
|
|
15256
|
+
active: boolean(),
|
|
15257
|
+
/** Deterministic key-event importance score in [0,1] (server-computed at
|
|
15258
|
+
* track expiry, recomputed on late label). Absent on legacy rows written
|
|
15259
|
+
* before scoring shipped — consumers degrade to absence / compute-on-read. */
|
|
15260
|
+
importance: number().optional(),
|
|
15261
|
+
/** Id of the track's highest-confidence ObjectEvent (its representative
|
|
15262
|
+
* "best" frame). Absent when the track produced no object events. */
|
|
15263
|
+
bestEventId: string().optional(),
|
|
15264
|
+
/** Tag of the importance sub-signal that dominated the score
|
|
15265
|
+
* (identity|dwell|proximity|class|confidence|travel|zone). */
|
|
15266
|
+
importanceReason: string().optional()
|
|
15316
15267
|
});
|
|
15317
15268
|
var BaseEventFields = {
|
|
15318
15269
|
id: string(),
|
|
@@ -15377,8 +15328,18 @@ var ObjectEventSchema = object({
|
|
|
15377
15328
|
frameHeight: number().optional(),
|
|
15378
15329
|
/** MediaStore key for the crop attached to this event (if any). */
|
|
15379
15330
|
mediaKey: string().optional(),
|
|
15331
|
+
/** Design B: MediaStore key of the track's native-resolution key frame (the
|
|
15332
|
+
* best-detection full frame). Resolve via the event-media data-plane
|
|
15333
|
+
* (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
|
|
15334
|
+
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
15335
|
+
* sources — consumers fall back to `mediaKey` (the tight crop). */
|
|
15336
|
+
keyFrameMediaKey: string().optional(),
|
|
15380
15337
|
/** Populated by B5 (recording playback URL for this event). */
|
|
15381
|
-
mediaUrl: string().optional()
|
|
15338
|
+
mediaUrl: string().optional(),
|
|
15339
|
+
/** The parent track's key-event importance [0,1], propagated to every object
|
|
15340
|
+
* event of the track (so an event row can be sorted by importance without a
|
|
15341
|
+
* track join). Absent on legacy rows / before the track was scored. */
|
|
15342
|
+
importance: number().optional()
|
|
15382
15343
|
});
|
|
15383
15344
|
var AudioEventSchema = object({
|
|
15384
15345
|
...BaseEventFields,
|
|
@@ -15402,7 +15363,8 @@ var MediaFileKindEnum = _enum([
|
|
|
15402
15363
|
"fullFrame",
|
|
15403
15364
|
"fullFrameBoxed",
|
|
15404
15365
|
"faceCrop",
|
|
15405
|
-
"plateCrop"
|
|
15366
|
+
"plateCrop",
|
|
15367
|
+
"keyFrame"
|
|
15406
15368
|
]);
|
|
15407
15369
|
var MediaFileSchema = object({
|
|
15408
15370
|
key: string(),
|
|
@@ -15423,6 +15385,32 @@ var DeviceEventQueryInput = object({
|
|
|
15423
15385
|
projection: _enum(["full", "slim"]).optional()
|
|
15424
15386
|
});
|
|
15425
15387
|
var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
|
|
15388
|
+
var KeyEventQueryInput = object({
|
|
15389
|
+
deviceId: number(),
|
|
15390
|
+
/** Window lower bound (track firstSeen ≥ since). */
|
|
15391
|
+
since: number(),
|
|
15392
|
+
/** Window upper bound (track firstSeen ≤ until). */
|
|
15393
|
+
until: number(),
|
|
15394
|
+
limit: number().int().min(1).max(200).default(50),
|
|
15395
|
+
/** Drop tracks scoring below this importance. */
|
|
15396
|
+
minImportance: number().min(0).max(1).optional(),
|
|
15397
|
+
/** Restrict to a single class (e.g. 'person'). */
|
|
15398
|
+
classFilter: string().optional()
|
|
15399
|
+
});
|
|
15400
|
+
var KeyEventSchema = object({
|
|
15401
|
+
/** The representative event id (the track's best ObjectEvent, else its trackId). */
|
|
15402
|
+
id: string(),
|
|
15403
|
+
trackId: string(),
|
|
15404
|
+
/** Track start time (firstSeen). */
|
|
15405
|
+
timestamp: number(),
|
|
15406
|
+
className: string(),
|
|
15407
|
+
label: string().optional(),
|
|
15408
|
+
importance: number(),
|
|
15409
|
+
/** Highest-confidence ObjectEvent id for the track (empty when none). */
|
|
15410
|
+
bestEventId: string(),
|
|
15411
|
+
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
15412
|
+
windowMs: number().optional()
|
|
15413
|
+
});
|
|
15426
15414
|
var TrackedDetectionSchema = object({
|
|
15427
15415
|
trackId: string(),
|
|
15428
15416
|
className: string(),
|
|
@@ -15452,7 +15440,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15452
15440
|
}), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
|
|
15453
15441
|
kind: "mutation",
|
|
15454
15442
|
auth: "admin"
|
|
15455
|
-
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
|
|
15443
|
+
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
15456
15444
|
deviceId: number(),
|
|
15457
15445
|
since: number(),
|
|
15458
15446
|
until: number(),
|
|
@@ -15497,11 +15485,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15497
15485
|
timestamp: number()
|
|
15498
15486
|
});
|
|
15499
15487
|
var CameraPipelineConfigSchema = object({
|
|
15500
|
-
engine: PipelineEngineChoiceSchema,
|
|
15488
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
15501
15489
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
15502
15490
|
audio: object({
|
|
15503
|
-
engine: PipelineEngineChoiceSchema,
|
|
15504
|
-
modelId: string(),
|
|
15491
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
15492
|
+
modelId: string().optional(),
|
|
15505
15493
|
enabled: boolean(),
|
|
15506
15494
|
settings: record(string(), unknown()).readonly().optional()
|
|
15507
15495
|
}).nullable().optional()
|
|
@@ -15516,7 +15504,7 @@ var PipelineTemplateSchema = object({
|
|
|
15516
15504
|
});
|
|
15517
15505
|
var AgentAddonConfigSchema = object({
|
|
15518
15506
|
enabled: boolean(),
|
|
15519
|
-
modelId: string(),
|
|
15507
|
+
modelId: string().optional(),
|
|
15520
15508
|
settings: record(string(), unknown()).readonly()
|
|
15521
15509
|
});
|
|
15522
15510
|
var AgentPipelineSettingsSchema = object({
|
|
@@ -15526,12 +15514,25 @@ var AgentPipelineSettingsSchema = object({
|
|
|
15526
15514
|
detectWeight: number().positive().optional(),
|
|
15527
15515
|
/** Node is eligible to run the detection pipeline (decode + inference). */
|
|
15528
15516
|
detect: boolean().optional(),
|
|
15529
|
-
/**
|
|
15517
|
+
/**
|
|
15518
|
+
* DEPRECATED AND IGNORED. Decode is always co-located with its frame
|
|
15519
|
+
* consumer, so decode eligibility IS detect eligibility. Kept optional in
|
|
15520
|
+
* the schema ONLY so persisted stores written before the removal still
|
|
15521
|
+
* parse — no code reads it and no write path emits it.
|
|
15522
|
+
*/
|
|
15530
15523
|
decode: boolean().optional(),
|
|
15531
15524
|
/** Node is eligible to run audio-analyzer sessions. */
|
|
15532
15525
|
audio: boolean().optional(),
|
|
15533
15526
|
/** Node is eligible to be the ingest / source-owner (serve the restream). */
|
|
15534
|
-
ingest: boolean().optional()
|
|
15527
|
+
ingest: boolean().optional(),
|
|
15528
|
+
/**
|
|
15529
|
+
* Operator override for the LAN host a cross-node decoder dials to reach
|
|
15530
|
+
* THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
|
|
15531
|
+
* falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
|
|
15532
|
+
* it already uses to reach the hub). Set this only when the auto-detected
|
|
15533
|
+
* address is wrong (multi-homed host, NAT, custom interface).
|
|
15534
|
+
*/
|
|
15535
|
+
reachableHost: string().optional()
|
|
15535
15536
|
});
|
|
15536
15537
|
var CameraPipelineForAgentSchema = object({
|
|
15537
15538
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -15579,25 +15580,6 @@ var PipelineAssignmentSchema = object({
|
|
|
15579
15580
|
assignedAt: number()
|
|
15580
15581
|
});
|
|
15581
15582
|
/**
|
|
15582
|
-
* Decoder placement record. Symmetric to `PipelineAssignmentSchema` but for
|
|
15583
|
-
* the decoder-node placement domain (`balanceDecoder` decision: manual pin
|
|
15584
|
-
* → co-located with pipeline → capacity).
|
|
15585
|
-
*/
|
|
15586
|
-
var DecoderAssignmentSchema = object({
|
|
15587
|
-
deviceId: number(),
|
|
15588
|
-
/** Moleculer node id of the decoder provider currently responsible for this camera. */
|
|
15589
|
-
decoderNodeId: string(),
|
|
15590
|
-
/** True when the assignment was set manually via `assignDecoder`, false when chosen by the balancer. */
|
|
15591
|
-
pinned: boolean(),
|
|
15592
|
-
/** Why this assignment was made — useful for debugging the decoder balancer. */
|
|
15593
|
-
reason: _enum([
|
|
15594
|
-
"manual",
|
|
15595
|
-
"co-located",
|
|
15596
|
-
"capacity",
|
|
15597
|
-
"hardware-affinity"
|
|
15598
|
-
])
|
|
15599
|
-
});
|
|
15600
|
-
/**
|
|
15601
15583
|
* Per-agent load summary surfaced to the load balancer + dashboards.
|
|
15602
15584
|
* Aggregated from each runner's `getLocalLoad` cap call.
|
|
15603
15585
|
*/
|
|
@@ -15637,6 +15619,15 @@ var GlobalMetricsSchema = object({
|
|
|
15637
15619
|
* capability providers.
|
|
15638
15620
|
*/
|
|
15639
15621
|
var CapabilityBindingsSchema = record(string(), string());
|
|
15622
|
+
/**
|
|
15623
|
+
* The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
|
|
15624
|
+
* its LAN-reachable host, if one is registered. See `getIngestOwner`.
|
|
15625
|
+
*/
|
|
15626
|
+
var IngestOwnerSchema = object({
|
|
15627
|
+
ownerNodeId: string(),
|
|
15628
|
+
reachableHost: string().optional(),
|
|
15629
|
+
configIssue: string().optional()
|
|
15630
|
+
});
|
|
15640
15631
|
/** Source block — always present; derives from the stream catalog. */
|
|
15641
15632
|
var CameraSourceStatusSchema = object({ streams: array(object({
|
|
15642
15633
|
camStreamId: string(),
|
|
@@ -15651,6 +15642,14 @@ var CameraAssignmentStatusSchema = object({
|
|
|
15651
15642
|
detectionNodeId: string().nullable(),
|
|
15652
15643
|
decoderNodeId: string().nullable(),
|
|
15653
15644
|
audioNodeId: string().nullable(),
|
|
15645
|
+
/**
|
|
15646
|
+
* The node that OWNS this camera's physical source pull (dials the RTSP and
|
|
15647
|
+
* hosts the broker/restream) — the cluster ingest owner today
|
|
15648
|
+
* (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
|
|
15649
|
+
* the UI show WHERE a camera is sourced without SSH/logs, and is the node the
|
|
15650
|
+
* broker block below was read from (pinned). Nullable only pre-wiring.
|
|
15651
|
+
*/
|
|
15652
|
+
sourceNodeId: string().nullable(),
|
|
15654
15653
|
pinned: object({
|
|
15655
15654
|
detection: boolean(),
|
|
15656
15655
|
decoder: boolean(),
|
|
@@ -15783,16 +15782,7 @@ method(object({
|
|
|
15783
15782
|
}), object({ success: literal(true) }), {
|
|
15784
15783
|
kind: "mutation",
|
|
15785
15784
|
auth: "admin"
|
|
15786
|
-
}), method(object({
|
|
15787
|
-
deviceId: number(),
|
|
15788
|
-
nodeId: string()
|
|
15789
|
-
}), _void(), {
|
|
15790
|
-
kind: "mutation",
|
|
15791
|
-
auth: "admin"
|
|
15792
|
-
}), method(object({ deviceId: number() }), _void(), {
|
|
15793
|
-
kind: "mutation",
|
|
15794
|
-
auth: "admin"
|
|
15795
|
-
}), method(_void(), array(DecoderAssignmentSchema).readonly()), method(object({
|
|
15785
|
+
}), method(_void(), IngestOwnerSchema), method(object({
|
|
15796
15786
|
deviceId: number(),
|
|
15797
15787
|
nodeId: string()
|
|
15798
15788
|
}), object({ success: literal(true) }), {
|
|
@@ -15813,10 +15803,7 @@ method(object({
|
|
|
15813
15803
|
nodeId: string(),
|
|
15814
15804
|
pinned: boolean(),
|
|
15815
15805
|
assignedAt: number()
|
|
15816
|
-
}))), method(object({
|
|
15817
|
-
deviceId: number(),
|
|
15818
|
-
pipelineNodeId: string().optional()
|
|
15819
|
-
}), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
|
|
15806
|
+
}))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
|
|
15820
15807
|
nodeId: string(),
|
|
15821
15808
|
settings: AgentPipelineSettingsSchema
|
|
15822
15809
|
})).readonly()), method(object({
|
|
@@ -15846,12 +15833,26 @@ method(object({
|
|
|
15846
15833
|
}), method(object({
|
|
15847
15834
|
agentNodeId: string(),
|
|
15848
15835
|
detect: boolean().nullable().optional(),
|
|
15849
|
-
decode: boolean().nullable().optional(),
|
|
15850
15836
|
audio: boolean().nullable().optional(),
|
|
15851
15837
|
ingest: boolean().nullable().optional()
|
|
15852
15838
|
}), object({ success: literal(true) }), {
|
|
15853
15839
|
kind: "mutation",
|
|
15854
15840
|
auth: "admin"
|
|
15841
|
+
}), method(object({
|
|
15842
|
+
agentNodeId: string(),
|
|
15843
|
+
reachableHost: string().nullable()
|
|
15844
|
+
}), object({ success: literal(true) }), {
|
|
15845
|
+
kind: "mutation",
|
|
15846
|
+
auth: "admin"
|
|
15847
|
+
}), method(object({ agentNodeId: string() }), object({
|
|
15848
|
+
success: literal(true),
|
|
15849
|
+
/** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
|
|
15850
|
+
effectiveModelId: string().nullable(),
|
|
15851
|
+
/** Number of cameras whose node-scoped overrides were cleared. */
|
|
15852
|
+
clearedCameraOverrides: number()
|
|
15853
|
+
}), {
|
|
15854
|
+
kind: "mutation",
|
|
15855
|
+
auth: "admin"
|
|
15855
15856
|
}), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
|
|
15856
15857
|
deviceId: number(),
|
|
15857
15858
|
addonId: string(),
|
|
@@ -15896,22 +15897,131 @@ method(object({
|
|
|
15896
15897
|
kind: "mutation",
|
|
15897
15898
|
auth: "admin"
|
|
15898
15899
|
});
|
|
15899
|
-
|
|
15900
|
-
|
|
15901
|
-
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15900
|
+
/**
|
|
15901
|
+
* server-management — per-NODE singleton capability for a node's ROOT
|
|
15902
|
+
* package lifecycle (runtime-updatable node packages, phase 2: hub + docker
|
|
15903
|
+
* agents).
|
|
15904
|
+
*
|
|
15905
|
+
* Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
|
|
15906
|
+
* on agents) carries the whole software stack in its npm dep tree, so ONE
|
|
15907
|
+
* version describes the node. Updates install into
|
|
15908
|
+
* `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
|
|
15909
|
+
* starter (probation boot + auto-rollback to N-1).
|
|
15910
|
+
*
|
|
15911
|
+
* Providers:
|
|
15912
|
+
* - HUB: `ServerUpdateService` behind the `server-provided` mount
|
|
15913
|
+
* (`buildServerProviders` in trpc.router.ts) — the default target for
|
|
15914
|
+
* unpinned calls.
|
|
15915
|
+
* - AGENT: `AgentUpdateService` registered by the agent bootstrap under
|
|
15916
|
+
* the synthetic `agent-runtime` addonId and declared in the agent's
|
|
15917
|
+
* `$hub.registerNode` manifest.
|
|
15918
|
+
*
|
|
15919
|
+
* Node routing: singleton caps get the codegen/runtime-builder `nodeId`
|
|
15920
|
+
* injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
|
|
15921
|
+
* SDK) routes the call to that node's provider via the standard remote
|
|
15922
|
+
* proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
|
|
15923
|
+
* in-process provider lookup). No `nodeId` → the hub's own provider.
|
|
15924
|
+
*
|
|
15925
|
+
* Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
|
|
15926
|
+
*/
|
|
15927
|
+
/**
|
|
15928
|
+
* Where the running hub's code was loaded from:
|
|
15929
|
+
* - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
|
|
15930
|
+
* plain resolution and runtime updates are refused.
|
|
15931
|
+
* - `baked` — the immutable image seed closure (no data-dir root active).
|
|
15932
|
+
* - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
|
|
15933
|
+
*/
|
|
15934
|
+
var ServerBootModeSchema = _enum([
|
|
15935
|
+
"workspace",
|
|
15936
|
+
"baked",
|
|
15937
|
+
"data-root"
|
|
15938
|
+
]);
|
|
15939
|
+
/**
|
|
15940
|
+
* Update lifecycle state:
|
|
15941
|
+
* - `idle` / `checking` / `staging` — steady / in-flight registry work.
|
|
15942
|
+
* - `pending-restart` — a version is staged and the node has NOT yet
|
|
15943
|
+
* restarted onto it (still running the OLD version).
|
|
15944
|
+
* - `awaiting-confirmation` — the node HAS restarted onto the staged version
|
|
15945
|
+
* (it is the active probation boot) and is waiting to confirm boot-health.
|
|
15946
|
+
* Apply/rollback are refused in this state and the node must NOT be
|
|
15947
|
+
* manually restarted, or the probation boot auto-rolls-back.
|
|
15948
|
+
*/
|
|
15949
|
+
var ServerUpdateStateSchema = _enum([
|
|
15950
|
+
"idle",
|
|
15951
|
+
"checking",
|
|
15952
|
+
"staging",
|
|
15953
|
+
"pending-restart",
|
|
15954
|
+
"awaiting-confirmation"
|
|
15955
|
+
]);
|
|
15956
|
+
var ServerRollbackInfoSchema = object({
|
|
15957
|
+
/** The version that failed (or was manually rolled back). */
|
|
15958
|
+
fromVersion: string(),
|
|
15959
|
+
/** The version rolled back to; null = the baked seed. */
|
|
15960
|
+
toVersion: string().nullable(),
|
|
15961
|
+
atMs: number(),
|
|
15962
|
+
reason: string()
|
|
15905
15963
|
});
|
|
15906
|
-
var
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15964
|
+
var ServerPackageStatusSchema = object({
|
|
15965
|
+
/** Root package name (`@camstack/server` on the hub). */
|
|
15966
|
+
packageName: string(),
|
|
15967
|
+
/** Version of the code the running process ACTUALLY loaded. */
|
|
15968
|
+
runningVersion: string().nullable(),
|
|
15969
|
+
/** Node.js runtime version the node's process runs on (`process.versions.node`). */
|
|
15970
|
+
nodeRuntimeVersion: string().nullable(),
|
|
15971
|
+
/** Active data-dir root version; null when booted from seed/workspace. */
|
|
15972
|
+
activeVersion: string().nullable(),
|
|
15973
|
+
/** N-1 version kept for rollback; null when no previous version exists. */
|
|
15974
|
+
previousVersion: string().nullable(),
|
|
15975
|
+
/** Version of the immutable baked seed closure (image fallback). */
|
|
15976
|
+
seedVersion: string().nullable(),
|
|
15977
|
+
/** Latest registry version from the most recent check (null = never checked). */
|
|
15978
|
+
latestVersion: string().nullable(),
|
|
15979
|
+
updateAvailable: boolean(),
|
|
15980
|
+
bootMode: ServerBootModeSchema,
|
|
15981
|
+
updateState: ServerUpdateStateSchema,
|
|
15982
|
+
/** Version staged + awaiting its probation boot, when one is pending. */
|
|
15983
|
+
pendingVersion: string().nullable(),
|
|
15984
|
+
/** Set when the last freshly-activated version failed its boot health-check. */
|
|
15985
|
+
rolledBack: ServerRollbackInfoSchema.nullable(),
|
|
15986
|
+
/**
|
|
15987
|
+
* True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
|
|
15988
|
+
* hub is running from the baked seed (or workspace) while installed data-dir
|
|
15989
|
+
* versions are being IGNORED. Surfaced as a warning in the UI.
|
|
15990
|
+
*/
|
|
15991
|
+
stateFileCorrupt: boolean(),
|
|
15992
|
+
lastCheckedAtMs: number().nullable()
|
|
15993
|
+
});
|
|
15994
|
+
var ServerUpdateCheckResultSchema = object({
|
|
15995
|
+
packageName: string(),
|
|
15996
|
+
runningVersion: string().nullable(),
|
|
15997
|
+
latestVersion: string().nullable(),
|
|
15998
|
+
updateAvailable: boolean(),
|
|
15999
|
+
checkedAtMs: number(),
|
|
16000
|
+
/** Non-null when the registry lookup failed (offline, bad registry, …). */
|
|
16001
|
+
error: string().nullable()
|
|
16002
|
+
});
|
|
16003
|
+
var ServerUpdateActionResultSchema = object({
|
|
16004
|
+
accepted: boolean(),
|
|
16005
|
+
targetVersion: string().nullable(),
|
|
16006
|
+
/** True when a graceful restart was scheduled to apply the change. */
|
|
16007
|
+
restarting: boolean(),
|
|
16008
|
+
message: string()
|
|
16009
|
+
});
|
|
16010
|
+
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
16011
|
+
kind: "mutation",
|
|
16012
|
+
auth: "admin"
|
|
16013
|
+
}), method(object({
|
|
16014
|
+
/** Explicit target version; omitted = latest from the registry. */
|
|
16015
|
+
version: string().optional() }), ServerUpdateActionResultSchema, {
|
|
16016
|
+
kind: "mutation",
|
|
16017
|
+
auth: "admin"
|
|
16018
|
+
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
16019
|
+
kind: "mutation",
|
|
16020
|
+
auth: "admin"
|
|
16021
|
+
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
16022
|
+
kind: "mutation",
|
|
16023
|
+
auth: "admin"
|
|
15910
16024
|
});
|
|
15911
|
-
method(object({
|
|
15912
|
-
deviceId: number(),
|
|
15913
|
-
streams: array(RegisteredStreamSchema).readonly()
|
|
15914
|
-
}), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(ExposedResourceSchema).readonly());
|
|
15915
16025
|
/**
|
|
15916
16026
|
* Query filter for settings-store collections.
|
|
15917
16027
|
*/
|
|
@@ -16064,9 +16174,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
|
|
|
16064
16174
|
/**
|
|
16065
16175
|
* A single device snapshot returned as base64 JPEG/PNG.
|
|
16066
16176
|
*
|
|
16067
|
-
*
|
|
16068
|
-
*
|
|
16069
|
-
*
|
|
16177
|
+
* The `SnapshotAddon` wrapper returns this shape whether the frame came from
|
|
16178
|
+
* the device-native provider (onboard capture) or from the stream-broker
|
|
16179
|
+
* prebuffer fallback.
|
|
16070
16180
|
*/
|
|
16071
16181
|
var SnapshotImageSchema = object({
|
|
16072
16182
|
base64: string(),
|
|
@@ -16097,11 +16207,12 @@ DeviceType.Camera, method(object({
|
|
|
16097
16207
|
}), SnapshotImageSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
16098
16208
|
kind: "mutation",
|
|
16099
16209
|
auth: "admin"
|
|
16100
|
-
})
|
|
16101
|
-
method(object({ deviceId: number() }), boolean()), method(object({
|
|
16210
|
+
}), systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
|
|
16102
16211
|
deviceId: number(),
|
|
16103
|
-
|
|
16104
|
-
|
|
16212
|
+
lastCapturedAt: number().nullable(),
|
|
16213
|
+
cacheAgeMs: number().nullable(),
|
|
16214
|
+
etag: string().nullable()
|
|
16215
|
+
})));
|
|
16105
16216
|
/**
|
|
16106
16217
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
|
16107
16218
|
* providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
|
|
@@ -16352,10 +16463,32 @@ method(_void(), array(TurnServerSchema).readonly());
|
|
|
16352
16463
|
* b. `finishAuthentication({userId, response})` → server verifies
|
|
16353
16464
|
* the assertion, bumps the credential counter, returns ok.
|
|
16354
16465
|
*
|
|
16466
|
+
* 2b. Usernameless (discoverable-credential) authentication — the
|
|
16467
|
+
* passkey IS the primary factor, no password leg:
|
|
16468
|
+
* a. `beginDiscoverableAuthentication({})` → assertion options with
|
|
16469
|
+
* EMPTY `allowCredentials` (the browser offers every resident
|
|
16470
|
+
* passkey it holds for this RP) + `userVerification: 'required'`
|
|
16471
|
+
* (the passkey replaces both factors, so UV is mandatory).
|
|
16472
|
+
* The challenge is stored server-side, NOT bound to any user.
|
|
16473
|
+
* b. `finishDiscoverableAuthentication({response})` → the provider
|
|
16474
|
+
* resolves the credential by the response's credential id,
|
|
16475
|
+
* verifies the assertion against the stored challenge + that
|
|
16476
|
+
* credential's public key/counter, and returns the OWNING
|
|
16477
|
+
* `userId` — the caller (core auth router) mints the session.
|
|
16478
|
+
*
|
|
16355
16479
|
* 3. Management:
|
|
16356
16480
|
* - `listPasskeys({userId})` — enumerate user's enrolled credentials.
|
|
16357
16481
|
* - `removePasskey({userId, credentialId})` — revoke one credential.
|
|
16358
16482
|
*
|
|
16483
|
+
* 4. Second-factor preference (opt-in, default OFF):
|
|
16484
|
+
* Enrolling a passkey only enables passkey-FIRST sign-in. It is
|
|
16485
|
+
* demanded as a second factor after a password login ONLY when the
|
|
16486
|
+
* user explicitly opts in via `setSecondFactorPreference`.
|
|
16487
|
+
* - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
|
|
16488
|
+
* row ⇒ `enabled: false`).
|
|
16489
|
+
* - `setSecondFactorPreference({userId, enabled})` — persisted by
|
|
16490
|
+
* the providing addon beside its credentials.
|
|
16491
|
+
*
|
|
16359
16492
|
* Challenges are short-lived (5 min, in-memory). The cap is internal —
|
|
16360
16493
|
* the admin-ui composes the begin/finish round-trip and never exposes
|
|
16361
16494
|
* the cap to non-admins.
|
|
@@ -16398,6 +16531,17 @@ method(object({
|
|
|
16398
16531
|
}), object({ verified: boolean() }), {
|
|
16399
16532
|
kind: "mutation",
|
|
16400
16533
|
access: "view"
|
|
16534
|
+
}), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
|
|
16535
|
+
kind: "mutation",
|
|
16536
|
+
access: "view"
|
|
16537
|
+
}), method(object({
|
|
16538
|
+
/** AuthenticationResponseJSON from the browser. */
|
|
16539
|
+
response: record(string(), unknown()) }), object({
|
|
16540
|
+
verified: boolean(),
|
|
16541
|
+
userId: string().nullable()
|
|
16542
|
+
}), {
|
|
16543
|
+
kind: "mutation",
|
|
16544
|
+
access: "view"
|
|
16401
16545
|
}), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
|
|
16402
16546
|
userId: string(),
|
|
16403
16547
|
credentialId: string()
|
|
@@ -16405,6 +16549,13 @@ method(object({
|
|
|
16405
16549
|
kind: "mutation",
|
|
16406
16550
|
auth: "admin",
|
|
16407
16551
|
access: "delete"
|
|
16552
|
+
}), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
|
|
16553
|
+
userId: string(),
|
|
16554
|
+
enabled: boolean()
|
|
16555
|
+
}), object({ success: literal(true) }), {
|
|
16556
|
+
kind: "mutation",
|
|
16557
|
+
auth: "admin",
|
|
16558
|
+
access: "create"
|
|
16408
16559
|
});
|
|
16409
16560
|
/**
|
|
16410
16561
|
* `videoclips` — the unified, navigable-clip surface for a camera.
|
|
@@ -16462,9 +16613,10 @@ method(object({
|
|
|
16462
16613
|
auth: "admin"
|
|
16463
16614
|
});
|
|
16464
16615
|
/**
|
|
16465
|
-
* Optional client-side hints sent at session creation to help the
|
|
16466
|
-
*
|
|
16467
|
-
*
|
|
16616
|
+
* Optional client-side hints sent at session creation to help the provider
|
|
16617
|
+
* pick the best native source. All fields optional — a viewer that knows
|
|
16618
|
+
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
16619
|
+
* collection cap; this `webrtc-session` cap is the live signaling surface.)
|
|
16468
16620
|
*/
|
|
16469
16621
|
var webrtcClientHintsSchema = object({
|
|
16470
16622
|
viewportWidth: number().int().positive().optional(),
|
|
@@ -16475,22 +16627,6 @@ var webrtcClientHintsSchema = object({
|
|
|
16475
16627
|
/** Hard tier override; takes precedence over scoring when registered. */
|
|
16476
16628
|
prefersTier: string().optional()
|
|
16477
16629
|
}).partial();
|
|
16478
|
-
method(object({
|
|
16479
|
-
streamId: string(),
|
|
16480
|
-
sdpOffer: string()
|
|
16481
|
-
}), string(), { kind: "mutation" }), method(object({ streamId: string() }), boolean()), method(object({
|
|
16482
|
-
streamId: string(),
|
|
16483
|
-
codec: string()
|
|
16484
|
-
}), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
16485
|
-
streamId: string(),
|
|
16486
|
-
hints: webrtcClientHintsSchema.optional()
|
|
16487
|
-
}), object({
|
|
16488
|
-
sessionId: string(),
|
|
16489
|
-
sdpOffer: string()
|
|
16490
|
-
}), { kind: "mutation" }), method(object({
|
|
16491
|
-
sessionId: string(),
|
|
16492
|
-
sdpAnswer: string()
|
|
16493
|
-
}), _void(), { kind: "mutation" }), method(object({ sessionId: string() }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), boolean());
|
|
16494
16630
|
/**
|
|
16495
16631
|
* Discriminated target for a WebRTC session. The client sends this
|
|
16496
16632
|
* structured object instead of building / parsing brokerId strings;
|
|
@@ -17221,7 +17357,17 @@ var FaceInfoSchema = object({
|
|
|
17221
17357
|
recognizedIdentityId: string().optional(),
|
|
17222
17358
|
identityName: string().optional(),
|
|
17223
17359
|
assigned: boolean(),
|
|
17224
|
-
base64: string().optional()
|
|
17360
|
+
base64: string().optional(),
|
|
17361
|
+
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
17362
|
+
* view draw the box over the native `keyFrameMediaKey` frame. Absent on
|
|
17363
|
+
* legacy rows written before design B. */
|
|
17364
|
+
faceBbox: BoundingBoxSchema.optional(),
|
|
17365
|
+
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
17366
|
+
* Fetch the native JPEG via the event-media data-plane
|
|
17367
|
+
* (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
|
|
17368
|
+
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
17369
|
+
* back to the inline `base64` face crop. */
|
|
17370
|
+
keyFrameMediaKey: string().optional()
|
|
17225
17371
|
});
|
|
17226
17372
|
var FaceFilterEnum = _enum([
|
|
17227
17373
|
"unassigned",
|
|
@@ -17918,6 +18064,16 @@ var TopologyCategorySchema = object({
|
|
|
17918
18064
|
healthy: number(),
|
|
17919
18065
|
addons: array(TopologyCategoryAddonSchema).readonly()
|
|
17920
18066
|
});
|
|
18067
|
+
/**
|
|
18068
|
+
* The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
|
|
18069
|
+
* `@camstack/agent` on agents) as reported by its `registerNode` manifest —
|
|
18070
|
+
* version visibility for the Server management surface. Nullable: offline
|
|
18071
|
+
* rows and pre-phase-2 nodes report none.
|
|
18072
|
+
*/
|
|
18073
|
+
var TopologyRootPackageSchema = object({
|
|
18074
|
+
name: string(),
|
|
18075
|
+
version: string()
|
|
18076
|
+
});
|
|
17921
18077
|
var TopologyNodeSchema = object({
|
|
17922
18078
|
id: string(),
|
|
17923
18079
|
name: string(),
|
|
@@ -17941,7 +18097,8 @@ var TopologyNodeSchema = object({
|
|
|
17941
18097
|
status: string()
|
|
17942
18098
|
})).readonly(),
|
|
17943
18099
|
processes: array(TopologyProcessSchema).readonly(),
|
|
17944
|
-
categories: array(TopologyCategorySchema).readonly()
|
|
18100
|
+
categories: array(TopologyCategorySchema).readonly(),
|
|
18101
|
+
rootPackage: TopologyRootPackageSchema.nullable()
|
|
17945
18102
|
});
|
|
17946
18103
|
var CapUsageEdgeSchema = object({
|
|
17947
18104
|
callerAddonId: string(),
|
|
@@ -20741,6 +20898,12 @@ Object.freeze({
|
|
|
20741
20898
|
addonId: null,
|
|
20742
20899
|
access: "create"
|
|
20743
20900
|
},
|
|
20901
|
+
"loginMethod.getLoginMethods": {
|
|
20902
|
+
capName: "login-method",
|
|
20903
|
+
capScope: "system",
|
|
20904
|
+
addonId: null,
|
|
20905
|
+
access: "view"
|
|
20906
|
+
},
|
|
20744
20907
|
"mediaPlayer.next": {
|
|
20745
20908
|
capName: "media-player",
|
|
20746
20909
|
capScope: "device",
|
|
@@ -21323,6 +21486,12 @@ Object.freeze({
|
|
|
21323
21486
|
addonId: null,
|
|
21324
21487
|
access: "view"
|
|
21325
21488
|
},
|
|
21489
|
+
"pipelineAnalytics.getKeyEvents": {
|
|
21490
|
+
capName: "pipeline-analytics",
|
|
21491
|
+
capScope: "device",
|
|
21492
|
+
addonId: null,
|
|
21493
|
+
access: "view"
|
|
21494
|
+
},
|
|
21326
21495
|
"pipelineAnalytics.getMotionEvents": {
|
|
21327
21496
|
capName: "pipeline-analytics",
|
|
21328
21497
|
capScope: "device",
|
|
@@ -21371,23 +21540,23 @@ Object.freeze({
|
|
|
21371
21540
|
addonId: null,
|
|
21372
21541
|
access: "create"
|
|
21373
21542
|
},
|
|
21374
|
-
"pipelineExecutor.
|
|
21543
|
+
"pipelineExecutor.clearDeviceOverrides": {
|
|
21375
21544
|
capName: "pipeline-executor",
|
|
21376
21545
|
capScope: "system",
|
|
21377
21546
|
addonId: null,
|
|
21378
21547
|
access: "delete"
|
|
21379
21548
|
},
|
|
21380
|
-
"pipelineExecutor.
|
|
21549
|
+
"pipelineExecutor.deleteModel": {
|
|
21381
21550
|
capName: "pipeline-executor",
|
|
21382
21551
|
capScope: "system",
|
|
21383
21552
|
addonId: null,
|
|
21384
21553
|
access: "delete"
|
|
21385
21554
|
},
|
|
21386
|
-
"pipelineExecutor.
|
|
21555
|
+
"pipelineExecutor.deleteTemplate": {
|
|
21387
21556
|
capName: "pipeline-executor",
|
|
21388
21557
|
capScope: "system",
|
|
21389
21558
|
addonId: null,
|
|
21390
|
-
access: "
|
|
21559
|
+
access: "delete"
|
|
21391
21560
|
},
|
|
21392
21561
|
"pipelineExecutor.downloadModel": {
|
|
21393
21562
|
capName: "pipeline-executor",
|
|
@@ -21581,13 +21750,13 @@ Object.freeze({
|
|
|
21581
21750
|
addonId: null,
|
|
21582
21751
|
access: "create"
|
|
21583
21752
|
},
|
|
21584
|
-
"
|
|
21585
|
-
capName: "pipeline-
|
|
21753
|
+
"pipelineExecutor.validatePipeline": {
|
|
21754
|
+
capName: "pipeline-executor",
|
|
21586
21755
|
capScope: "system",
|
|
21587
21756
|
addonId: null,
|
|
21588
|
-
access: "
|
|
21757
|
+
access: "view"
|
|
21589
21758
|
},
|
|
21590
|
-
"pipelineOrchestrator.
|
|
21759
|
+
"pipelineOrchestrator.assignAudio": {
|
|
21591
21760
|
capName: "pipeline-orchestrator",
|
|
21592
21761
|
capScope: "system",
|
|
21593
21762
|
addonId: null,
|
|
@@ -21671,19 +21840,13 @@ Object.freeze({
|
|
|
21671
21840
|
addonId: null,
|
|
21672
21841
|
access: "view"
|
|
21673
21842
|
},
|
|
21674
|
-
"pipelineOrchestrator.
|
|
21675
|
-
capName: "pipeline-orchestrator",
|
|
21676
|
-
capScope: "system",
|
|
21677
|
-
addonId: null,
|
|
21678
|
-
access: "view"
|
|
21679
|
-
},
|
|
21680
|
-
"pipelineOrchestrator.getDecoderAssignments": {
|
|
21843
|
+
"pipelineOrchestrator.getGlobalMetrics": {
|
|
21681
21844
|
capName: "pipeline-orchestrator",
|
|
21682
21845
|
capScope: "system",
|
|
21683
21846
|
addonId: null,
|
|
21684
21847
|
access: "view"
|
|
21685
21848
|
},
|
|
21686
|
-
"pipelineOrchestrator.
|
|
21849
|
+
"pipelineOrchestrator.getIngestOwner": {
|
|
21687
21850
|
capName: "pipeline-orchestrator",
|
|
21688
21851
|
capScope: "system",
|
|
21689
21852
|
addonId: null,
|
|
@@ -21725,6 +21888,12 @@ Object.freeze({
|
|
|
21725
21888
|
addonId: null,
|
|
21726
21889
|
access: "delete"
|
|
21727
21890
|
},
|
|
21891
|
+
"pipelineOrchestrator.resetNodePipelineDefaults": {
|
|
21892
|
+
capName: "pipeline-orchestrator",
|
|
21893
|
+
capScope: "system",
|
|
21894
|
+
addonId: null,
|
|
21895
|
+
access: "delete"
|
|
21896
|
+
},
|
|
21728
21897
|
"pipelineOrchestrator.resolvePipeline": {
|
|
21729
21898
|
capName: "pipeline-orchestrator",
|
|
21730
21899
|
capScope: "system",
|
|
@@ -21761,37 +21930,37 @@ Object.freeze({
|
|
|
21761
21930
|
addonId: null,
|
|
21762
21931
|
access: "create"
|
|
21763
21932
|
},
|
|
21764
|
-
"pipelineOrchestrator.
|
|
21933
|
+
"pipelineOrchestrator.setAgentReachableHost": {
|
|
21765
21934
|
capName: "pipeline-orchestrator",
|
|
21766
21935
|
capScope: "system",
|
|
21767
21936
|
addonId: null,
|
|
21768
21937
|
access: "create"
|
|
21769
21938
|
},
|
|
21770
|
-
"pipelineOrchestrator.
|
|
21939
|
+
"pipelineOrchestrator.setCameraPipelineForAgent": {
|
|
21771
21940
|
capName: "pipeline-orchestrator",
|
|
21772
21941
|
capScope: "system",
|
|
21773
21942
|
addonId: null,
|
|
21774
21943
|
access: "create"
|
|
21775
21944
|
},
|
|
21776
|
-
"pipelineOrchestrator.
|
|
21945
|
+
"pipelineOrchestrator.setCameraStepOverride": {
|
|
21777
21946
|
capName: "pipeline-orchestrator",
|
|
21778
21947
|
capScope: "system",
|
|
21779
21948
|
addonId: null,
|
|
21780
21949
|
access: "create"
|
|
21781
21950
|
},
|
|
21782
|
-
"pipelineOrchestrator.
|
|
21951
|
+
"pipelineOrchestrator.setCameraStepToggle": {
|
|
21783
21952
|
capName: "pipeline-orchestrator",
|
|
21784
21953
|
capScope: "system",
|
|
21785
21954
|
addonId: null,
|
|
21786
21955
|
access: "create"
|
|
21787
21956
|
},
|
|
21788
|
-
"pipelineOrchestrator.
|
|
21957
|
+
"pipelineOrchestrator.setCapabilityBinding": {
|
|
21789
21958
|
capName: "pipeline-orchestrator",
|
|
21790
21959
|
capScope: "system",
|
|
21791
21960
|
addonId: null,
|
|
21792
21961
|
access: "create"
|
|
21793
21962
|
},
|
|
21794
|
-
"pipelineOrchestrator.
|
|
21963
|
+
"pipelineOrchestrator.unassignAudio": {
|
|
21795
21964
|
capName: "pipeline-orchestrator",
|
|
21796
21965
|
capScope: "system",
|
|
21797
21966
|
addonId: null,
|
|
@@ -21851,6 +22020,12 @@ Object.freeze({
|
|
|
21851
22020
|
addonId: null,
|
|
21852
22021
|
access: "view"
|
|
21853
22022
|
},
|
|
22023
|
+
"pipelineRunner.getNativeCrop": {
|
|
22024
|
+
capName: "pipeline-runner",
|
|
22025
|
+
capScope: "system",
|
|
22026
|
+
addonId: null,
|
|
22027
|
+
access: "view"
|
|
22028
|
+
},
|
|
21854
22029
|
"pipelineRunner.reportMotion": {
|
|
21855
22030
|
capName: "pipeline-runner",
|
|
21856
22031
|
capScope: "system",
|
|
@@ -22091,33 +22266,45 @@ Object.freeze({
|
|
|
22091
22266
|
addonId: null,
|
|
22092
22267
|
access: "create"
|
|
22093
22268
|
},
|
|
22094
|
-
"
|
|
22095
|
-
capName: "
|
|
22269
|
+
"scriptRunner.run": {
|
|
22270
|
+
capName: "script-runner",
|
|
22271
|
+
capScope: "device",
|
|
22272
|
+
addonId: null,
|
|
22273
|
+
access: "create"
|
|
22274
|
+
},
|
|
22275
|
+
"scriptRunner.stop": {
|
|
22276
|
+
capName: "script-runner",
|
|
22277
|
+
capScope: "device",
|
|
22278
|
+
addonId: null,
|
|
22279
|
+
access: "create"
|
|
22280
|
+
},
|
|
22281
|
+
"serverManagement.applyServerUpdate": {
|
|
22282
|
+
capName: "server-management",
|
|
22096
22283
|
capScope: "system",
|
|
22097
22284
|
addonId: null,
|
|
22098
|
-
access: "
|
|
22285
|
+
access: "create"
|
|
22099
22286
|
},
|
|
22100
|
-
"
|
|
22101
|
-
capName: "
|
|
22287
|
+
"serverManagement.checkServerUpdate": {
|
|
22288
|
+
capName: "server-management",
|
|
22102
22289
|
capScope: "system",
|
|
22103
22290
|
addonId: null,
|
|
22104
22291
|
access: "create"
|
|
22105
22292
|
},
|
|
22106
|
-
"
|
|
22107
|
-
capName: "
|
|
22293
|
+
"serverManagement.getServerPackageStatus": {
|
|
22294
|
+
capName: "server-management",
|
|
22108
22295
|
capScope: "system",
|
|
22109
22296
|
addonId: null,
|
|
22110
|
-
access: "
|
|
22297
|
+
access: "view"
|
|
22111
22298
|
},
|
|
22112
|
-
"
|
|
22113
|
-
capName: "
|
|
22114
|
-
capScope: "
|
|
22299
|
+
"serverManagement.restartServer": {
|
|
22300
|
+
capName: "server-management",
|
|
22301
|
+
capScope: "system",
|
|
22115
22302
|
addonId: null,
|
|
22116
22303
|
access: "create"
|
|
22117
22304
|
},
|
|
22118
|
-
"
|
|
22119
|
-
capName: "
|
|
22120
|
-
capScope: "
|
|
22305
|
+
"serverManagement.rollbackServerUpdate": {
|
|
22306
|
+
capName: "server-management",
|
|
22307
|
+
capScope: "system",
|
|
22121
22308
|
addonId: null,
|
|
22122
22309
|
access: "create"
|
|
22123
22310
|
},
|
|
@@ -22205,23 +22392,17 @@ Object.freeze({
|
|
|
22205
22392
|
addonId: null,
|
|
22206
22393
|
access: "view"
|
|
22207
22394
|
},
|
|
22208
|
-
"snapshot.
|
|
22395
|
+
"snapshot.getSnapshotOverview": {
|
|
22209
22396
|
capName: "snapshot",
|
|
22210
22397
|
capScope: "device",
|
|
22211
22398
|
addonId: null,
|
|
22212
|
-
access: "create"
|
|
22213
|
-
},
|
|
22214
|
-
"snapshotProvider.getSnapshot": {
|
|
22215
|
-
capName: "snapshot-provider",
|
|
22216
|
-
capScope: "system",
|
|
22217
|
-
addonId: null,
|
|
22218
22399
|
access: "view"
|
|
22219
22400
|
},
|
|
22220
|
-
"
|
|
22221
|
-
capName: "snapshot
|
|
22222
|
-
capScope: "
|
|
22401
|
+
"snapshot.invalidateCache": {
|
|
22402
|
+
capName: "snapshot",
|
|
22403
|
+
capScope: "device",
|
|
22223
22404
|
addonId: null,
|
|
22224
|
-
access: "
|
|
22405
|
+
access: "create"
|
|
22225
22406
|
},
|
|
22226
22407
|
"ssoBridge.signBridgeToken": {
|
|
22227
22408
|
capName: "sso-bridge",
|
|
@@ -22649,30 +22830,6 @@ Object.freeze({
|
|
|
22649
22830
|
addonId: null,
|
|
22650
22831
|
access: "view"
|
|
22651
22832
|
},
|
|
22652
|
-
"streamingEngine.getStreamUrl": {
|
|
22653
|
-
capName: "streaming-engine",
|
|
22654
|
-
capScope: "system",
|
|
22655
|
-
addonId: null,
|
|
22656
|
-
access: "view"
|
|
22657
|
-
},
|
|
22658
|
-
"streamingEngine.listStreams": {
|
|
22659
|
-
capName: "streaming-engine",
|
|
22660
|
-
capScope: "system",
|
|
22661
|
-
addonId: null,
|
|
22662
|
-
access: "view"
|
|
22663
|
-
},
|
|
22664
|
-
"streamingEngine.registerStream": {
|
|
22665
|
-
capName: "streaming-engine",
|
|
22666
|
-
capScope: "system",
|
|
22667
|
-
addonId: null,
|
|
22668
|
-
access: "create"
|
|
22669
|
-
},
|
|
22670
|
-
"streamingEngine.unregisterStream": {
|
|
22671
|
-
capName: "streaming-engine",
|
|
22672
|
-
capScope: "system",
|
|
22673
|
-
addonId: null,
|
|
22674
|
-
access: "delete"
|
|
22675
|
-
},
|
|
22676
22833
|
"streamParams.getConfigSchema": {
|
|
22677
22834
|
capName: "stream-params",
|
|
22678
22835
|
capScope: "device",
|
|
@@ -22919,6 +23076,12 @@ Object.freeze({
|
|
|
22919
23076
|
addonId: null,
|
|
22920
23077
|
access: "view"
|
|
22921
23078
|
},
|
|
23079
|
+
"userPasskeys.beginDiscoverableAuthentication": {
|
|
23080
|
+
capName: "user-passkeys",
|
|
23081
|
+
capScope: "system",
|
|
23082
|
+
addonId: null,
|
|
23083
|
+
access: "view"
|
|
23084
|
+
},
|
|
22922
23085
|
"userPasskeys.beginRegistration": {
|
|
22923
23086
|
capName: "user-passkeys",
|
|
22924
23087
|
capScope: "system",
|
|
@@ -22931,12 +23094,24 @@ Object.freeze({
|
|
|
22931
23094
|
addonId: null,
|
|
22932
23095
|
access: "view"
|
|
22933
23096
|
},
|
|
23097
|
+
"userPasskeys.finishDiscoverableAuthentication": {
|
|
23098
|
+
capName: "user-passkeys",
|
|
23099
|
+
capScope: "system",
|
|
23100
|
+
addonId: null,
|
|
23101
|
+
access: "view"
|
|
23102
|
+
},
|
|
22934
23103
|
"userPasskeys.finishRegistration": {
|
|
22935
23104
|
capName: "user-passkeys",
|
|
22936
23105
|
capScope: "system",
|
|
22937
23106
|
addonId: null,
|
|
22938
23107
|
access: "create"
|
|
22939
23108
|
},
|
|
23109
|
+
"userPasskeys.getSecondFactorPreference": {
|
|
23110
|
+
capName: "user-passkeys",
|
|
23111
|
+
capScope: "system",
|
|
23112
|
+
addonId: null,
|
|
23113
|
+
access: "view"
|
|
23114
|
+
},
|
|
22940
23115
|
"userPasskeys.listPasskeys": {
|
|
22941
23116
|
capName: "user-passkeys",
|
|
22942
23117
|
capScope: "system",
|
|
@@ -22949,6 +23124,12 @@ Object.freeze({
|
|
|
22949
23124
|
addonId: null,
|
|
22950
23125
|
access: "delete"
|
|
22951
23126
|
},
|
|
23127
|
+
"userPasskeys.setSecondFactorPreference": {
|
|
23128
|
+
capName: "user-passkeys",
|
|
23129
|
+
capScope: "system",
|
|
23130
|
+
addonId: null,
|
|
23131
|
+
access: "create"
|
|
23132
|
+
},
|
|
22952
23133
|
"vacuumControl.locate": {
|
|
22953
23134
|
capName: "vacuum-control",
|
|
22954
23135
|
capScope: "device",
|
|
@@ -23021,6 +23202,18 @@ Object.freeze({
|
|
|
23021
23202
|
addonId: null,
|
|
23022
23203
|
access: "view"
|
|
23023
23204
|
},
|
|
23205
|
+
"viewerUi.getStaticDir": {
|
|
23206
|
+
capName: "viewer-ui",
|
|
23207
|
+
capScope: "system",
|
|
23208
|
+
addonId: null,
|
|
23209
|
+
access: "view"
|
|
23210
|
+
},
|
|
23211
|
+
"viewerUi.getVersion": {
|
|
23212
|
+
capName: "viewer-ui",
|
|
23213
|
+
capScope: "system",
|
|
23214
|
+
addonId: null,
|
|
23215
|
+
access: "view"
|
|
23216
|
+
},
|
|
23024
23217
|
"waterHeater.setAway": {
|
|
23025
23218
|
capName: "water-heater",
|
|
23026
23219
|
capScope: "device",
|
|
@@ -23039,54 +23232,6 @@ Object.freeze({
|
|
|
23039
23232
|
addonId: null,
|
|
23040
23233
|
access: "create"
|
|
23041
23234
|
},
|
|
23042
|
-
"webrtc.closeSession": {
|
|
23043
|
-
capName: "webrtc",
|
|
23044
|
-
capScope: "system",
|
|
23045
|
-
addonId: null,
|
|
23046
|
-
access: "create"
|
|
23047
|
-
},
|
|
23048
|
-
"webrtc.createSession": {
|
|
23049
|
-
capName: "webrtc",
|
|
23050
|
-
capScope: "system",
|
|
23051
|
-
addonId: null,
|
|
23052
|
-
access: "create"
|
|
23053
|
-
},
|
|
23054
|
-
"webrtc.handleAnswer": {
|
|
23055
|
-
capName: "webrtc",
|
|
23056
|
-
capScope: "system",
|
|
23057
|
-
addonId: null,
|
|
23058
|
-
access: "create"
|
|
23059
|
-
},
|
|
23060
|
-
"webrtc.handleOffer": {
|
|
23061
|
-
capName: "webrtc",
|
|
23062
|
-
capScope: "system",
|
|
23063
|
-
addonId: null,
|
|
23064
|
-
access: "create"
|
|
23065
|
-
},
|
|
23066
|
-
"webrtc.hasAdaptiveBitrate": {
|
|
23067
|
-
capName: "webrtc",
|
|
23068
|
-
capScope: "system",
|
|
23069
|
-
addonId: null,
|
|
23070
|
-
access: "view"
|
|
23071
|
-
},
|
|
23072
|
-
"webrtc.registerStream": {
|
|
23073
|
-
capName: "webrtc",
|
|
23074
|
-
capScope: "system",
|
|
23075
|
-
addonId: null,
|
|
23076
|
-
access: "create"
|
|
23077
|
-
},
|
|
23078
|
-
"webrtc.supportsStream": {
|
|
23079
|
-
capName: "webrtc",
|
|
23080
|
-
capScope: "system",
|
|
23081
|
-
addonId: null,
|
|
23082
|
-
access: "view"
|
|
23083
|
-
},
|
|
23084
|
-
"webrtc.unregisterStream": {
|
|
23085
|
-
capName: "webrtc",
|
|
23086
|
-
capScope: "system",
|
|
23087
|
-
addonId: null,
|
|
23088
|
-
access: "delete"
|
|
23089
|
-
},
|
|
23090
23235
|
"webrtcSession.addIceCandidate": {
|
|
23091
23236
|
capName: "webrtc-session",
|
|
23092
23237
|
capScope: "device",
|
|
@@ -23935,7 +24080,7 @@ var NodeAvDecoderSession = class NodeAvDecoderSession {
|
|
|
23935
24080
|
if (typeof this.config.deviceId === "number") seedParts.push(String(this.config.deviceId));
|
|
23936
24081
|
if (typeof this.config.tag === "string" && this.config.tag.length > 0) seedParts.push(this.config.tag);
|
|
23937
24082
|
const seed = seedParts.length > 0 ? seedParts.join(":") : "anon";
|
|
23938
|
-
this.frameRingSink = new DecoderFrameRingSink({
|
|
24083
|
+
this.frameRingSink = new _camstack_shm_ring.DecoderFrameRingSink({
|
|
23939
24084
|
seed,
|
|
23940
24085
|
logger: this.logger,
|
|
23941
24086
|
nodeId: this.nodeId
|
|
@@ -25789,7 +25934,7 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
25789
25934
|
return registrations;
|
|
25790
25935
|
}
|
|
25791
25936
|
this.ctx.logger.info("node-av decoder addon initialized", { meta: { selectedBackend: backend } });
|
|
25792
|
-
const purged = purgeOrphanSegments(SEGMENT_NAME_PREFIX);
|
|
25937
|
+
const purged = purgeOrphanSegments(_camstack_shm_ring.SEGMENT_NAME_PREFIX);
|
|
25793
25938
|
if (purged.removed > 0) this.ctx.logger.warn("node-av decoder: reclaimed orphaned shm segments at startup", { meta: {
|
|
25794
25939
|
removed: purged.removed,
|
|
25795
25940
|
scanned: purged.scanned
|
|
@@ -26050,7 +26195,7 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
26050
26195
|
return {
|
|
26051
26196
|
sessionId: input.sessionId,
|
|
26052
26197
|
...stats,
|
|
26053
|
-
budgetMb: RING_BUDGET_MB,
|
|
26198
|
+
budgetMb: _camstack_shm_ring.RING_BUDGET_MB,
|
|
26054
26199
|
getFrameHits: this.getFrameHits,
|
|
26055
26200
|
getFrameMisses: this.getFrameMisses
|
|
26056
26201
|
};
|
|
@@ -26076,7 +26221,12 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
26076
26221
|
}
|
|
26077
26222
|
};
|
|
26078
26223
|
//#endregion
|
|
26079
|
-
exports
|
|
26224
|
+
Object.defineProperty(exports, "DecoderFrameRingSink", {
|
|
26225
|
+
enumerable: true,
|
|
26226
|
+
get: function() {
|
|
26227
|
+
return _camstack_shm_ring.DecoderFrameRingSink;
|
|
26228
|
+
}
|
|
26229
|
+
});
|
|
26080
26230
|
exports.DecoderNodeAvAddon = DecoderNodeAvAddon;
|
|
26081
26231
|
exports.NodeAvAudioCodecProvider = NodeAvAudioCodecProvider;
|
|
26082
26232
|
exports.NodeAvAudioDecodeSession = NodeAvAudioDecodeSession;
|
|
@@ -26084,5 +26234,10 @@ exports.NodeAvAudioEncodeSession = NodeAvAudioEncodeSession;
|
|
|
26084
26234
|
exports.NodeAvDecoderSession = NodeAvDecoderSession;
|
|
26085
26235
|
exports.default = DecoderNodeAvAddon;
|
|
26086
26236
|
exports.loadNodeAvRuntime = loadNodeAvRuntime;
|
|
26087
|
-
exports
|
|
26237
|
+
Object.defineProperty(exports, "makeSegmentName", {
|
|
26238
|
+
enumerable: true,
|
|
26239
|
+
get: function() {
|
|
26240
|
+
return _camstack_shm_ring.makeSegmentName;
|
|
26241
|
+
}
|
|
26242
|
+
});
|
|
26088
26243
|
exports.peekNodeAvRuntime = peekNodeAvRuntime;
|