@camstack/addon-decoder-nodeav 1.1.8 → 1.1.9
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 +502 -527
- package/dist/index.mjs +488 -523
- 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-DJaTV2D7.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,9 @@ function method(input, output, options) {
|
|
|
7000
6738
|
timeoutMs: options?.timeoutMs
|
|
7001
6739
|
};
|
|
7002
6740
|
}
|
|
6741
|
+
var StaticDirOutputSchema$1 = object({ staticDir: string() });
|
|
6742
|
+
var VersionOutputSchema$1 = object({ version: string() });
|
|
6743
|
+
method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
|
|
7003
6744
|
var StaticDirOutputSchema = object({ staticDir: string() });
|
|
7004
6745
|
var VersionOutputSchema = object({ version: string() });
|
|
7005
6746
|
method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
|
|
@@ -7181,6 +6922,36 @@ var ModelFormatsSchema = object({
|
|
|
7181
6922
|
tflite: ModelFormatEntrySchema.optional(),
|
|
7182
6923
|
pt: ModelFormatEntrySchema.optional()
|
|
7183
6924
|
});
|
|
6925
|
+
/**
|
|
6926
|
+
* Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
|
|
6927
|
+
* the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
|
|
6928
|
+
* grouped Family→Tier→Variant picker renders identically in the config UI and
|
|
6929
|
+
* in the pipeline/device steppers. The flat `id` stays the source of truth for
|
|
6930
|
+
* resolution/download/persistence; this is a presentation overlay resolved back
|
|
6931
|
+
* to an `id`.
|
|
6932
|
+
*/
|
|
6933
|
+
var ModelVariantGroupSchema = object({
|
|
6934
|
+
/** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
|
|
6935
|
+
family: string(),
|
|
6936
|
+
/** Size within the family, e.g. `n` | `s` | `m` | `l`. */
|
|
6937
|
+
tier: string(),
|
|
6938
|
+
/** Quantization axis. Omit ⇒ the fp32 base build. */
|
|
6939
|
+
precision: _enum(["fp32", "int8"]).optional(),
|
|
6940
|
+
/**
|
|
6941
|
+
* Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
|
|
6942
|
+
* latency-optimized export (e.g. ReLU-activation variant) — the slot the
|
|
6943
|
+
* future performance variants plug into.
|
|
6944
|
+
*/
|
|
6945
|
+
optimization: _enum(["standard", "fast"]).optional(),
|
|
6946
|
+
/**
|
|
6947
|
+
* Input-resolution axis (square input side, px). Omit ⇒ the family's native
|
|
6948
|
+
* resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
|
|
6949
|
+
* cheap latency lever — especially on Apple ANE and the Intel N100 — at a
|
|
6950
|
+
* small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
|
|
6951
|
+
* the group so the selector can offer it as a variant axis.
|
|
6952
|
+
*/
|
|
6953
|
+
resolution: number().int().positive().optional()
|
|
6954
|
+
});
|
|
7184
6955
|
var ModelCatalogEntrySchema = object({
|
|
7185
6956
|
id: string(),
|
|
7186
6957
|
name: string(),
|
|
@@ -7210,7 +6981,43 @@ var ModelCatalogEntrySchema = object({
|
|
|
7210
6981
|
* Auxiliary files required at runtime (labels JSON, charset dict, etc.).
|
|
7211
6982
|
* Downloaded into the same modelsDir alongside the model file.
|
|
7212
6983
|
*/
|
|
7213
|
-
extraFiles: array(ModelExtraFileSchema).readonly().optional()
|
|
6984
|
+
extraFiles: array(ModelExtraFileSchema).readonly().optional(),
|
|
6985
|
+
/**
|
|
6986
|
+
* LEGACY entry — retained in the catalog so a persisted operator selection
|
|
6987
|
+
* still RESOLVES (and can be re-activated), but hidden from the selectable
|
|
6988
|
+
* model list and excluded from the auto format-default pick. Set on the
|
|
6989
|
+
* superseded / consolidated models (older lineages, redundant fp16 IRs) so
|
|
6990
|
+
* the active lineup stays the coherent curated ladder without deleting a
|
|
6991
|
+
* model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
|
|
6992
|
+
* an explicit legacy id that has a build for the node's format.
|
|
6993
|
+
*/
|
|
6994
|
+
legacy: boolean().optional(),
|
|
6995
|
+
/**
|
|
6996
|
+
* Measured quality/latency metadata — populated from the benchmark addon on
|
|
6997
|
+
* the real node classes. Absent = not yet measured (most entries today; the
|
|
6998
|
+
* catalog historically carried only `sizeMB`, a poor cross-architecture
|
|
6999
|
+
* speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
|
|
7000
|
+
*/
|
|
7001
|
+
metrics: object({
|
|
7002
|
+
map50: number().optional(),
|
|
7003
|
+
p95LatencyMs: record(string(), number()).optional()
|
|
7004
|
+
}).optional(),
|
|
7005
|
+
/**
|
|
7006
|
+
* SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
|
|
7007
|
+
* YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
|
|
7008
|
+
* the retraining addon and any future commercial distribution.
|
|
7009
|
+
*/
|
|
7010
|
+
license: string().optional(),
|
|
7011
|
+
/**
|
|
7012
|
+
* Variant-selector grouping. The UI groups models by `family` + `tier` and
|
|
7013
|
+
* offers `precision` / `optimization` as variant axes WITHIN a tier — so all
|
|
7014
|
+
* of a family's sizes and quantizations collapse into one grouped picker
|
|
7015
|
+
* instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
|
|
7016
|
+
* (legacy / custom models) — never shown in the grouped selector. The flat
|
|
7017
|
+
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
7018
|
+
* is a presentation overlay resolved back to an `id`.
|
|
7019
|
+
*/
|
|
7020
|
+
group: ModelVariantGroupSchema.optional()
|
|
7214
7021
|
});
|
|
7215
7022
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
7216
7023
|
format: literal("openvino"),
|
|
@@ -7271,8 +7078,8 @@ var RecordingModeSchema = _enum([
|
|
|
7271
7078
|
"onAudioThreshold"
|
|
7272
7079
|
]);
|
|
7273
7080
|
/**
|
|
7274
|
-
* First-class, authoritative per-camera storage mode — the
|
|
7275
|
-
* reads directly (never inferred from `rules`):
|
|
7081
|
+
* First-class, authoritative per-camera storage mode — the explicit choice the
|
|
7082
|
+
* UI reads directly (never inferred from `rules`):
|
|
7276
7083
|
* - `off` — not recording.
|
|
7277
7084
|
* - `events` — record only around triggers (motion / audio threshold),
|
|
7278
7085
|
* with pre/post-buffer.
|
|
@@ -8920,26 +8727,13 @@ DeviceType.Light, method(object({
|
|
|
8920
8727
|
percentage: number().min(0).max(100),
|
|
8921
8728
|
lastChangedAt: number()
|
|
8922
8729
|
});
|
|
8730
|
+
/** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
|
|
8923
8731
|
var StreamFormatSchema = _enum([
|
|
8924
8732
|
"webrtc",
|
|
8925
8733
|
"hls",
|
|
8926
8734
|
"mjpeg",
|
|
8927
8735
|
"rtsp"
|
|
8928
8736
|
]);
|
|
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
8737
|
var RtspRestreamEntrySchema = object({
|
|
8944
8738
|
brokerId: string(),
|
|
8945
8739
|
url: string(),
|
|
@@ -9604,7 +9398,7 @@ var ConsumablesStatusSchema = object({
|
|
|
9604
9398
|
})),
|
|
9605
9399
|
lastChangedAt: number()
|
|
9606
9400
|
});
|
|
9607
|
-
|
|
9401
|
+
Object.values(DeviceType), method(object({
|
|
9608
9402
|
deviceId: number().int().nonnegative(),
|
|
9609
9403
|
key: string().min(1)
|
|
9610
9404
|
}), _void(), {
|
|
@@ -10519,7 +10313,7 @@ var BoundingBoxSchema = object({
|
|
|
10519
10313
|
w: number(),
|
|
10520
10314
|
h: number()
|
|
10521
10315
|
});
|
|
10522
|
-
|
|
10316
|
+
object({
|
|
10523
10317
|
class: string(),
|
|
10524
10318
|
originalClass: string(),
|
|
10525
10319
|
score: number(),
|
|
@@ -10654,7 +10448,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
|
|
|
10654
10448
|
enabled: boolean(),
|
|
10655
10449
|
modelId: string(),
|
|
10656
10450
|
children: array(PipelineDefaultStepSchema).readonly(),
|
|
10657
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
10658
10451
|
group: string().optional(),
|
|
10659
10452
|
settings: record(string(), unknown()).optional()
|
|
10660
10453
|
}));
|
|
@@ -10679,7 +10472,9 @@ var PipelineModelOptionSchema = object({
|
|
|
10679
10472
|
formats: record(string(), object({
|
|
10680
10473
|
downloaded: boolean(),
|
|
10681
10474
|
sizeMB: number()
|
|
10682
|
-
}))
|
|
10475
|
+
})),
|
|
10476
|
+
group: ModelVariantGroupSchema.optional(),
|
|
10477
|
+
legacy: boolean().optional()
|
|
10683
10478
|
});
|
|
10684
10479
|
var ConfigFieldBridge = custom();
|
|
10685
10480
|
var PipelineAddonSchemaSchema = object({
|
|
@@ -10709,11 +10504,6 @@ var PipelineSchemaSchema = object({
|
|
|
10709
10504
|
selectedEngine: PipelineEngineChoiceSchema,
|
|
10710
10505
|
slots: array(PipelineSlotSchemaSchema).readonly()
|
|
10711
10506
|
});
|
|
10712
|
-
var DetectorOutputSchema = object({
|
|
10713
|
-
detections: array(SpatialDetectionSchema).readonly(),
|
|
10714
|
-
inferenceMs: number(),
|
|
10715
|
-
modelId: string()
|
|
10716
|
-
});
|
|
10717
10507
|
var EngineProvisioningSchema = object({
|
|
10718
10508
|
runtimeId: _enum([
|
|
10719
10509
|
"onnx",
|
|
@@ -10730,15 +10520,42 @@ var EngineProvisioningSchema = object({
|
|
|
10730
10520
|
]),
|
|
10731
10521
|
progress: number().optional(),
|
|
10732
10522
|
error: string().optional(),
|
|
10733
|
-
nextRetryAt: number().optional()
|
|
10523
|
+
nextRetryAt: number().optional(),
|
|
10524
|
+
/**
|
|
10525
|
+
* Gate A (config-correctness gate at engine change): human-readable
|
|
10526
|
+
* config issues surfaced EAGERLY when the node's engine changes — model
|
|
10527
|
+
* substitutions ("chose X, running Y") and zero-build steps ("no model
|
|
10528
|
+
* has a <format> build"). Additive/optional: informational only, never
|
|
10529
|
+
* enforced here — `assertEngineReady` (readiness) still gates inference.
|
|
10530
|
+
* Absent/empty when the node-default tree resolves cleanly.
|
|
10531
|
+
*/
|
|
10532
|
+
configIssues: array(string()).optional()
|
|
10734
10533
|
});
|
|
10735
10534
|
var PipelineStepInputSchema = lazy(() => object({
|
|
10736
10535
|
addonId: string(),
|
|
10737
|
-
modelId: string(),
|
|
10536
|
+
modelId: string().optional(),
|
|
10738
10537
|
enabled: boolean().default(true),
|
|
10739
10538
|
children: array(PipelineStepInputSchema).optional(),
|
|
10740
10539
|
settings: record(string(), unknown()).optional()
|
|
10741
10540
|
}));
|
|
10541
|
+
var ModelSubstitutionSchema = object({
|
|
10542
|
+
addonId: string(),
|
|
10543
|
+
chosen: string(),
|
|
10544
|
+
running: string(),
|
|
10545
|
+
format: string()
|
|
10546
|
+
});
|
|
10547
|
+
var PipelineValidationIssueSchema = object({
|
|
10548
|
+
addonId: string(),
|
|
10549
|
+
kind: _enum(["unknown-addon", "no-format-build"]),
|
|
10550
|
+
detail: string()
|
|
10551
|
+
});
|
|
10552
|
+
var PipelineValidationResultSchema = object({
|
|
10553
|
+
ok: boolean(),
|
|
10554
|
+
issues: array(PipelineValidationIssueSchema).readonly(),
|
|
10555
|
+
substitutions: array(ModelSubstitutionSchema).readonly(),
|
|
10556
|
+
/** The node's `currentEngine.format` this validation ran against. */
|
|
10557
|
+
format: string()
|
|
10558
|
+
});
|
|
10742
10559
|
var ReferenceImageEntrySchema = object({
|
|
10743
10560
|
filename: string(),
|
|
10744
10561
|
stepIds: array(string()).readonly().optional()
|
|
@@ -10809,7 +10626,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
10809
10626
|
})) }), object({ success: literal(true) }), {
|
|
10810
10627
|
kind: "mutation",
|
|
10811
10628
|
auth: "admin"
|
|
10812
|
-
}), method(
|
|
10629
|
+
}), method(object({ nodeId: string() }), object({
|
|
10630
|
+
success: literal(true),
|
|
10631
|
+
clearedDevices: number()
|
|
10632
|
+
}), {
|
|
10633
|
+
kind: "mutation",
|
|
10634
|
+
auth: "admin"
|
|
10635
|
+
}), 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
10636
|
name: string(),
|
|
10814
10637
|
steps: array(PipelineTemplateStepSchema).readonly(),
|
|
10815
10638
|
engine: PipelineEngineChoiceSchema
|
|
@@ -10826,10 +10649,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
10826
10649
|
modelId: string(),
|
|
10827
10650
|
format: ModelFormatSchema$1
|
|
10828
10651
|
}), 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
10652
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
10834
10653
|
steps: array(PipelineStepInputSchema).min(1),
|
|
10835
10654
|
frame: FrameInputSchema.optional(),
|
|
@@ -11069,6 +10888,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
11069
10888
|
kind: literal("remote-restream"),
|
|
11070
10889
|
/** The camera's source-owner node (slice 1: always the hub). */
|
|
11071
10890
|
ownerNodeId: string(),
|
|
10891
|
+
/**
|
|
10892
|
+
* The owner's LAN-reachable host, resolved by the orchestrator from the
|
|
10893
|
+
* per-node `reachableHost` override (Cluster UI). When present the runner
|
|
10894
|
+
* dials THIS host for the owner's restream, in preference to the
|
|
10895
|
+
* `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
|
|
10896
|
+
*/
|
|
10897
|
+
ownerReachableHost: string().optional(),
|
|
11072
10898
|
/** Operator override for the owner host the runner dials. */
|
|
11073
10899
|
hubHostnameOverride: string().optional()
|
|
11074
10900
|
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
@@ -11077,13 +10903,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
|
|
|
11077
10903
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
11078
10904
|
* runner needs to subscribe to the local broker and execute inference.
|
|
11079
10905
|
*
|
|
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.
|
|
10906
|
+
* Stateless-pipeline model: the pipeline content (`steps`, optional
|
|
10907
|
+
* `audio`) travels with the attach payload. The runner keeps it in RAM
|
|
10908
|
+
* for the lifetime of the attach — on rebalance, edit, or restart the
|
|
10909
|
+
* orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
|
|
10910
|
+
* node-local, resolved by the executing runner at dispatch time.
|
|
11087
10911
|
*/
|
|
11088
10912
|
var RunnerCameraConfigSchema = object({
|
|
11089
10913
|
deviceId: number(),
|
|
@@ -11134,14 +10958,11 @@ var RunnerCameraConfigSchema = object({
|
|
|
11134
10958
|
*/
|
|
11135
10959
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
11136
10960
|
pipelineEnabled: boolean().default(true),
|
|
11137
|
-
/** Engine choice for video steps (runtime+backend+format). */
|
|
11138
|
-
engine: PipelineEngineChoiceSchema.optional(),
|
|
11139
10961
|
/** Ordered tree of video steps. Absent → runner skips video detection. */
|
|
11140
10962
|
steps: array(PipelineStepInputSchema).readonly().optional(),
|
|
11141
10963
|
/** Audio classification branch. `enabled:false` disables, null skips. */
|
|
11142
10964
|
audio: object({
|
|
11143
|
-
|
|
11144
|
-
modelId: string(),
|
|
10965
|
+
modelId: string().optional(),
|
|
11145
10966
|
enabled: boolean()
|
|
11146
10967
|
}).nullable().optional(),
|
|
11147
10968
|
/**
|
|
@@ -12522,7 +12343,9 @@ var AddonPageDeclarationSchema$1 = object({
|
|
|
12522
12343
|
icon: string(),
|
|
12523
12344
|
path: string(),
|
|
12524
12345
|
remoteName: string(),
|
|
12525
|
-
bundle: string()
|
|
12346
|
+
bundle: string(),
|
|
12347
|
+
section: string().optional(),
|
|
12348
|
+
sectionLabel: string().optional()
|
|
12526
12349
|
});
|
|
12527
12350
|
var AddonPageInfoSchema = object({
|
|
12528
12351
|
addonId: string(),
|
|
@@ -12562,7 +12385,18 @@ var AddonPageDeclarationSchema = object({
|
|
|
12562
12385
|
* the static-file route can compute an mtime-based cache-buster URL
|
|
12563
12386
|
* without a separate filesystem stat.
|
|
12564
12387
|
*/
|
|
12565
|
-
bundle: string()
|
|
12388
|
+
bundle: string(),
|
|
12389
|
+
/**
|
|
12390
|
+
* Sidebar section this page docks into. Well-known ids: `'detection'`,
|
|
12391
|
+
* `'cluster'`, `'administration'` — the page renders inside that group.
|
|
12392
|
+
* Any OTHER string creates (or joins) a custom section rendered after
|
|
12393
|
+
* the built-in groups; its label comes from `sectionLabel` (first
|
|
12394
|
+
* declaration wins), falling back to the id. Absent → the legacy
|
|
12395
|
+
* "Addon Pages" group.
|
|
12396
|
+
*/
|
|
12397
|
+
section: string().optional(),
|
|
12398
|
+
/** Display label for a CUSTOM `section` id (ignored for well-known ids). */
|
|
12399
|
+
sectionLabel: string().optional()
|
|
12566
12400
|
});
|
|
12567
12401
|
method(_void(), array(AddonPageDeclarationSchema).readonly());
|
|
12568
12402
|
var AddonHttpRouteSchema = object({
|
|
@@ -12778,6 +12612,17 @@ var WidgetMetadataSchema = object({
|
|
|
12778
12612
|
deviceContext: boolean().default(false),
|
|
12779
12613
|
integrationContext: boolean().default(false)
|
|
12780
12614
|
}),
|
|
12615
|
+
/**
|
|
12616
|
+
* Loadable BEFORE authentication. The normal widget registry listing
|
|
12617
|
+
* (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
|
|
12618
|
+
* (the login page) cannot discover a widget through it. A widget that
|
|
12619
|
+
* declares `preAuth: true` marks itself as safe to mount on a pre-auth
|
|
12620
|
+
* screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
|
|
12621
|
+
* login-method contribution channel (see `login-method.cap.ts`) rather
|
|
12622
|
+
* than the authenticated registry, and its bundle is served by the
|
|
12623
|
+
* public `/api/addon-widgets/:addonId/*` static route. Defaults false.
|
|
12624
|
+
*/
|
|
12625
|
+
preAuth: boolean().optional().default(false),
|
|
12781
12626
|
/** Dashboard placement HINTS (operator can override per instance). */
|
|
12782
12627
|
defaultSize: WidgetSizeEnum.default("md"),
|
|
12783
12628
|
allowedSizes: array(WidgetSizeEnum).readonly().default([
|
|
@@ -13116,6 +12961,66 @@ method(object({
|
|
|
13116
12961
|
password: string()
|
|
13117
12962
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
13118
12963
|
/**
|
|
12964
|
+
* `login-method` — collection cap through which auth addons contribute
|
|
12965
|
+
* their pre-auth login surfaces to the login page. This is the SINGLE,
|
|
12966
|
+
* generic mechanism that supersedes the dead `auth.listProviders` reader:
|
|
12967
|
+
* every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
|
|
12968
|
+
* `login-method` provider and the PUBLIC `auth.listLoginMethods`
|
|
12969
|
+
* procedure aggregates them for the unauthenticated login page.
|
|
12970
|
+
*
|
|
12971
|
+
* A contribution is a discriminated union on `kind`:
|
|
12972
|
+
*
|
|
12973
|
+
* - `redirect` — a declarative button. The login page renders a generic
|
|
12974
|
+
* button that navigates to `startUrl` (an addon-owned HTTP route).
|
|
12975
|
+
* Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
|
|
12976
|
+
* ZERO shell-side JS. A future SSO addon plugs in the same way — the
|
|
12977
|
+
* login page needs NO change.
|
|
12978
|
+
*
|
|
12979
|
+
* - `widget` — a Module-Federation widget the login page mounts (via
|
|
12980
|
+
* `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
|
|
12981
|
+
* login ceremony, which must run `@simplewebauthn/browser` INSIDE the
|
|
12982
|
+
* addon bundle. The referenced widget also declares `preAuth: true` in
|
|
12983
|
+
* its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
|
|
12984
|
+
* stamps a public `bundleUrl` from `addonId` + `bundle`.
|
|
12985
|
+
*
|
|
12986
|
+
* Every contribution carries a `stage`:
|
|
12987
|
+
* - `primary` — shown on the first credentials screen (OIDC /
|
|
12988
|
+
* magic-link buttons; a future usernameless passkey).
|
|
12989
|
+
* - `second-factor` — shown AFTER the password leg, gated on the
|
|
12990
|
+
* returned `factors` (passkey-as-2FA today).
|
|
12991
|
+
*
|
|
12992
|
+
* `mount: skip` — the cap is read server-side by the core auth router
|
|
12993
|
+
* (`registry.getCollection('login-method')`), never mounted as its own
|
|
12994
|
+
* tRPC router.
|
|
12995
|
+
*/
|
|
12996
|
+
/** When a login method renders in the two-phase login flow. */
|
|
12997
|
+
var LoginStageEnum = _enum(["primary", "second-factor"]);
|
|
12998
|
+
/** One login-method contribution — redirect button OR pre-auth widget. */
|
|
12999
|
+
var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
|
|
13000
|
+
kind: literal("redirect"),
|
|
13001
|
+
/** Stable id within the login-method set (e.g. `auth-oidc/google`). */
|
|
13002
|
+
id: string(),
|
|
13003
|
+
/** Operator-facing button label. */
|
|
13004
|
+
label: string(),
|
|
13005
|
+
/** lucide-react icon name. */
|
|
13006
|
+
icon: string().optional(),
|
|
13007
|
+
/** Addon-owned HTTP route the button navigates to (GET). */
|
|
13008
|
+
startUrl: string(),
|
|
13009
|
+
stage: LoginStageEnum
|
|
13010
|
+
}), object({
|
|
13011
|
+
kind: literal("widget"),
|
|
13012
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
|
|
13013
|
+
id: string(),
|
|
13014
|
+
/** Owning addon id — drives the public bundle URL + the MF namespace. */
|
|
13015
|
+
addonId: string(),
|
|
13016
|
+
/** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
|
|
13017
|
+
bundle: string(),
|
|
13018
|
+
/** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
|
|
13019
|
+
remote: WidgetRemoteSchema,
|
|
13020
|
+
stage: LoginStageEnum
|
|
13021
|
+
})]);
|
|
13022
|
+
method(_void(), array(LoginMethodContributionSchema).readonly());
|
|
13023
|
+
/**
|
|
13119
13024
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
13120
13025
|
* `id = <addonId>:<subId>` from its provider lookup so consumers
|
|
13121
13026
|
* (admin UI, restore flow) see one canonical key.
|
|
@@ -15497,11 +15402,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15497
15402
|
timestamp: number()
|
|
15498
15403
|
});
|
|
15499
15404
|
var CameraPipelineConfigSchema = object({
|
|
15500
|
-
engine: PipelineEngineChoiceSchema,
|
|
15405
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
15501
15406
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
15502
15407
|
audio: object({
|
|
15503
|
-
engine: PipelineEngineChoiceSchema,
|
|
15504
|
-
modelId: string(),
|
|
15408
|
+
engine: PipelineEngineChoiceSchema.optional(),
|
|
15409
|
+
modelId: string().optional(),
|
|
15505
15410
|
enabled: boolean(),
|
|
15506
15411
|
settings: record(string(), unknown()).readonly().optional()
|
|
15507
15412
|
}).nullable().optional()
|
|
@@ -15516,7 +15421,7 @@ var PipelineTemplateSchema = object({
|
|
|
15516
15421
|
});
|
|
15517
15422
|
var AgentAddonConfigSchema = object({
|
|
15518
15423
|
enabled: boolean(),
|
|
15519
|
-
modelId: string(),
|
|
15424
|
+
modelId: string().optional(),
|
|
15520
15425
|
settings: record(string(), unknown()).readonly()
|
|
15521
15426
|
});
|
|
15522
15427
|
var AgentPipelineSettingsSchema = object({
|
|
@@ -15526,12 +15431,25 @@ var AgentPipelineSettingsSchema = object({
|
|
|
15526
15431
|
detectWeight: number().positive().optional(),
|
|
15527
15432
|
/** Node is eligible to run the detection pipeline (decode + inference). */
|
|
15528
15433
|
detect: boolean().optional(),
|
|
15529
|
-
/**
|
|
15434
|
+
/**
|
|
15435
|
+
* DEPRECATED AND IGNORED. Decode is always co-located with its frame
|
|
15436
|
+
* consumer, so decode eligibility IS detect eligibility. Kept optional in
|
|
15437
|
+
* the schema ONLY so persisted stores written before the removal still
|
|
15438
|
+
* parse — no code reads it and no write path emits it.
|
|
15439
|
+
*/
|
|
15530
15440
|
decode: boolean().optional(),
|
|
15531
15441
|
/** Node is eligible to run audio-analyzer sessions. */
|
|
15532
15442
|
audio: boolean().optional(),
|
|
15533
15443
|
/** Node is eligible to be the ingest / source-owner (serve the restream). */
|
|
15534
|
-
ingest: boolean().optional()
|
|
15444
|
+
ingest: boolean().optional(),
|
|
15445
|
+
/**
|
|
15446
|
+
* Operator override for the LAN host a cross-node decoder dials to reach
|
|
15447
|
+
* THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
|
|
15448
|
+
* falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
|
|
15449
|
+
* it already uses to reach the hub). Set this only when the auto-detected
|
|
15450
|
+
* address is wrong (multi-homed host, NAT, custom interface).
|
|
15451
|
+
*/
|
|
15452
|
+
reachableHost: string().optional()
|
|
15535
15453
|
});
|
|
15536
15454
|
var CameraPipelineForAgentSchema = object({
|
|
15537
15455
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -15579,25 +15497,6 @@ var PipelineAssignmentSchema = object({
|
|
|
15579
15497
|
assignedAt: number()
|
|
15580
15498
|
});
|
|
15581
15499
|
/**
|
|
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
15500
|
* Per-agent load summary surfaced to the load balancer + dashboards.
|
|
15602
15501
|
* Aggregated from each runner's `getLocalLoad` cap call.
|
|
15603
15502
|
*/
|
|
@@ -15637,6 +15536,15 @@ var GlobalMetricsSchema = object({
|
|
|
15637
15536
|
* capability providers.
|
|
15638
15537
|
*/
|
|
15639
15538
|
var CapabilityBindingsSchema = record(string(), string());
|
|
15539
|
+
/**
|
|
15540
|
+
* The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
|
|
15541
|
+
* its LAN-reachable host, if one is registered. See `getIngestOwner`.
|
|
15542
|
+
*/
|
|
15543
|
+
var IngestOwnerSchema = object({
|
|
15544
|
+
ownerNodeId: string(),
|
|
15545
|
+
reachableHost: string().optional(),
|
|
15546
|
+
configIssue: string().optional()
|
|
15547
|
+
});
|
|
15640
15548
|
/** Source block — always present; derives from the stream catalog. */
|
|
15641
15549
|
var CameraSourceStatusSchema = object({ streams: array(object({
|
|
15642
15550
|
camStreamId: string(),
|
|
@@ -15651,6 +15559,14 @@ var CameraAssignmentStatusSchema = object({
|
|
|
15651
15559
|
detectionNodeId: string().nullable(),
|
|
15652
15560
|
decoderNodeId: string().nullable(),
|
|
15653
15561
|
audioNodeId: string().nullable(),
|
|
15562
|
+
/**
|
|
15563
|
+
* The node that OWNS this camera's physical source pull (dials the RTSP and
|
|
15564
|
+
* hosts the broker/restream) — the cluster ingest owner today
|
|
15565
|
+
* (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
|
|
15566
|
+
* the UI show WHERE a camera is sourced without SSH/logs, and is the node the
|
|
15567
|
+
* broker block below was read from (pinned). Nullable only pre-wiring.
|
|
15568
|
+
*/
|
|
15569
|
+
sourceNodeId: string().nullable(),
|
|
15654
15570
|
pinned: object({
|
|
15655
15571
|
detection: boolean(),
|
|
15656
15572
|
decoder: boolean(),
|
|
@@ -15783,16 +15699,7 @@ method(object({
|
|
|
15783
15699
|
}), object({ success: literal(true) }), {
|
|
15784
15700
|
kind: "mutation",
|
|
15785
15701
|
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({
|
|
15702
|
+
}), method(_void(), IngestOwnerSchema), method(object({
|
|
15796
15703
|
deviceId: number(),
|
|
15797
15704
|
nodeId: string()
|
|
15798
15705
|
}), object({ success: literal(true) }), {
|
|
@@ -15813,10 +15720,7 @@ method(object({
|
|
|
15813
15720
|
nodeId: string(),
|
|
15814
15721
|
pinned: boolean(),
|
|
15815
15722
|
assignedAt: number()
|
|
15816
|
-
}))), method(object({
|
|
15817
|
-
deviceId: number(),
|
|
15818
|
-
pipelineNodeId: string().optional()
|
|
15819
|
-
}), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
|
|
15723
|
+
}))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
|
|
15820
15724
|
nodeId: string(),
|
|
15821
15725
|
settings: AgentPipelineSettingsSchema
|
|
15822
15726
|
})).readonly()), method(object({
|
|
@@ -15846,12 +15750,26 @@ method(object({
|
|
|
15846
15750
|
}), method(object({
|
|
15847
15751
|
agentNodeId: string(),
|
|
15848
15752
|
detect: boolean().nullable().optional(),
|
|
15849
|
-
decode: boolean().nullable().optional(),
|
|
15850
15753
|
audio: boolean().nullable().optional(),
|
|
15851
15754
|
ingest: boolean().nullable().optional()
|
|
15852
15755
|
}), object({ success: literal(true) }), {
|
|
15853
15756
|
kind: "mutation",
|
|
15854
15757
|
auth: "admin"
|
|
15758
|
+
}), method(object({
|
|
15759
|
+
agentNodeId: string(),
|
|
15760
|
+
reachableHost: string().nullable()
|
|
15761
|
+
}), object({ success: literal(true) }), {
|
|
15762
|
+
kind: "mutation",
|
|
15763
|
+
auth: "admin"
|
|
15764
|
+
}), method(object({ agentNodeId: string() }), object({
|
|
15765
|
+
success: literal(true),
|
|
15766
|
+
/** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
|
|
15767
|
+
effectiveModelId: string().nullable(),
|
|
15768
|
+
/** Number of cameras whose node-scoped overrides were cleared. */
|
|
15769
|
+
clearedCameraOverrides: number()
|
|
15770
|
+
}), {
|
|
15771
|
+
kind: "mutation",
|
|
15772
|
+
auth: "admin"
|
|
15855
15773
|
}), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
|
|
15856
15774
|
deviceId: number(),
|
|
15857
15775
|
addonId: string(),
|
|
@@ -15896,22 +15814,131 @@ method(object({
|
|
|
15896
15814
|
kind: "mutation",
|
|
15897
15815
|
auth: "admin"
|
|
15898
15816
|
});
|
|
15899
|
-
|
|
15900
|
-
|
|
15901
|
-
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15817
|
+
/**
|
|
15818
|
+
* server-management — per-NODE singleton capability for a node's ROOT
|
|
15819
|
+
* package lifecycle (runtime-updatable node packages, phase 2: hub + docker
|
|
15820
|
+
* agents).
|
|
15821
|
+
*
|
|
15822
|
+
* Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
|
|
15823
|
+
* on agents) carries the whole software stack in its npm dep tree, so ONE
|
|
15824
|
+
* version describes the node. Updates install into
|
|
15825
|
+
* `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
|
|
15826
|
+
* starter (probation boot + auto-rollback to N-1).
|
|
15827
|
+
*
|
|
15828
|
+
* Providers:
|
|
15829
|
+
* - HUB: `ServerUpdateService` behind the `server-provided` mount
|
|
15830
|
+
* (`buildServerProviders` in trpc.router.ts) — the default target for
|
|
15831
|
+
* unpinned calls.
|
|
15832
|
+
* - AGENT: `AgentUpdateService` registered by the agent bootstrap under
|
|
15833
|
+
* the synthetic `agent-runtime` addonId and declared in the agent's
|
|
15834
|
+
* `$hub.registerNode` manifest.
|
|
15835
|
+
*
|
|
15836
|
+
* Node routing: singleton caps get the codegen/runtime-builder `nodeId`
|
|
15837
|
+
* injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
|
|
15838
|
+
* SDK) routes the call to that node's provider via the standard remote
|
|
15839
|
+
* proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
|
|
15840
|
+
* in-process provider lookup). No `nodeId` → the hub's own provider.
|
|
15841
|
+
*
|
|
15842
|
+
* Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
|
|
15843
|
+
*/
|
|
15844
|
+
/**
|
|
15845
|
+
* Where the running hub's code was loaded from:
|
|
15846
|
+
* - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
|
|
15847
|
+
* plain resolution and runtime updates are refused.
|
|
15848
|
+
* - `baked` — the immutable image seed closure (no data-dir root active).
|
|
15849
|
+
* - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
|
|
15850
|
+
*/
|
|
15851
|
+
var ServerBootModeSchema = _enum([
|
|
15852
|
+
"workspace",
|
|
15853
|
+
"baked",
|
|
15854
|
+
"data-root"
|
|
15855
|
+
]);
|
|
15856
|
+
/**
|
|
15857
|
+
* Update lifecycle state:
|
|
15858
|
+
* - `idle` / `checking` / `staging` — steady / in-flight registry work.
|
|
15859
|
+
* - `pending-restart` — a version is staged and the node has NOT yet
|
|
15860
|
+
* restarted onto it (still running the OLD version).
|
|
15861
|
+
* - `awaiting-confirmation` — the node HAS restarted onto the staged version
|
|
15862
|
+
* (it is the active probation boot) and is waiting to confirm boot-health.
|
|
15863
|
+
* Apply/rollback are refused in this state and the node must NOT be
|
|
15864
|
+
* manually restarted, or the probation boot auto-rolls-back.
|
|
15865
|
+
*/
|
|
15866
|
+
var ServerUpdateStateSchema = _enum([
|
|
15867
|
+
"idle",
|
|
15868
|
+
"checking",
|
|
15869
|
+
"staging",
|
|
15870
|
+
"pending-restart",
|
|
15871
|
+
"awaiting-confirmation"
|
|
15872
|
+
]);
|
|
15873
|
+
var ServerRollbackInfoSchema = object({
|
|
15874
|
+
/** The version that failed (or was manually rolled back). */
|
|
15875
|
+
fromVersion: string(),
|
|
15876
|
+
/** The version rolled back to; null = the baked seed. */
|
|
15877
|
+
toVersion: string().nullable(),
|
|
15878
|
+
atMs: number(),
|
|
15879
|
+
reason: string()
|
|
15905
15880
|
});
|
|
15906
|
-
var
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15881
|
+
var ServerPackageStatusSchema = object({
|
|
15882
|
+
/** Root package name (`@camstack/server` on the hub). */
|
|
15883
|
+
packageName: string(),
|
|
15884
|
+
/** Version of the code the running process ACTUALLY loaded. */
|
|
15885
|
+
runningVersion: string().nullable(),
|
|
15886
|
+
/** Node.js runtime version the node's process runs on (`process.versions.node`). */
|
|
15887
|
+
nodeRuntimeVersion: string().nullable(),
|
|
15888
|
+
/** Active data-dir root version; null when booted from seed/workspace. */
|
|
15889
|
+
activeVersion: string().nullable(),
|
|
15890
|
+
/** N-1 version kept for rollback; null when no previous version exists. */
|
|
15891
|
+
previousVersion: string().nullable(),
|
|
15892
|
+
/** Version of the immutable baked seed closure (image fallback). */
|
|
15893
|
+
seedVersion: string().nullable(),
|
|
15894
|
+
/** Latest registry version from the most recent check (null = never checked). */
|
|
15895
|
+
latestVersion: string().nullable(),
|
|
15896
|
+
updateAvailable: boolean(),
|
|
15897
|
+
bootMode: ServerBootModeSchema,
|
|
15898
|
+
updateState: ServerUpdateStateSchema,
|
|
15899
|
+
/** Version staged + awaiting its probation boot, when one is pending. */
|
|
15900
|
+
pendingVersion: string().nullable(),
|
|
15901
|
+
/** Set when the last freshly-activated version failed its boot health-check. */
|
|
15902
|
+
rolledBack: ServerRollbackInfoSchema.nullable(),
|
|
15903
|
+
/**
|
|
15904
|
+
* True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
|
|
15905
|
+
* hub is running from the baked seed (or workspace) while installed data-dir
|
|
15906
|
+
* versions are being IGNORED. Surfaced as a warning in the UI.
|
|
15907
|
+
*/
|
|
15908
|
+
stateFileCorrupt: boolean(),
|
|
15909
|
+
lastCheckedAtMs: number().nullable()
|
|
15910
|
+
});
|
|
15911
|
+
var ServerUpdateCheckResultSchema = object({
|
|
15912
|
+
packageName: string(),
|
|
15913
|
+
runningVersion: string().nullable(),
|
|
15914
|
+
latestVersion: string().nullable(),
|
|
15915
|
+
updateAvailable: boolean(),
|
|
15916
|
+
checkedAtMs: number(),
|
|
15917
|
+
/** Non-null when the registry lookup failed (offline, bad registry, …). */
|
|
15918
|
+
error: string().nullable()
|
|
15919
|
+
});
|
|
15920
|
+
var ServerUpdateActionResultSchema = object({
|
|
15921
|
+
accepted: boolean(),
|
|
15922
|
+
targetVersion: string().nullable(),
|
|
15923
|
+
/** True when a graceful restart was scheduled to apply the change. */
|
|
15924
|
+
restarting: boolean(),
|
|
15925
|
+
message: string()
|
|
15926
|
+
});
|
|
15927
|
+
method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
|
|
15928
|
+
kind: "mutation",
|
|
15929
|
+
auth: "admin"
|
|
15930
|
+
}), method(object({
|
|
15931
|
+
/** Explicit target version; omitted = latest from the registry. */
|
|
15932
|
+
version: string().optional() }), ServerUpdateActionResultSchema, {
|
|
15933
|
+
kind: "mutation",
|
|
15934
|
+
auth: "admin"
|
|
15935
|
+
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
15936
|
+
kind: "mutation",
|
|
15937
|
+
auth: "admin"
|
|
15938
|
+
}), method(_void(), ServerUpdateActionResultSchema, {
|
|
15939
|
+
kind: "mutation",
|
|
15940
|
+
auth: "admin"
|
|
15910
15941
|
});
|
|
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
15942
|
/**
|
|
15916
15943
|
* Query filter for settings-store collections.
|
|
15917
15944
|
*/
|
|
@@ -16064,9 +16091,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
|
|
|
16064
16091
|
/**
|
|
16065
16092
|
* A single device snapshot returned as base64 JPEG/PNG.
|
|
16066
16093
|
*
|
|
16067
|
-
*
|
|
16068
|
-
*
|
|
16069
|
-
*
|
|
16094
|
+
* The `SnapshotAddon` wrapper returns this shape whether the frame came from
|
|
16095
|
+
* the device-native provider (onboard capture) or from the stream-broker
|
|
16096
|
+
* prebuffer fallback.
|
|
16070
16097
|
*/
|
|
16071
16098
|
var SnapshotImageSchema = object({
|
|
16072
16099
|
base64: string(),
|
|
@@ -16098,10 +16125,6 @@ DeviceType.Camera, method(object({
|
|
|
16098
16125
|
kind: "mutation",
|
|
16099
16126
|
auth: "admin"
|
|
16100
16127
|
});
|
|
16101
|
-
method(object({ deviceId: number() }), boolean()), method(object({
|
|
16102
|
-
deviceId: number(),
|
|
16103
|
-
streamId: string().optional()
|
|
16104
|
-
}), SnapshotImageSchema.nullable());
|
|
16105
16128
|
/**
|
|
16106
16129
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
|
16107
16130
|
* providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
|
|
@@ -16462,9 +16485,10 @@ method(object({
|
|
|
16462
16485
|
auth: "admin"
|
|
16463
16486
|
});
|
|
16464
16487
|
/**
|
|
16465
|
-
* Optional client-side hints sent at session creation to help the
|
|
16466
|
-
*
|
|
16467
|
-
*
|
|
16488
|
+
* Optional client-side hints sent at session creation to help the provider
|
|
16489
|
+
* pick the best native source. All fields optional — a viewer that knows
|
|
16490
|
+
* nothing still gets a sane default. (Relocated from the retired `webrtc`
|
|
16491
|
+
* collection cap; this `webrtc-session` cap is the live signaling surface.)
|
|
16468
16492
|
*/
|
|
16469
16493
|
var webrtcClientHintsSchema = object({
|
|
16470
16494
|
viewportWidth: number().int().positive().optional(),
|
|
@@ -16475,22 +16499,6 @@ var webrtcClientHintsSchema = object({
|
|
|
16475
16499
|
/** Hard tier override; takes precedence over scoring when registered. */
|
|
16476
16500
|
prefersTier: string().optional()
|
|
16477
16501
|
}).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
16502
|
/**
|
|
16495
16503
|
* Discriminated target for a WebRTC session. The client sends this
|
|
16496
16504
|
* structured object instead of building / parsing brokerId strings;
|
|
@@ -17918,6 +17926,16 @@ var TopologyCategorySchema = object({
|
|
|
17918
17926
|
healthy: number(),
|
|
17919
17927
|
addons: array(TopologyCategoryAddonSchema).readonly()
|
|
17920
17928
|
});
|
|
17929
|
+
/**
|
|
17930
|
+
* The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
|
|
17931
|
+
* `@camstack/agent` on agents) as reported by its `registerNode` manifest —
|
|
17932
|
+
* version visibility for the Server management surface. Nullable: offline
|
|
17933
|
+
* rows and pre-phase-2 nodes report none.
|
|
17934
|
+
*/
|
|
17935
|
+
var TopologyRootPackageSchema = object({
|
|
17936
|
+
name: string(),
|
|
17937
|
+
version: string()
|
|
17938
|
+
});
|
|
17921
17939
|
var TopologyNodeSchema = object({
|
|
17922
17940
|
id: string(),
|
|
17923
17941
|
name: string(),
|
|
@@ -17941,7 +17959,8 @@ var TopologyNodeSchema = object({
|
|
|
17941
17959
|
status: string()
|
|
17942
17960
|
})).readonly(),
|
|
17943
17961
|
processes: array(TopologyProcessSchema).readonly(),
|
|
17944
|
-
categories: array(TopologyCategorySchema).readonly()
|
|
17962
|
+
categories: array(TopologyCategorySchema).readonly(),
|
|
17963
|
+
rootPackage: TopologyRootPackageSchema.nullable()
|
|
17945
17964
|
});
|
|
17946
17965
|
var CapUsageEdgeSchema = object({
|
|
17947
17966
|
callerAddonId: string(),
|
|
@@ -20741,6 +20760,12 @@ Object.freeze({
|
|
|
20741
20760
|
addonId: null,
|
|
20742
20761
|
access: "create"
|
|
20743
20762
|
},
|
|
20763
|
+
"loginMethod.getLoginMethods": {
|
|
20764
|
+
capName: "login-method",
|
|
20765
|
+
capScope: "system",
|
|
20766
|
+
addonId: null,
|
|
20767
|
+
access: "view"
|
|
20768
|
+
},
|
|
20744
20769
|
"mediaPlayer.next": {
|
|
20745
20770
|
capName: "media-player",
|
|
20746
20771
|
capScope: "device",
|
|
@@ -21371,23 +21396,23 @@ Object.freeze({
|
|
|
21371
21396
|
addonId: null,
|
|
21372
21397
|
access: "create"
|
|
21373
21398
|
},
|
|
21374
|
-
"pipelineExecutor.
|
|
21399
|
+
"pipelineExecutor.clearDeviceOverrides": {
|
|
21375
21400
|
capName: "pipeline-executor",
|
|
21376
21401
|
capScope: "system",
|
|
21377
21402
|
addonId: null,
|
|
21378
21403
|
access: "delete"
|
|
21379
21404
|
},
|
|
21380
|
-
"pipelineExecutor.
|
|
21405
|
+
"pipelineExecutor.deleteModel": {
|
|
21381
21406
|
capName: "pipeline-executor",
|
|
21382
21407
|
capScope: "system",
|
|
21383
21408
|
addonId: null,
|
|
21384
21409
|
access: "delete"
|
|
21385
21410
|
},
|
|
21386
|
-
"pipelineExecutor.
|
|
21411
|
+
"pipelineExecutor.deleteTemplate": {
|
|
21387
21412
|
capName: "pipeline-executor",
|
|
21388
21413
|
capScope: "system",
|
|
21389
21414
|
addonId: null,
|
|
21390
|
-
access: "
|
|
21415
|
+
access: "delete"
|
|
21391
21416
|
},
|
|
21392
21417
|
"pipelineExecutor.downloadModel": {
|
|
21393
21418
|
capName: "pipeline-executor",
|
|
@@ -21581,13 +21606,13 @@ Object.freeze({
|
|
|
21581
21606
|
addonId: null,
|
|
21582
21607
|
access: "create"
|
|
21583
21608
|
},
|
|
21584
|
-
"
|
|
21585
|
-
capName: "pipeline-
|
|
21609
|
+
"pipelineExecutor.validatePipeline": {
|
|
21610
|
+
capName: "pipeline-executor",
|
|
21586
21611
|
capScope: "system",
|
|
21587
21612
|
addonId: null,
|
|
21588
|
-
access: "
|
|
21613
|
+
access: "view"
|
|
21589
21614
|
},
|
|
21590
|
-
"pipelineOrchestrator.
|
|
21615
|
+
"pipelineOrchestrator.assignAudio": {
|
|
21591
21616
|
capName: "pipeline-orchestrator",
|
|
21592
21617
|
capScope: "system",
|
|
21593
21618
|
addonId: null,
|
|
@@ -21671,19 +21696,13 @@ Object.freeze({
|
|
|
21671
21696
|
addonId: null,
|
|
21672
21697
|
access: "view"
|
|
21673
21698
|
},
|
|
21674
|
-
"pipelineOrchestrator.
|
|
21675
|
-
capName: "pipeline-orchestrator",
|
|
21676
|
-
capScope: "system",
|
|
21677
|
-
addonId: null,
|
|
21678
|
-
access: "view"
|
|
21679
|
-
},
|
|
21680
|
-
"pipelineOrchestrator.getDecoderAssignments": {
|
|
21699
|
+
"pipelineOrchestrator.getGlobalMetrics": {
|
|
21681
21700
|
capName: "pipeline-orchestrator",
|
|
21682
21701
|
capScope: "system",
|
|
21683
21702
|
addonId: null,
|
|
21684
21703
|
access: "view"
|
|
21685
21704
|
},
|
|
21686
|
-
"pipelineOrchestrator.
|
|
21705
|
+
"pipelineOrchestrator.getIngestOwner": {
|
|
21687
21706
|
capName: "pipeline-orchestrator",
|
|
21688
21707
|
capScope: "system",
|
|
21689
21708
|
addonId: null,
|
|
@@ -21725,6 +21744,12 @@ Object.freeze({
|
|
|
21725
21744
|
addonId: null,
|
|
21726
21745
|
access: "delete"
|
|
21727
21746
|
},
|
|
21747
|
+
"pipelineOrchestrator.resetNodePipelineDefaults": {
|
|
21748
|
+
capName: "pipeline-orchestrator",
|
|
21749
|
+
capScope: "system",
|
|
21750
|
+
addonId: null,
|
|
21751
|
+
access: "delete"
|
|
21752
|
+
},
|
|
21728
21753
|
"pipelineOrchestrator.resolvePipeline": {
|
|
21729
21754
|
capName: "pipeline-orchestrator",
|
|
21730
21755
|
capScope: "system",
|
|
@@ -21761,37 +21786,37 @@ Object.freeze({
|
|
|
21761
21786
|
addonId: null,
|
|
21762
21787
|
access: "create"
|
|
21763
21788
|
},
|
|
21764
|
-
"pipelineOrchestrator.
|
|
21789
|
+
"pipelineOrchestrator.setAgentReachableHost": {
|
|
21765
21790
|
capName: "pipeline-orchestrator",
|
|
21766
21791
|
capScope: "system",
|
|
21767
21792
|
addonId: null,
|
|
21768
21793
|
access: "create"
|
|
21769
21794
|
},
|
|
21770
|
-
"pipelineOrchestrator.
|
|
21795
|
+
"pipelineOrchestrator.setCameraPipelineForAgent": {
|
|
21771
21796
|
capName: "pipeline-orchestrator",
|
|
21772
21797
|
capScope: "system",
|
|
21773
21798
|
addonId: null,
|
|
21774
21799
|
access: "create"
|
|
21775
21800
|
},
|
|
21776
|
-
"pipelineOrchestrator.
|
|
21801
|
+
"pipelineOrchestrator.setCameraStepOverride": {
|
|
21777
21802
|
capName: "pipeline-orchestrator",
|
|
21778
21803
|
capScope: "system",
|
|
21779
21804
|
addonId: null,
|
|
21780
21805
|
access: "create"
|
|
21781
21806
|
},
|
|
21782
|
-
"pipelineOrchestrator.
|
|
21807
|
+
"pipelineOrchestrator.setCameraStepToggle": {
|
|
21783
21808
|
capName: "pipeline-orchestrator",
|
|
21784
21809
|
capScope: "system",
|
|
21785
21810
|
addonId: null,
|
|
21786
21811
|
access: "create"
|
|
21787
21812
|
},
|
|
21788
|
-
"pipelineOrchestrator.
|
|
21813
|
+
"pipelineOrchestrator.setCapabilityBinding": {
|
|
21789
21814
|
capName: "pipeline-orchestrator",
|
|
21790
21815
|
capScope: "system",
|
|
21791
21816
|
addonId: null,
|
|
21792
21817
|
access: "create"
|
|
21793
21818
|
},
|
|
21794
|
-
"pipelineOrchestrator.
|
|
21819
|
+
"pipelineOrchestrator.unassignAudio": {
|
|
21795
21820
|
capName: "pipeline-orchestrator",
|
|
21796
21821
|
capScope: "system",
|
|
21797
21822
|
addonId: null,
|
|
@@ -22091,33 +22116,45 @@ Object.freeze({
|
|
|
22091
22116
|
addonId: null,
|
|
22092
22117
|
access: "create"
|
|
22093
22118
|
},
|
|
22094
|
-
"
|
|
22095
|
-
capName: "
|
|
22119
|
+
"scriptRunner.run": {
|
|
22120
|
+
capName: "script-runner",
|
|
22121
|
+
capScope: "device",
|
|
22122
|
+
addonId: null,
|
|
22123
|
+
access: "create"
|
|
22124
|
+
},
|
|
22125
|
+
"scriptRunner.stop": {
|
|
22126
|
+
capName: "script-runner",
|
|
22127
|
+
capScope: "device",
|
|
22128
|
+
addonId: null,
|
|
22129
|
+
access: "create"
|
|
22130
|
+
},
|
|
22131
|
+
"serverManagement.applyServerUpdate": {
|
|
22132
|
+
capName: "server-management",
|
|
22096
22133
|
capScope: "system",
|
|
22097
22134
|
addonId: null,
|
|
22098
|
-
access: "
|
|
22135
|
+
access: "create"
|
|
22099
22136
|
},
|
|
22100
|
-
"
|
|
22101
|
-
capName: "
|
|
22137
|
+
"serverManagement.checkServerUpdate": {
|
|
22138
|
+
capName: "server-management",
|
|
22102
22139
|
capScope: "system",
|
|
22103
22140
|
addonId: null,
|
|
22104
22141
|
access: "create"
|
|
22105
22142
|
},
|
|
22106
|
-
"
|
|
22107
|
-
capName: "
|
|
22143
|
+
"serverManagement.getServerPackageStatus": {
|
|
22144
|
+
capName: "server-management",
|
|
22108
22145
|
capScope: "system",
|
|
22109
22146
|
addonId: null,
|
|
22110
|
-
access: "
|
|
22147
|
+
access: "view"
|
|
22111
22148
|
},
|
|
22112
|
-
"
|
|
22113
|
-
capName: "
|
|
22114
|
-
capScope: "
|
|
22149
|
+
"serverManagement.restartServer": {
|
|
22150
|
+
capName: "server-management",
|
|
22151
|
+
capScope: "system",
|
|
22115
22152
|
addonId: null,
|
|
22116
22153
|
access: "create"
|
|
22117
22154
|
},
|
|
22118
|
-
"
|
|
22119
|
-
capName: "
|
|
22120
|
-
capScope: "
|
|
22155
|
+
"serverManagement.rollbackServerUpdate": {
|
|
22156
|
+
capName: "server-management",
|
|
22157
|
+
capScope: "system",
|
|
22121
22158
|
addonId: null,
|
|
22122
22159
|
access: "create"
|
|
22123
22160
|
},
|
|
@@ -22211,18 +22248,6 @@ Object.freeze({
|
|
|
22211
22248
|
addonId: null,
|
|
22212
22249
|
access: "create"
|
|
22213
22250
|
},
|
|
22214
|
-
"snapshotProvider.getSnapshot": {
|
|
22215
|
-
capName: "snapshot-provider",
|
|
22216
|
-
capScope: "system",
|
|
22217
|
-
addonId: null,
|
|
22218
|
-
access: "view"
|
|
22219
|
-
},
|
|
22220
|
-
"snapshotProvider.supportsDevice": {
|
|
22221
|
-
capName: "snapshot-provider",
|
|
22222
|
-
capScope: "system",
|
|
22223
|
-
addonId: null,
|
|
22224
|
-
access: "view"
|
|
22225
|
-
},
|
|
22226
22251
|
"ssoBridge.signBridgeToken": {
|
|
22227
22252
|
capName: "sso-bridge",
|
|
22228
22253
|
capScope: "system",
|
|
@@ -22649,30 +22674,6 @@ Object.freeze({
|
|
|
22649
22674
|
addonId: null,
|
|
22650
22675
|
access: "view"
|
|
22651
22676
|
},
|
|
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
22677
|
"streamParams.getConfigSchema": {
|
|
22677
22678
|
capName: "stream-params",
|
|
22678
22679
|
capScope: "device",
|
|
@@ -23021,6 +23022,18 @@ Object.freeze({
|
|
|
23021
23022
|
addonId: null,
|
|
23022
23023
|
access: "view"
|
|
23023
23024
|
},
|
|
23025
|
+
"viewerUi.getStaticDir": {
|
|
23026
|
+
capName: "viewer-ui",
|
|
23027
|
+
capScope: "system",
|
|
23028
|
+
addonId: null,
|
|
23029
|
+
access: "view"
|
|
23030
|
+
},
|
|
23031
|
+
"viewerUi.getVersion": {
|
|
23032
|
+
capName: "viewer-ui",
|
|
23033
|
+
capScope: "system",
|
|
23034
|
+
addonId: null,
|
|
23035
|
+
access: "view"
|
|
23036
|
+
},
|
|
23024
23037
|
"waterHeater.setAway": {
|
|
23025
23038
|
capName: "water-heater",
|
|
23026
23039
|
capScope: "device",
|
|
@@ -23039,54 +23052,6 @@ Object.freeze({
|
|
|
23039
23052
|
addonId: null,
|
|
23040
23053
|
access: "create"
|
|
23041
23054
|
},
|
|
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
23055
|
"webrtcSession.addIceCandidate": {
|
|
23091
23056
|
capName: "webrtc-session",
|
|
23092
23057
|
capScope: "device",
|
|
@@ -23935,7 +23900,7 @@ var NodeAvDecoderSession = class NodeAvDecoderSession {
|
|
|
23935
23900
|
if (typeof this.config.deviceId === "number") seedParts.push(String(this.config.deviceId));
|
|
23936
23901
|
if (typeof this.config.tag === "string" && this.config.tag.length > 0) seedParts.push(this.config.tag);
|
|
23937
23902
|
const seed = seedParts.length > 0 ? seedParts.join(":") : "anon";
|
|
23938
|
-
this.frameRingSink = new DecoderFrameRingSink({
|
|
23903
|
+
this.frameRingSink = new _camstack_shm_ring.DecoderFrameRingSink({
|
|
23939
23904
|
seed,
|
|
23940
23905
|
logger: this.logger,
|
|
23941
23906
|
nodeId: this.nodeId
|
|
@@ -25789,7 +25754,7 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
25789
25754
|
return registrations;
|
|
25790
25755
|
}
|
|
25791
25756
|
this.ctx.logger.info("node-av decoder addon initialized", { meta: { selectedBackend: backend } });
|
|
25792
|
-
const purged = purgeOrphanSegments(SEGMENT_NAME_PREFIX);
|
|
25757
|
+
const purged = purgeOrphanSegments(_camstack_shm_ring.SEGMENT_NAME_PREFIX);
|
|
25793
25758
|
if (purged.removed > 0) this.ctx.logger.warn("node-av decoder: reclaimed orphaned shm segments at startup", { meta: {
|
|
25794
25759
|
removed: purged.removed,
|
|
25795
25760
|
scanned: purged.scanned
|
|
@@ -26050,7 +26015,7 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
26050
26015
|
return {
|
|
26051
26016
|
sessionId: input.sessionId,
|
|
26052
26017
|
...stats,
|
|
26053
|
-
budgetMb: RING_BUDGET_MB,
|
|
26018
|
+
budgetMb: _camstack_shm_ring.RING_BUDGET_MB,
|
|
26054
26019
|
getFrameHits: this.getFrameHits,
|
|
26055
26020
|
getFrameMisses: this.getFrameMisses
|
|
26056
26021
|
};
|
|
@@ -26076,7 +26041,12 @@ var DecoderNodeAvAddon = class extends BaseAddon {
|
|
|
26076
26041
|
}
|
|
26077
26042
|
};
|
|
26078
26043
|
//#endregion
|
|
26079
|
-
exports
|
|
26044
|
+
Object.defineProperty(exports, "DecoderFrameRingSink", {
|
|
26045
|
+
enumerable: true,
|
|
26046
|
+
get: function() {
|
|
26047
|
+
return _camstack_shm_ring.DecoderFrameRingSink;
|
|
26048
|
+
}
|
|
26049
|
+
});
|
|
26080
26050
|
exports.DecoderNodeAvAddon = DecoderNodeAvAddon;
|
|
26081
26051
|
exports.NodeAvAudioCodecProvider = NodeAvAudioCodecProvider;
|
|
26082
26052
|
exports.NodeAvAudioDecodeSession = NodeAvAudioDecodeSession;
|
|
@@ -26084,5 +26054,10 @@ exports.NodeAvAudioEncodeSession = NodeAvAudioEncodeSession;
|
|
|
26084
26054
|
exports.NodeAvDecoderSession = NodeAvDecoderSession;
|
|
26085
26055
|
exports.default = DecoderNodeAvAddon;
|
|
26086
26056
|
exports.loadNodeAvRuntime = loadNodeAvRuntime;
|
|
26087
|
-
exports
|
|
26057
|
+
Object.defineProperty(exports, "makeSegmentName", {
|
|
26058
|
+
enumerable: true,
|
|
26059
|
+
get: function() {
|
|
26060
|
+
return _camstack_shm_ring.makeSegmentName;
|
|
26061
|
+
}
|
|
26062
|
+
});
|
|
26088
26063
|
exports.peekNodeAvRuntime = peekNodeAvRuntime;
|