@camstack/addon-post-analysis 1.2.46 → 1.2.48
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/{dist-BoV5RsRC.mjs → dist-4NhN1aPx.mjs} +604 -22
- package/dist/{dist-QzgUDrwU.js → dist-DKhwOB5L.js} +621 -21
- package/dist/embedding-encoder/index.js +2 -2
- package/dist/embedding-encoder/index.mjs +2 -2
- package/dist/{node-BmVBZiOw.mjs → node-Bjc_xs4R.mjs} +1 -0
- package/dist/{node-HrEN5lB7.js → node-XPzbKGXi.js} +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DvfzPjZx.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CD55gKkr.mjs} +2 -2
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Da6ggNiB.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BfiNBOyJ.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-BhH6N_nH.mjs → hostInit-DnhLbxcA.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +9426 -7001
- package/dist/pipeline-analytics/index.mjs +9424 -6999
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -7090,6 +7090,30 @@ var DEVICE_SCOPED_CAPS = new Set([
|
|
|
7090
7090
|
function isDeviceScopedCap(capName) {
|
|
7091
7091
|
return DEVICE_SCOPED_CAPS.has(capName);
|
|
7092
7092
|
}
|
|
7093
|
+
/**
|
|
7094
|
+
* Promise-based timer helpers — used everywhere the codebase needs to
|
|
7095
|
+
* wait, back off, or schedule a retry. Before these helpers landed, each
|
|
7096
|
+
* call site re-implemented `new Promise(r => setTimeout(r, ms))` inline,
|
|
7097
|
+
* with subtle variations (some swallowing cancellation, some not). Two
|
|
7098
|
+
* shapes cover every observed use case:
|
|
7099
|
+
*
|
|
7100
|
+
* - {@link sleep} for a plain, uncancellable wait — the default choice.
|
|
7101
|
+
* - {@link sleepCancellable} for a wait that wakes early when an
|
|
7102
|
+
* abort signal trips, used by long-running pollers whose teardown
|
|
7103
|
+
* must stop a pending backoff promptly.
|
|
7104
|
+
*/
|
|
7105
|
+
/**
|
|
7106
|
+
* Resolve after `ms` milliseconds. Never rejects, never cancels. The
|
|
7107
|
+
* sleep cannot be interrupted; for a wakeable variant use
|
|
7108
|
+
* {@link sleepCancellable}.
|
|
7109
|
+
*
|
|
7110
|
+
* `ms <= 0` resolves on the next microtask via `setTimeout(0)`, which
|
|
7111
|
+
* still gives the event loop a chance to drain — useful for breaking
|
|
7112
|
+
* up tight async loops without changing call-site semantics.
|
|
7113
|
+
*/
|
|
7114
|
+
function sleep(ms) {
|
|
7115
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
7116
|
+
}
|
|
7093
7117
|
//#endregion
|
|
7094
7118
|
//#region ../types/dist/err-msg-IQTHeDzc.mjs
|
|
7095
7119
|
/**
|
|
@@ -7114,6 +7138,14 @@ var EncodeProfileSchema = object({
|
|
|
7114
7138
|
"main",
|
|
7115
7139
|
"high"
|
|
7116
7140
|
]).optional(),
|
|
7141
|
+
/**
|
|
7142
|
+
* `-level`, e.g. `'3.1'`. A consumer that ADVERTISES a level in its SDP
|
|
7143
|
+
* (`profile-level-id=42e01f` is Baseline 3.1) must constrain the encoder to
|
|
7144
|
+
* it, or it ships a stream that does not match its own advertisement — the
|
|
7145
|
+
* defect class that kept HomeKit black for a year and that Alexa carried
|
|
7146
|
+
* silently. Optional because a browser negotiates the level itself.
|
|
7147
|
+
*/
|
|
7148
|
+
level: string().optional(),
|
|
7117
7149
|
width: number().int().positive().optional(),
|
|
7118
7150
|
height: number().int().positive().optional(),
|
|
7119
7151
|
fps: number().positive().optional(),
|
|
@@ -7161,6 +7193,29 @@ var EncodeProfileSchema = object({
|
|
|
7161
7193
|
outputArgs: array(string()).optional()
|
|
7162
7194
|
});
|
|
7163
7195
|
/**
|
|
7196
|
+
* The shape every live egress starts from: H.264 Baseline 3.1 at 720p25.
|
|
7197
|
+
* Baseline because it is the one profile every consumer in this repo decodes
|
|
7198
|
+
* (Echo, iOS, an old browser); 3.1 because that is what the SDPs advertise.
|
|
7199
|
+
*/
|
|
7200
|
+
var BASE_LIVE_EGRESS_PROFILE = {
|
|
7201
|
+
video: {
|
|
7202
|
+
codec: "h264",
|
|
7203
|
+
profile: "baseline",
|
|
7204
|
+
level: "3.1",
|
|
7205
|
+
width: 1280,
|
|
7206
|
+
height: 720,
|
|
7207
|
+
fps: 25,
|
|
7208
|
+
bitrateKbps: 2500,
|
|
7209
|
+
gopFrames: 25,
|
|
7210
|
+
bf: 0,
|
|
7211
|
+
preset: "veryfast",
|
|
7212
|
+
tune: "zerolatency"
|
|
7213
|
+
},
|
|
7214
|
+
audio: "passthrough"
|
|
7215
|
+
};
|
|
7216
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7217
|
+
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7218
|
+
/**
|
|
7164
7219
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7165
7220
|
* every declared capability + widget of every installed plugin, on every
|
|
7166
7221
|
* node. Produced by the backend `WiringHealthService` and surfaced via
|
|
@@ -7210,6 +7265,105 @@ object({
|
|
|
7210
7265
|
})
|
|
7211
7266
|
});
|
|
7212
7267
|
/**
|
|
7268
|
+
* Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
|
|
7269
|
+
* pipeline functions an operator thinks in terms of.
|
|
7270
|
+
*
|
|
7271
|
+
* ## This file adds no state
|
|
7272
|
+
*
|
|
7273
|
+
* Every switch here is a VIEW onto an authority that already existed
|
|
7274
|
+
* ([D61](../../../../docs/decisions/adr-0062.md)). The whole point of the
|
|
7275
|
+
* group is that there is exactly one place each function is turned off, and
|
|
7276
|
+
* the group routes to it:
|
|
7277
|
+
*
|
|
7278
|
+
* | Switch | Authority | Proven "off stops the work" gate |
|
|
7279
|
+
* | --- | --- | --- |
|
|
7280
|
+
* | `stream-broker` | `deviceManager.setDisabled` | `StreamBrokerManager.reconcileAllCatalogs` releases the brokers; `ensureBroker` refuses re-creation |
|
|
7281
|
+
* | `object-detection` | `deviceManager.setWrapperActive('detection-pipeline')` | `PipelineSettingsStore.resolvePipelineForDevice` returns `{ steps: [], audio: null }` |
|
|
7282
|
+
* | `audio-analysis` | `deviceManager.setWrapperActive('audio-analysis')` | `AudioSubscriptionController.subscribeAudioStream` returns `null` before opening the stream |
|
|
7283
|
+
* | `recording` | `recording.setDeviceConfig` → `RecordingConfig.enabled` | `band-decision.shouldRecord` returns false; the controller detaches the device |
|
|
7284
|
+
* | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
|
|
7285
|
+
*
|
|
7286
|
+
* The wrapper-binding pair is not a new idea: `legacy-migrations.ts` already
|
|
7287
|
+
* migrated the legacy `audioEnabled` / `pipelineEnabled` /
|
|
7288
|
+
* `motionDetectionEnabled` booleans ONTO `setWrapperActive`. The group is the
|
|
7289
|
+
* surface that decision never got.
|
|
7290
|
+
*
|
|
7291
|
+
* ## Two rules that are load-bearing
|
|
7292
|
+
*
|
|
7293
|
+
* - **Recording's switch is `enabled`, never the bands.** `bands` is the only
|
|
7294
|
+
* authored intent and `mode` is derived from it (`deriveRecordingMode`).
|
|
7295
|
+
* Expressing "off" by clearing bands destroys the operator's schedule and
|
|
7296
|
+
* turning the camera back on would then silently record nothing.
|
|
7297
|
+
* - **A switch that is off must be reported as off**, not merely produce
|
|
7298
|
+
* nothing. {@link CameraSwitch.enabled} is what a status surface renders as
|
|
7299
|
+
* "disabled by an operator" instead of "broken" — see
|
|
7300
|
+
* `CameraStatus.switchedOff`.
|
|
7301
|
+
*/
|
|
7302
|
+
/**
|
|
7303
|
+
* The five functions the operator named (2026-08-05). Deliberately NOT one id
|
|
7304
|
+
* per pipeline step: face recognition and plate/LPR are per-step toggles on
|
|
7305
|
+
* `pipelineOrchestrator.setCameraStepToggle` and belong in the pipeline
|
|
7306
|
+
* editor, not in a five-button safety group.
|
|
7307
|
+
*/
|
|
7308
|
+
var CameraSwitchIdSchema = _enum([
|
|
7309
|
+
"stream-broker",
|
|
7310
|
+
"object-detection",
|
|
7311
|
+
"audio-analysis",
|
|
7312
|
+
"recording",
|
|
7313
|
+
"notifications"
|
|
7314
|
+
]);
|
|
7315
|
+
/**
|
|
7316
|
+
* WHERE the switch's state actually lives. A discriminated union rather than a
|
|
7317
|
+
* string so both the writer (the orchestrator's `setCameraSwitch`) and any
|
|
7318
|
+
* reader can exhaustively narrow — and so "the group added a parallel map" is
|
|
7319
|
+
* a compile error rather than a review comment.
|
|
7320
|
+
*/
|
|
7321
|
+
var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
|
|
7322
|
+
object({ kind: literal("device-disabled") }),
|
|
7323
|
+
object({
|
|
7324
|
+
kind: literal("wrapper-binding"),
|
|
7325
|
+
capName: string()
|
|
7326
|
+
}),
|
|
7327
|
+
object({ kind: literal("recording-config") }),
|
|
7328
|
+
object({ kind: literal("notification-mute") })
|
|
7329
|
+
]);
|
|
7330
|
+
/**
|
|
7331
|
+
* Why a switch is not offered for this camera. Rendered instead of the
|
|
7332
|
+
* control, never as a dead control — an absent function and a broken one must
|
|
7333
|
+
* not look the same.
|
|
7334
|
+
*/
|
|
7335
|
+
var CameraSwitchUnavailableReasonSchema = _enum(["no-provider", "source-unreachable"]);
|
|
7336
|
+
/**
|
|
7337
|
+
* One switch, resolved for one camera.
|
|
7338
|
+
*
|
|
7339
|
+
* `label` and `costWhenOff` travel ON THE WIRE rather than being looked up
|
|
7340
|
+
* client-side: the viewer is a separate repository that does not import
|
|
7341
|
+
* `@camstack/types`, and a cost line duplicated in two clients is a cost line
|
|
7342
|
+
* that will disagree with itself. Five rows per camera is nothing.
|
|
7343
|
+
*/
|
|
7344
|
+
var CameraSwitchSchema = object({
|
|
7345
|
+
id: CameraSwitchIdSchema,
|
|
7346
|
+
label: string(),
|
|
7347
|
+
/**
|
|
7348
|
+
* What the operator LOSES while this is off, in one sentence. Required, not
|
|
7349
|
+
* optional: a switch that cannot say what it costs should not ship.
|
|
7350
|
+
*/
|
|
7351
|
+
costWhenOff: string(),
|
|
7352
|
+
/** False = do not render a control. `unavailableReason` says why. */
|
|
7353
|
+
available: boolean(),
|
|
7354
|
+
unavailableReason: CameraSwitchUnavailableReasonSchema.optional(),
|
|
7355
|
+
/** Current state. Meaningless when `available` is false — read it as `true`. */
|
|
7356
|
+
enabled: boolean(),
|
|
7357
|
+
authority: CameraSwitchAuthoritySchema
|
|
7358
|
+
});
|
|
7359
|
+
/** The whole group for one camera. */
|
|
7360
|
+
var CameraSwitchGroupSchema = object({
|
|
7361
|
+
deviceId: number().int(),
|
|
7362
|
+
switches: array(CameraSwitchSchema).readonly(),
|
|
7363
|
+
/** Unix ms when the group was composed server-side. */
|
|
7364
|
+
fetchedAt: number()
|
|
7365
|
+
});
|
|
7366
|
+
/**
|
|
7213
7367
|
* Ops-log — the durable, append-only operations audit shared by the
|
|
7214
7368
|
* recordings and events management surfaces.
|
|
7215
7369
|
*
|
|
@@ -7228,14 +7382,16 @@ var OpsLogOpSchema = _enum([
|
|
|
7228
7382
|
"manual-delete",
|
|
7229
7383
|
"rescan",
|
|
7230
7384
|
"retention-run",
|
|
7231
|
-
"relocate"
|
|
7385
|
+
"relocate",
|
|
7386
|
+
"orphan-audit"
|
|
7232
7387
|
]);
|
|
7233
7388
|
/** Why the operation ran. */
|
|
7234
7389
|
var OpsLogReasonSchema = _enum([
|
|
7235
7390
|
"retention",
|
|
7236
7391
|
"quota",
|
|
7237
7392
|
"manual",
|
|
7238
|
-
"operator"
|
|
7393
|
+
"operator",
|
|
7394
|
+
"maintenance"
|
|
7239
7395
|
]);
|
|
7240
7396
|
/** One audit row, shared verbatim by both domains. */
|
|
7241
7397
|
var OpsLogEntrySchema = object({
|
|
@@ -9121,6 +9277,100 @@ var RtpSourceSchema = object({
|
|
|
9121
9277
|
encoder: string(),
|
|
9122
9278
|
pipelineKey: string()
|
|
9123
9279
|
});
|
|
9280
|
+
/**
|
|
9281
|
+
* The encode request — **structured and serialisable, with NO raw-flag escape
|
|
9282
|
+
* hatch.** This is deliberate and it is the one lesson taken from
|
|
9283
|
+
* `getStreamWithCodec`: that method's `outputArgs: string[]` is simultaneously
|
|
9284
|
+
* its extensibility mechanism AND part of `pipelineKeyFor`'s sharing key, so
|
|
9285
|
+
* adding a flag silently forks the shared child, and two consumers that mean
|
|
9286
|
+
* the same thing but spell it differently never share. Here every knob is a
|
|
9287
|
+
* NAMED field: a new requirement becomes a schema field (and a codegen run),
|
|
9288
|
+
* never an opaque array.
|
|
9289
|
+
*
|
|
9290
|
+
* `inputArgs` / `outputArgs` are omitted from the profile for the same reason.
|
|
9291
|
+
* The operator-facing derived-stream transform editor still has them — that is
|
|
9292
|
+
* a different surface (`publishCameraStream({ kind: 'derived' })`) with a
|
|
9293
|
+
* different purpose (reshaping a badly-behaved SOURCE), and it is unchanged.
|
|
9294
|
+
*/
|
|
9295
|
+
var EgressEncodeSchema = EncodeProfileSchema.omit({
|
|
9296
|
+
inputArgs: true,
|
|
9297
|
+
outputArgs: true
|
|
9298
|
+
});
|
|
9299
|
+
/**
|
|
9300
|
+
* How the encoder is bounded. `'tight'` is a one-second VBV window for a
|
|
9301
|
+
* consumer whose budget is enforced per second (HomeKit); `'relaxed'` is two
|
|
9302
|
+
* seconds, letting a keyframe spike borrow from the next second (a browser,
|
|
9303
|
+
* an Echo). Named rather than numeric so the INTENT survives.
|
|
9304
|
+
*/
|
|
9305
|
+
var EgressRateControlSchema = _enum(["tight", "relaxed"]);
|
|
9306
|
+
var EgressTranscodeRequestSchema = object({
|
|
9307
|
+
deviceId: number().int().nonnegative(),
|
|
9308
|
+
/** Which published stream to read. */
|
|
9309
|
+
source: discriminatedUnion("kind", [object({
|
|
9310
|
+
kind: literal("profile"),
|
|
9311
|
+
profile: CamProfileSchema
|
|
9312
|
+
}), object({
|
|
9313
|
+
kind: literal("cam-stream"),
|
|
9314
|
+
camStreamId: string().min(1)
|
|
9315
|
+
})]),
|
|
9316
|
+
encode: EgressEncodeSchema,
|
|
9317
|
+
rateControl: EgressRateControlSchema.optional(),
|
|
9318
|
+
/**
|
|
9319
|
+
* `-bsf:v`. A consumer that negotiates its OWN SDP (HomeKit) cannot carry
|
|
9320
|
+
* out-of-band extradata and needs `dump_extra` on both the copy and encode
|
|
9321
|
+
* branches. Enumerated, not free text.
|
|
9322
|
+
*/
|
|
9323
|
+
bitstreamFilter: _enum([
|
|
9324
|
+
"dump_extra",
|
|
9325
|
+
"h264_mp4toannexb",
|
|
9326
|
+
"hevc_mp4toannexb"
|
|
9327
|
+
]).optional(),
|
|
9328
|
+
pixelFormat: _enum(["yuv420p", "nv12"]).optional(),
|
|
9329
|
+
/**
|
|
9330
|
+
* Operator/consumer override for decode hardware. ABSENT is the normal case
|
|
9331
|
+
* and the one that matters: the broker then resolves the backend from the
|
|
9332
|
+
* DECODER ADDON's per-node `probedBestHwaccel` (see
|
|
9333
|
+
* `@camstack/types` `ffmpeg/hwaccel.ts`), which is the ranking known to work
|
|
9334
|
+
* on this hardware — never the raw kernel resolver's qsv-first order.
|
|
9335
|
+
*/
|
|
9336
|
+
decodeHwAccel: _enum([
|
|
9337
|
+
"auto",
|
|
9338
|
+
"none",
|
|
9339
|
+
"videotoolbox",
|
|
9340
|
+
"vaapi",
|
|
9341
|
+
"qsv",
|
|
9342
|
+
"cuda"
|
|
9343
|
+
]).optional(),
|
|
9344
|
+
/**
|
|
9345
|
+
* Host to embed in the returned restream `url`. The broker mints hub-local
|
|
9346
|
+
* `127.0.0.1` URLs; a consumer on another node passes a cluster-resolvable
|
|
9347
|
+
* host (`NodeTopologyService.reachableHostByNode`) so the returned URL is
|
|
9348
|
+
* dialable from there. Same contract as `getStreamWithCodec.hostname` —
|
|
9349
|
+
* `substituteRtspHost` rewrites only the dial address, never the restreamer.
|
|
9350
|
+
*/
|
|
9351
|
+
hostname: string().optional(),
|
|
9352
|
+
/** Attribution for the broker panel. Never part of the sharing key. */
|
|
9353
|
+
tag: string().optional()
|
|
9354
|
+
});
|
|
9355
|
+
var EgressTranscodeSchema = object({
|
|
9356
|
+
/** Dial-able RTSP url (host-substituted when `hostname` was supplied). */
|
|
9357
|
+
url: string(),
|
|
9358
|
+
/** Release handle. Refcounted — the child dies when the last holder releases. */
|
|
9359
|
+
pipelineKey: string(),
|
|
9360
|
+
videoCodec: _enum(["H264", "H265"]),
|
|
9361
|
+
resolution: object({
|
|
9362
|
+
width: number().int().positive(),
|
|
9363
|
+
height: number().int().positive()
|
|
9364
|
+
}),
|
|
9365
|
+
transcoded: boolean(),
|
|
9366
|
+
encoder: string(),
|
|
9367
|
+
/**
|
|
9368
|
+
* The decode backend the child ACTUALLY ran with — `null` for software.
|
|
9369
|
+
* Returned rather than assumed: a consumer that asked for hardware and got
|
|
9370
|
+
* software needs to be able to see that without reading the broker's logs.
|
|
9371
|
+
*/
|
|
9372
|
+
decodeHwAccel: string().nullable()
|
|
9373
|
+
});
|
|
9124
9374
|
method(object({
|
|
9125
9375
|
deviceId: number().int().nonnegative(),
|
|
9126
9376
|
camStreamId: string().min(1),
|
|
@@ -9230,6 +9480,15 @@ method(object({
|
|
|
9230
9480
|
}), {
|
|
9231
9481
|
kind: "mutation",
|
|
9232
9482
|
auth: "admin"
|
|
9483
|
+
}), method(EgressTranscodeRequestSchema, EgressTranscodeSchema, {
|
|
9484
|
+
kind: "mutation",
|
|
9485
|
+
auth: "admin"
|
|
9486
|
+
}), method(object({ pipelineKey: string() }), object({
|
|
9487
|
+
released: boolean(),
|
|
9488
|
+
refcount: number().int().nonnegative()
|
|
9489
|
+
}), {
|
|
9490
|
+
kind: "mutation",
|
|
9491
|
+
auth: "admin"
|
|
9233
9492
|
}), method(SubscribeAudioChunksInputSchema, SubscribeAudioChunksResultSchema, { kind: "mutation" }), method(object({
|
|
9234
9493
|
subscriptionId: string(),
|
|
9235
9494
|
maxCount: number().int().positive().default(8)
|
|
@@ -13842,12 +14101,13 @@ var NcConditionsSchema = object({
|
|
|
13842
14101
|
* source; otherwise the subject's source must equal it. Legacy records
|
|
13843
14102
|
* with no stamped source are treated as `pipeline`. The union spans both
|
|
13844
14103
|
* record kinds — object events carry `pipeline` | `onboard`, synthetic
|
|
13845
|
-
* tracks carry `sensor
|
|
14104
|
+
* tracks carry `sensor` (a linked device) or `audio` (a D62 audio marker).
|
|
13846
14105
|
*/
|
|
13847
14106
|
source: _enum([
|
|
13848
14107
|
"pipeline",
|
|
13849
14108
|
"onboard",
|
|
13850
14109
|
"sensor",
|
|
14110
|
+
"audio",
|
|
13851
14111
|
"any"
|
|
13852
14112
|
]).optional(),
|
|
13853
14113
|
/**
|
|
@@ -14401,6 +14661,10 @@ var NC_CONDITION_CATALOG = [
|
|
|
14401
14661
|
{
|
|
14402
14662
|
value: "sensor",
|
|
14403
14663
|
label: "Sensor"
|
|
14664
|
+
},
|
|
14665
|
+
{
|
|
14666
|
+
value: "audio",
|
|
14667
|
+
label: "Audio marker"
|
|
14404
14668
|
}
|
|
14405
14669
|
],
|
|
14406
14670
|
operator: "in",
|
|
@@ -14411,7 +14675,7 @@ var NC_CONDITION_CATALOG = [
|
|
|
14411
14675
|
"package-event"
|
|
14412
14676
|
],
|
|
14413
14677
|
phase: "P1",
|
|
14414
|
-
description: "pipeline / onboard / sensor; a record with no stamped source counts as pipeline."
|
|
14678
|
+
description: "pipeline / onboard / sensor / audio; a record with no stamped source counts as pipeline."
|
|
14415
14679
|
},
|
|
14416
14680
|
{
|
|
14417
14681
|
id: "deviceState",
|
|
@@ -14757,6 +15021,35 @@ var notificationRulesCapability = {
|
|
|
14757
15021
|
auth: "admin"
|
|
14758
15022
|
}),
|
|
14759
15023
|
/**
|
|
15024
|
+
* PERMANENT per-camera mute — the notifications half of the per-camera
|
|
15025
|
+
* function switch group ([D61](../../../../docs/decisions/adr-0067.md)).
|
|
15026
|
+
*
|
|
15027
|
+
* Deliberately NOT a snooze. A snooze is bounded at
|
|
15028
|
+
* {@link NC_SNOOZE_MAX_MINUTES} on purpose — "a snooze that could not
|
|
15029
|
+
* expire would be an outage the operator asked for once and forgot" — and
|
|
15030
|
+
* widening it to express "this camera never notifies" would destroy that
|
|
15031
|
+
* property for every snooze. A mute is the other thing: an explicit,
|
|
15032
|
+
* indefinite, admin-only decision, visible in the switch group next to the
|
|
15033
|
+
* other four, and reported on `CameraStatus.switchedOff` so a silent
|
|
15034
|
+
* camera never reads as a working one.
|
|
15035
|
+
*
|
|
15036
|
+
* Returned as ONE list rather than a per-camera query: the group's reader
|
|
15037
|
+
* needs every camera's state, and a per-camera fan-out over the viewer's
|
|
15038
|
+
* single WebSocket is N frames serialised on one socket.
|
|
15039
|
+
*/
|
|
15040
|
+
listDeviceMutes: method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }),
|
|
15041
|
+
/**
|
|
15042
|
+
* Mute or unmute one camera. Idempotent; an unmute of a camera that was
|
|
15043
|
+
* never muted succeeds.
|
|
15044
|
+
*/
|
|
15045
|
+
setDeviceMuted: method(object({
|
|
15046
|
+
deviceId: number().int(),
|
|
15047
|
+
muted: boolean()
|
|
15048
|
+
}), object({ success: literal(true) }), {
|
|
15049
|
+
kind: "mutation",
|
|
15050
|
+
auth: "admin"
|
|
15051
|
+
}),
|
|
15052
|
+
/**
|
|
14760
15053
|
* Dry-run a rule against recently persisted records (object events for
|
|
14761
15054
|
* `immediate`, closed tracks for `track-end`). Mutation kind only to
|
|
14762
15055
|
* carry the full rule object safely; no side effects.
|
|
@@ -15162,12 +15455,60 @@ var TrackAudioLabelSchema = object({
|
|
|
15162
15455
|
});
|
|
15163
15456
|
/**
|
|
15164
15457
|
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
15165
|
-
* detection+tracking pipeline.
|
|
15166
|
-
*
|
|
15167
|
-
*
|
|
15168
|
-
*
|
|
15458
|
+
* detection+tracking pipeline. Every OTHER value is a SYNTHETIC projection —
|
|
15459
|
+
* no positions, a single snapshot, and no bbox trajectory at all:
|
|
15460
|
+
*
|
|
15461
|
+
* - `sensor` — a linked sensor/control device state change.
|
|
15462
|
+
* - `audio` — an audio event on the camera itself that was anomalous for
|
|
15463
|
+
* THAT camera, loud, and heard while nothing visual was happening (D62).
|
|
15464
|
+
*
|
|
15465
|
+
* The spatial subsystems (tracker association, occupancy count, re-id /
|
|
15466
|
+
* embedding, resurrection) MUST skip every synthetic source. Test for that
|
|
15467
|
+
* with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
|
|
15468
|
+
* check silently readmits every source added after it was written.
|
|
15469
|
+
*/
|
|
15470
|
+
var TrackSourceSchema = _enum([
|
|
15471
|
+
"pipeline",
|
|
15472
|
+
"sensor",
|
|
15473
|
+
"audio"
|
|
15474
|
+
]);
|
|
15475
|
+
/**
|
|
15476
|
+
* Per-track OPERATOR flags — set by hand from the admin UI or the viewer, never
|
|
15477
|
+
* by the pipeline. Spread into `TrackSchema` and `KeyEventSchema` from one place
|
|
15478
|
+
* so the two surfaces cannot drift.
|
|
15479
|
+
*
|
|
15480
|
+
* **Absent ≠ false.** A track that has never been touched omits the field; an
|
|
15481
|
+
* explicitly un-flagged track carries `false`. Legacy rows written before the
|
|
15482
|
+
* columns existed read as absent, and a consumer that needs a boolean should say
|
|
15483
|
+
* `flag === true`, not `flag !== false`.
|
|
15484
|
+
*
|
|
15485
|
+
* What the flags DO is deliberately UNDEFINED at the time of writing: they are
|
|
15486
|
+
* operator curation, and the behaviour they drive will be specified separately.
|
|
15487
|
+
* In particular a `markForTrain` track is NOT pinned against retention — see
|
|
15488
|
+
* `docs/decisions/adr-0059.md` for why that is a store-level change, not a flag.
|
|
15489
|
+
*/
|
|
15490
|
+
var TrackFlagFields = {
|
|
15491
|
+
/** Operator marked this track as training material. */
|
|
15492
|
+
markForTrain: boolean().optional(),
|
|
15493
|
+
/** Operator marked this track for diagnostic attention. */
|
|
15494
|
+
debug: boolean().optional()
|
|
15495
|
+
};
|
|
15496
|
+
/**
|
|
15497
|
+
* The write half: a PARTIAL patch. An omitted key is left untouched, so setting
|
|
15498
|
+
* one flag can never clear the other — the toggles are independent and are
|
|
15499
|
+
* driven from three surfaces that do not know about each other.
|
|
15169
15500
|
*/
|
|
15170
|
-
var
|
|
15501
|
+
var TrackFlagsPatchSchema = object(TrackFlagFields);
|
|
15502
|
+
/**
|
|
15503
|
+
* The resolved flag state after a write. Both fields are REQUIRED here (absent
|
|
15504
|
+
* collapses to `false`) so a caller can drive a toggle's checked state off the
|
|
15505
|
+
* mutation result without a re-fetch.
|
|
15506
|
+
*/
|
|
15507
|
+
var TrackFlagsSchema = object({
|
|
15508
|
+
trackId: string(),
|
|
15509
|
+
markForTrain: boolean(),
|
|
15510
|
+
debug: boolean()
|
|
15511
|
+
});
|
|
15171
15512
|
var TrackSchema = object({
|
|
15172
15513
|
trackId: string(),
|
|
15173
15514
|
deviceId: number(),
|
|
@@ -15210,7 +15551,8 @@ var TrackSchema = object({
|
|
|
15210
15551
|
/** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
|
|
15211
15552
|
* Populated from the persisted envelope columns on historical reads;
|
|
15212
15553
|
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
15213
|
-
envelope: TrackEnvelopeSchema.optional()
|
|
15554
|
+
envelope: TrackEnvelopeSchema.optional(),
|
|
15555
|
+
...TrackFlagFields
|
|
15214
15556
|
});
|
|
15215
15557
|
var BaseEventFields = {
|
|
15216
15558
|
id: string(),
|
|
@@ -15423,7 +15765,8 @@ var KeyEventSchema = object({
|
|
|
15423
15765
|
/** Highest-confidence ObjectEvent id for the track (empty when none). */
|
|
15424
15766
|
bestEventId: string(),
|
|
15425
15767
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
15426
|
-
windowMs: number().optional()
|
|
15768
|
+
windowMs: number().optional(),
|
|
15769
|
+
...TrackFlagFields
|
|
15427
15770
|
});
|
|
15428
15771
|
object({
|
|
15429
15772
|
trackId: string(),
|
|
@@ -15508,16 +15851,32 @@ var RebuildObjectEmbeddingsInput = object({
|
|
|
15508
15851
|
deviceId: number().optional(),
|
|
15509
15852
|
since: number().optional(),
|
|
15510
15853
|
until: number().optional(),
|
|
15854
|
+
/** Stop after this many tracks; the result reports whether more remain. */
|
|
15855
|
+
maxTracks: number().int().positive().optional(),
|
|
15511
15856
|
/**
|
|
15512
|
-
*
|
|
15513
|
-
*
|
|
15514
|
-
*
|
|
15857
|
+
* Run every embedding on THIS node instead of round-robining the fleet.
|
|
15858
|
+
*
|
|
15859
|
+
* Named `executeOnNodeId` and not `nodeId` on purpose: an inline `nodeId`
|
|
15860
|
+
* field in cap args is read by `parent-unowned-call.ts` as a ROUTING PIN, so
|
|
15861
|
+
* calling it that would pin the rebuild REQUEST itself to that node — the
|
|
15862
|
+
* rebuild orchestration lives on the hub, and only the per-track step runs
|
|
15863
|
+
* remotely. This field is data; the per-track pin is applied inside.
|
|
15864
|
+
*
|
|
15865
|
+
* Absent ⇒ round-robin over every online node whose runner can serve the
|
|
15866
|
+
* pinned model.
|
|
15515
15867
|
*/
|
|
15516
|
-
|
|
15517
|
-
/**
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15868
|
+
executeOnNodeId: string().optional(),
|
|
15869
|
+
/**
|
|
15870
|
+
* Milliseconds to wait between tracks; omit for the built-in default, `0` to
|
|
15871
|
+
* run flat out.
|
|
15872
|
+
*
|
|
15873
|
+
* A rebuild is bulk maintenance on hub-main's single thread. Measured
|
|
15874
|
+
* 2026-08-06, an unpaced pass held that thread busy 82.2 s out of 120 and
|
|
15875
|
+
* pushed `nodes.topology` from 0.25 s to 26 s for 43 minutes. The value in
|
|
15876
|
+
* force is logged at start and finish so a deliberately slow pass reads
|
|
15877
|
+
* differently from a stalled one.
|
|
15878
|
+
*/
|
|
15879
|
+
pacingMs: number().int().nonnegative().optional()
|
|
15521
15880
|
});
|
|
15522
15881
|
/**
|
|
15523
15882
|
* Result of emptying the CLIP index.
|
|
@@ -15550,6 +15909,24 @@ var RebuildStatusSchema = object({
|
|
|
15550
15909
|
missingKeyFrame: number(),
|
|
15551
15910
|
/** Tracks with no usable detection box. */
|
|
15552
15911
|
missingBbox: number(),
|
|
15912
|
+
/**
|
|
15913
|
+
* Tracks an executing node REFUSED rather than broke on — an unreadable key
|
|
15914
|
+
* frame, a step that threw. Separate from `failed` because the remedy is
|
|
15915
|
+
* different, and because a whole camera silently contributing zero vectors
|
|
15916
|
+
* is the shape of failure a rebuild must never hide.
|
|
15917
|
+
*/
|
|
15918
|
+
notRunnable: number(),
|
|
15919
|
+
/**
|
|
15920
|
+
* The pass stopped because NO node could serve the pinned model.
|
|
15921
|
+
*
|
|
15922
|
+
* Distinct from `notRunnable` on purpose: that one says "this track was
|
|
15923
|
+
* refused", this one says "the cluster cannot do this work at all" — every
|
|
15924
|
+
* candidate node either lacks the `clip-embedding` step, lacks a build of the
|
|
15925
|
+
* pinned model for its engine format, or dropped out. The remedy is a model /
|
|
15926
|
+
* engine change, not a per-camera one. Non-zero here always comes with
|
|
15927
|
+
* `complete: false`.
|
|
15928
|
+
*/
|
|
15929
|
+
noCapableNode: number(),
|
|
15553
15930
|
failed: number(),
|
|
15554
15931
|
/** Set once a pass ends: true only when EVERYTHING was covered. */
|
|
15555
15932
|
complete: boolean().nullable(),
|
|
@@ -15739,6 +16116,31 @@ var pipelineAnalyticsCapability = {
|
|
|
15739
16116
|
auth: "admin"
|
|
15740
16117
|
}),
|
|
15741
16118
|
/**
|
|
16119
|
+
* Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
|
|
16120
|
+
* The patch is PARTIAL — an omitted key is left untouched — because the
|
|
16121
|
+
* three surfaces that write it (admin Events grid, viewer track detail,
|
|
16122
|
+
* viewer cluster detail) each own one toggle and must not clobber the other.
|
|
16123
|
+
*
|
|
16124
|
+
* Writes the track ROW: `markForTrain`/`debug` are per-TRACK state, so they
|
|
16125
|
+
* live where `label` and `importance` live, not in any per-device settings
|
|
16126
|
+
* store. Updates the in-RAM active track too, so a flag set on a live track
|
|
16127
|
+
* survives its expiry-time persist.
|
|
16128
|
+
*
|
|
16129
|
+
* `auth: 'protected'` (the default), NOT `admin`: the viewer is an
|
|
16130
|
+
* authenticated non-admin surface and two of the three call sites are
|
|
16131
|
+
* there. Revisit if a flag ever gains an effect that costs storage —
|
|
16132
|
+
* `deleteTracks` next door is admin for exactly that reason.
|
|
16133
|
+
*
|
|
16134
|
+
* Returns the RESOLVED state of both flags (absent → `false`) so a caller
|
|
16135
|
+
* can drive its toggle without a re-fetch. Rejects an unknown track.
|
|
16136
|
+
*/
|
|
16137
|
+
setTrackFlags: method(object({
|
|
16138
|
+
/** Log/audit scope only — the trackId is globally unique on its own. */
|
|
16139
|
+
deviceId: number(),
|
|
16140
|
+
trackId: string(),
|
|
16141
|
+
flags: TrackFlagsPatchSchema
|
|
16142
|
+
}), TrackFlagsSchema, { kind: "mutation" }),
|
|
16143
|
+
/**
|
|
15742
16144
|
* Durable event-store footprint for the management UI: event rows
|
|
15743
16145
|
* (motion + object + audio) counted per camera + total, plus the
|
|
15744
16146
|
* event-owned media bytes on disk per camera + total. Stat/count-based,
|
|
@@ -16465,6 +16867,53 @@ var DetailResultSchema = object({
|
|
|
16465
16867
|
nativeFaceShortSidePx: number().optional()
|
|
16466
16868
|
});
|
|
16467
16869
|
/**
|
|
16870
|
+
* Why an executing node REFUSED a stateless step run (`runStatelessStep`).
|
|
16871
|
+
*
|
|
16872
|
+
* A refusal is a first-class answer, not an error, because the caller's next
|
|
16873
|
+
* move depends on WHICH one it is — and because "the pass produced nothing"
|
|
16874
|
+
* must never be reachable without a named, counted cause. The two tiers:
|
|
16875
|
+
*
|
|
16876
|
+
* - **node-level** (`unknown-step`, `model-not-servable`) — this node can
|
|
16877
|
+
* never serve this (step, model) pair. The caller drops it from its rotation
|
|
16878
|
+
* and retries the same work elsewhere; nothing about the work changes.
|
|
16879
|
+
* - **work-level** (`unreadable-frame`, `execution-failed`) — this node is
|
|
16880
|
+
* fine, this one request is not. Retrying it on another node would only
|
|
16881
|
+
* spread the same failure.
|
|
16882
|
+
*/
|
|
16883
|
+
var StatelessStepRefusalSchema = _enum([
|
|
16884
|
+
"unknown-step",
|
|
16885
|
+
"model-not-servable",
|
|
16886
|
+
"unreadable-frame",
|
|
16887
|
+
"execution-failed"
|
|
16888
|
+
]);
|
|
16889
|
+
/**
|
|
16890
|
+
* Answer to `runStatelessStep` — a discriminated union rather than a nullable
|
|
16891
|
+
* result, because `null` is exactly what made the camera-bound detail path
|
|
16892
|
+
* unable to tell "refused" from "never asked".
|
|
16893
|
+
*/
|
|
16894
|
+
var RunStatelessStepResultSchema = discriminatedUnion("kind", [object({
|
|
16895
|
+
kind: literal("ran"),
|
|
16896
|
+
/** The node that actually executed it — the pin, echoed back for the log. */
|
|
16897
|
+
nodeId: string(),
|
|
16898
|
+
/**
|
|
16899
|
+
* The model the step ran with.
|
|
16900
|
+
*
|
|
16901
|
+
* The node verified this exact id has a build for the format it dispatched
|
|
16902
|
+
* on BEFORE running, so the executor's format resolution returns it
|
|
16903
|
+
* unchanged. A caller that pinned a model must compare this field and
|
|
16904
|
+
* treat a mismatch as a refusal — the whole point of the pin is that a
|
|
16905
|
+
* pass writes one feature space.
|
|
16906
|
+
*/
|
|
16907
|
+
modelId: string(),
|
|
16908
|
+
details: array(DetailResultSchema)
|
|
16909
|
+
}), object({
|
|
16910
|
+
kind: literal("refused"),
|
|
16911
|
+
nodeId: string(),
|
|
16912
|
+
reason: StatelessStepRefusalSchema,
|
|
16913
|
+
/** Human-readable specifics — the format tried, the formats shipped, etc. */
|
|
16914
|
+
detail: string()
|
|
16915
|
+
})]);
|
|
16916
|
+
/**
|
|
16468
16917
|
* Per-camera tunable ranges + defaults. Single source of truth used
|
|
16469
16918
|
* by both the Zod data schema (validation + default fallback) and
|
|
16470
16919
|
* the device settings UI (slider min/max/step). Touch one place and
|
|
@@ -16800,10 +17249,46 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
|
|
|
16800
17249
|
}), NativeCropResultSchema.nullable()), method(object({
|
|
16801
17250
|
deviceId: number(),
|
|
16802
17251
|
frameHandle: FrameHandleSchema.optional(),
|
|
17252
|
+
/**
|
|
17253
|
+
* FULL FRAME (base64 JPEG). The runner derives the crop rectangle from
|
|
17254
|
+
* `parent.bbox` with the cluster crop convention and cuts it itself —
|
|
17255
|
+
* do NOT pre-crop for this field, that is what `cropJpeg` is.
|
|
17256
|
+
*/
|
|
17257
|
+
frameJpeg: string().optional(),
|
|
17258
|
+
/**
|
|
17259
|
+
* PRE-CUT tile (base64 JPEG), used verbatim — NO padding is applied.
|
|
17260
|
+
* The fallback when the lease/session backing the frame is gone and the
|
|
17261
|
+
* caller already holds a crop.
|
|
17262
|
+
*/
|
|
16803
17263
|
cropJpeg: string().optional(),
|
|
16804
17264
|
parent: DetailParentSchema,
|
|
16805
17265
|
steps: array(string()).optional()
|
|
16806
|
-
}), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" })
|
|
17266
|
+
}), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }), method(object({
|
|
17267
|
+
/** Catalog step id, e.g. `clip-embedding`. */
|
|
17268
|
+
stepId: string(),
|
|
17269
|
+
/**
|
|
17270
|
+
* REQUIRED model pin. The node runs this exact model or refuses with
|
|
17271
|
+
* `model-not-servable` — it never substitutes a format default, because
|
|
17272
|
+
* a fleet pass that round-robins across nodes would then fill one index
|
|
17273
|
+
* from several encoders.
|
|
17274
|
+
*/
|
|
17275
|
+
modelId: string(),
|
|
17276
|
+
/** FULL FRAME, base64 JPEG. The runner cuts — do NOT pre-crop. */
|
|
17277
|
+
frameJpeg: string(),
|
|
17278
|
+
/**
|
|
17279
|
+
* The subject box, NORMALISED [0,1] against `frameJpeg`. Normalised on
|
|
17280
|
+
* purpose: the caller stores boxes against a downscaled analysis frame
|
|
17281
|
+
* while the stored key frame is native-resolution, and the only side
|
|
17282
|
+
* that reliably knows the image's pixel dimensions is the side that
|
|
17283
|
+
* decodes it. Denormalising here removes a second reader of the
|
|
17284
|
+
* dimensions and the class of mismatch that comes with it.
|
|
17285
|
+
*/
|
|
17286
|
+
bbox: NativeCropBboxSchema,
|
|
17287
|
+
/** Parent class of the subject (`person`, `vehicle`, …) — carried into the result. */
|
|
17288
|
+
className: string(),
|
|
17289
|
+
/** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
|
|
17290
|
+
sourceDeviceId: number()
|
|
17291
|
+
}), RunStatelessStepResultSchema, { kind: "mutation" });
|
|
16807
17292
|
var CameraPipelineConfigSchema = object({
|
|
16808
17293
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16809
17294
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -17101,6 +17586,20 @@ var CameraStatusSchema = object({
|
|
|
17101
17586
|
detection: CameraDetectionStatusSchema.nullable(),
|
|
17102
17587
|
audio: CameraAudioStatusSchema.nullable(),
|
|
17103
17588
|
recording: CameraRecordingStatusSchema.nullable(),
|
|
17589
|
+
/**
|
|
17590
|
+
* Per-camera function switches an OPERATOR has turned off
|
|
17591
|
+
* ([D61](../../../../docs/decisions/adr-0067.md)).
|
|
17592
|
+
*
|
|
17593
|
+
* This is the difference between DISABLED and BROKEN. A camera whose
|
|
17594
|
+
* `detection` block reports zero fps and whose `switchedOff` contains
|
|
17595
|
+
* `'object-detection'` was switched off by a person; the same camera with an
|
|
17596
|
+
* empty list is failing. Every status surface must render the two
|
|
17597
|
+
* differently — a quiet camera that looks identical to a dead one is the
|
|
17598
|
+
* silence-reads-as-never-happened trap this repo keeps paying for.
|
|
17599
|
+
*
|
|
17600
|
+
* Empty when nothing is off. Never contains a switch no provider offers.
|
|
17601
|
+
*/
|
|
17602
|
+
switchedOff: array(CameraSwitchIdSchema).readonly(),
|
|
17104
17603
|
/** Unix timestamp (ms) when this snapshot was composed server-side. */
|
|
17105
17604
|
fetchedAt: number()
|
|
17106
17605
|
});
|
|
@@ -17269,7 +17768,14 @@ method(object({
|
|
|
17269
17768
|
}), method(object({
|
|
17270
17769
|
deviceId: number(),
|
|
17271
17770
|
agentNodeId: string().optional()
|
|
17272
|
-
}), CameraPipelineConfigSchema), method(object({ deviceId: number() }),
|
|
17771
|
+
}), CameraPipelineConfigSchema), method(object({ deviceId: number() }), CameraSwitchGroupSchema), method(object({
|
|
17772
|
+
deviceId: number(),
|
|
17773
|
+
switchId: CameraSwitchIdSchema,
|
|
17774
|
+
enabled: boolean()
|
|
17775
|
+
}), CameraSwitchGroupSchema, {
|
|
17776
|
+
kind: "mutation",
|
|
17777
|
+
auth: "admin"
|
|
17778
|
+
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
|
|
17273
17779
|
name: string(),
|
|
17274
17780
|
description: string().optional(),
|
|
17275
17781
|
config: CameraPipelineConfigSchema
|
|
@@ -28843,6 +29349,12 @@ Object.freeze({
|
|
|
28843
29349
|
addonId: null,
|
|
28844
29350
|
access: "view"
|
|
28845
29351
|
},
|
|
29352
|
+
"notificationRules.listDeviceMutes": {
|
|
29353
|
+
capName: "notification-rules",
|
|
29354
|
+
capScope: "system",
|
|
29355
|
+
addonId: null,
|
|
29356
|
+
access: "view"
|
|
29357
|
+
},
|
|
28846
29358
|
"notificationRules.listRules": {
|
|
28847
29359
|
capName: "notification-rules",
|
|
28848
29360
|
capScope: "system",
|
|
@@ -28861,6 +29373,12 @@ Object.freeze({
|
|
|
28861
29373
|
addonId: null,
|
|
28862
29374
|
access: "create"
|
|
28863
29375
|
},
|
|
29376
|
+
"notificationRules.setDeviceMuted": {
|
|
29377
|
+
capName: "notification-rules",
|
|
29378
|
+
capScope: "system",
|
|
29379
|
+
addonId: null,
|
|
29380
|
+
access: "create"
|
|
29381
|
+
},
|
|
28864
29382
|
"notificationRules.setRuleEnabled": {
|
|
28865
29383
|
capName: "notification-rules",
|
|
28866
29384
|
capScope: "system",
|
|
@@ -29137,6 +29655,12 @@ Object.freeze({
|
|
|
29137
29655
|
addonId: null,
|
|
29138
29656
|
access: "view"
|
|
29139
29657
|
},
|
|
29658
|
+
"pipelineAnalytics.setTrackFlags": {
|
|
29659
|
+
capName: "pipeline-analytics",
|
|
29660
|
+
capScope: "device",
|
|
29661
|
+
addonId: null,
|
|
29662
|
+
access: "create"
|
|
29663
|
+
},
|
|
29140
29664
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
29141
29665
|
capName: "pipeline-analytics",
|
|
29142
29666
|
capScope: "device",
|
|
@@ -29443,6 +29967,12 @@ Object.freeze({
|
|
|
29443
29967
|
addonId: null,
|
|
29444
29968
|
access: "view"
|
|
29445
29969
|
},
|
|
29970
|
+
"pipelineOrchestrator.getCameraSwitches": {
|
|
29971
|
+
capName: "pipeline-orchestrator",
|
|
29972
|
+
capScope: "system",
|
|
29973
|
+
addonId: null,
|
|
29974
|
+
access: "view"
|
|
29975
|
+
},
|
|
29446
29976
|
"pipelineOrchestrator.getCapabilityBindings": {
|
|
29447
29977
|
capName: "pipeline-orchestrator",
|
|
29448
29978
|
capScope: "system",
|
|
@@ -29575,6 +30105,12 @@ Object.freeze({
|
|
|
29575
30105
|
addonId: null,
|
|
29576
30106
|
access: "create"
|
|
29577
30107
|
},
|
|
30108
|
+
"pipelineOrchestrator.setCameraSwitch": {
|
|
30109
|
+
capName: "pipeline-orchestrator",
|
|
30110
|
+
capScope: "system",
|
|
30111
|
+
addonId: null,
|
|
30112
|
+
access: "create"
|
|
30113
|
+
},
|
|
29578
30114
|
"pipelineOrchestrator.setCapabilityBinding": {
|
|
29579
30115
|
capName: "pipeline-orchestrator",
|
|
29580
30116
|
capScope: "system",
|
|
@@ -29665,6 +30201,12 @@ Object.freeze({
|
|
|
29665
30201
|
addonId: null,
|
|
29666
30202
|
access: "create"
|
|
29667
30203
|
},
|
|
30204
|
+
"pipelineRunner.runStatelessStep": {
|
|
30205
|
+
capName: "pipeline-runner",
|
|
30206
|
+
capScope: "system",
|
|
30207
|
+
addonId: null,
|
|
30208
|
+
access: "create"
|
|
30209
|
+
},
|
|
29668
30210
|
"plateGallery.assignPlate": {
|
|
29669
30211
|
capName: "plate-gallery",
|
|
29670
30212
|
capScope: "system",
|
|
@@ -30481,6 +31023,12 @@ Object.freeze({
|
|
|
30481
31023
|
addonId: null,
|
|
30482
31024
|
access: "create"
|
|
30483
31025
|
},
|
|
31026
|
+
"streamBroker.acquireEgressTranscode": {
|
|
31027
|
+
capName: "stream-broker",
|
|
31028
|
+
capScope: "system",
|
|
31029
|
+
addonId: null,
|
|
31030
|
+
access: "create"
|
|
31031
|
+
},
|
|
30484
31032
|
"streamBroker.assignProfile": {
|
|
30485
31033
|
capName: "stream-broker",
|
|
30486
31034
|
capScope: "system",
|
|
@@ -30589,6 +31137,12 @@ Object.freeze({
|
|
|
30589
31137
|
addonId: null,
|
|
30590
31138
|
access: "create"
|
|
30591
31139
|
},
|
|
31140
|
+
"streamBroker.releaseEgressTranscode": {
|
|
31141
|
+
capName: "stream-broker",
|
|
31142
|
+
capScope: "system",
|
|
31143
|
+
addonId: null,
|
|
31144
|
+
access: "create"
|
|
31145
|
+
},
|
|
30592
31146
|
"streamBroker.releaseStreamWithCodec": {
|
|
30593
31147
|
capName: "stream-broker",
|
|
30594
31148
|
capScope: "system",
|
|
@@ -31391,6 +31945,34 @@ function encodeVectorBase64(vector) {
|
|
|
31391
31945
|
for (let i = 0; i < floats.length; i += 1) view.setFloat32(i * 4, floats[i] ?? 0, true);
|
|
31392
31946
|
return Buffer.from(bytes).toString("base64");
|
|
31393
31947
|
}
|
|
31948
|
+
/** Vector length implied by a base64 payload, without decoding it. */
|
|
31949
|
+
function vectorDimFromBase64(encoded) {
|
|
31950
|
+
return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
|
|
31951
|
+
}
|
|
31952
|
+
object({
|
|
31953
|
+
/**
|
|
31954
|
+
* Fraction of the box's own size added on EACH side before cutting.
|
|
31955
|
+
*
|
|
31956
|
+
* CLIP is trained on natural images WITH surroundings; a pixel-tight crop
|
|
31957
|
+
* removes exactly the context it is strongest on (a dog cut to its outline
|
|
31958
|
+
* is a dark blob). The right value is an empirical question, which is why it
|
|
31959
|
+
* is a setting: 0 / 0.15 / 0.2 / 0.5 are the interesting points.
|
|
31960
|
+
*/
|
|
31961
|
+
paddingRatio: number().min(0).max(4),
|
|
31962
|
+
/**
|
|
31963
|
+
* Square the window (in PIXELS) before cutting.
|
|
31964
|
+
*
|
|
31965
|
+
* CLIP's input is square, so a tall bbox resized straight to NxN is squashed
|
|
31966
|
+
* — a standing person becomes a shape the model never saw. Squaring costs
|
|
31967
|
+
* extra background, which is context the model wants anyway. Off by default
|
|
31968
|
+
* because the live path has never squared and the stored index reflects that.
|
|
31969
|
+
*/
|
|
31970
|
+
square: boolean()
|
|
31971
|
+
});
|
|
31972
|
+
({
|
|
31973
|
+
paddingRatio: .15,
|
|
31974
|
+
square: false
|
|
31975
|
+
}).paddingRatio;
|
|
31394
31976
|
//#endregion
|
|
31395
31977
|
Object.defineProperty(exports, "BaseAddon", {
|
|
31396
31978
|
enumerable: true,
|
|
@@ -31518,6 +32100,12 @@ Object.defineProperty(exports, "TimelapseRuleSchema", {
|
|
|
31518
32100
|
return TimelapseRuleSchema;
|
|
31519
32101
|
}
|
|
31520
32102
|
});
|
|
32103
|
+
Object.defineProperty(exports, "TrackSourceSchema", {
|
|
32104
|
+
enumerable: true,
|
|
32105
|
+
get: function() {
|
|
32106
|
+
return TrackSourceSchema;
|
|
32107
|
+
}
|
|
32108
|
+
});
|
|
31521
32109
|
Object.defineProperty(exports, "__toESM", {
|
|
31522
32110
|
enumerable: true,
|
|
31523
32111
|
get: function() {
|
|
@@ -31692,6 +32280,12 @@ Object.defineProperty(exports, "record", {
|
|
|
31692
32280
|
return record;
|
|
31693
32281
|
}
|
|
31694
32282
|
});
|
|
32283
|
+
Object.defineProperty(exports, "sleep", {
|
|
32284
|
+
enumerable: true,
|
|
32285
|
+
get: function() {
|
|
32286
|
+
return sleep;
|
|
32287
|
+
}
|
|
32288
|
+
});
|
|
31695
32289
|
Object.defineProperty(exports, "string", {
|
|
31696
32290
|
enumerable: true,
|
|
31697
32291
|
get: function() {
|
|
@@ -31710,6 +32304,12 @@ Object.defineProperty(exports, "unknown", {
|
|
|
31710
32304
|
return unknown;
|
|
31711
32305
|
}
|
|
31712
32306
|
});
|
|
32307
|
+
Object.defineProperty(exports, "vectorDimFromBase64", {
|
|
32308
|
+
enumerable: true,
|
|
32309
|
+
get: function() {
|
|
32310
|
+
return vectorDimFromBase64;
|
|
32311
|
+
}
|
|
32312
|
+
});
|
|
31713
32313
|
Object.defineProperty(exports, "videoclipsCapability", {
|
|
31714
32314
|
enumerable: true,
|
|
31715
32315
|
get: function() {
|