@camstack/system 1.2.56 → 1.2.58

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.
Files changed (64) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +2 -2
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +2 -2
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +2 -2
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +2 -2
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  16. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  17. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  18. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  20. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  21. package/dist/builtins/hub-forwarder/index.js +1 -1
  22. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  24. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  26. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  27. package/dist/builtins/local-network/local-network.addon.js +1 -1
  28. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  29. package/dist/builtins/loki-logging/index.js +1 -1
  30. package/dist/builtins/loki-logging/index.mjs +1 -1
  31. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  33. package/dist/builtins/platform-probe/index.js +1 -1
  34. package/dist/builtins/platform-probe/index.mjs +1 -1
  35. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  37. package/dist/builtins/snapshot/index.js +1 -1
  38. package/dist/builtins/snapshot/index.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +2 -2
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +2 -2
  41. package/dist/builtins/sqlite-storage/index.d.ts +3 -0
  42. package/dist/builtins/sqlite-storage/index.js +8 -0
  43. package/dist/builtins/sqlite-storage/index.mjs +2 -2
  44. package/dist/builtins/sqlite-storage/sqlite-pragmas.d.ts +85 -0
  45. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +1 -0
  46. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +304 -1
  47. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +297 -2
  48. package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +113 -0
  49. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  51. package/dist/builtins/system-config/system-config.addon.js +1 -1
  52. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  53. package/dist/builtins/winston-logging/index.js +1 -1
  54. package/dist/builtins/winston-logging/index.mjs +1 -1
  55. package/dist/{dist-CblJsHb-.js → dist-Chl2MvMd.js} +692 -25
  56. package/dist/{dist-BOpRqInW.mjs → dist-UrXyJ9Zm.mjs} +692 -25
  57. package/dist/index.js +4 -4
  58. package/dist/index.mjs +5 -5
  59. package/dist/kernel/transport/frame-codec.d.ts +43 -2
  60. package/dist/{manifest-python-deps-Ck4-9K9m.mjs → manifest-python-deps-CX5tGRqf.mjs} +95 -10
  61. package/dist/{manifest-python-deps-BqE5j0-O.js → manifest-python-deps-d4acYXVV.js} +95 -10
  62. package/package.json +1 -1
  63. package/dist/{model-download-service-hf0ookyy.js → model-download-service-Cpc6SWzV.js} +1 -1
  64. package/dist/{model-download-service-Cp9f4dk6.mjs → model-download-service-D8B-4ktF.mjs} +1 -1
@@ -3028,6 +3028,14 @@ var VideoEncodeSchema = zod.z.object({
3028
3028
  "main",
3029
3029
  "high"
3030
3030
  ]).optional(),
3031
+ /**
3032
+ * `-level`, e.g. `'3.1'`. A consumer that ADVERTISES a level in its SDP
3033
+ * (`profile-level-id=42e01f` is Baseline 3.1) must constrain the encoder to
3034
+ * it, or it ships a stream that does not match its own advertisement — the
3035
+ * defect class that kept HomeKit black for a year and that Alexa carried
3036
+ * silently. Optional because a browser negotiates the level itself.
3037
+ */
3038
+ level: zod.z.string().optional(),
3031
3039
  width: zod.z.number().int().positive().optional(),
3032
3040
  height: zod.z.number().int().positive().optional(),
3033
3041
  fps: zod.z.number().positive().optional(),
@@ -3078,6 +3086,29 @@ var EncodeProfileSchema = zod.z.object({
3078
3086
  outputArgs: zod.z.array(zod.z.string()).optional()
3079
3087
  });
3080
3088
  /**
3089
+ * The shape every live egress starts from: H.264 Baseline 3.1 at 720p25.
3090
+ * Baseline because it is the one profile every consumer in this repo decodes
3091
+ * (Echo, iOS, an old browser); 3.1 because that is what the SDPs advertise.
3092
+ */
3093
+ var BASE_LIVE_EGRESS_PROFILE = {
3094
+ video: {
3095
+ codec: "h264",
3096
+ profile: "baseline",
3097
+ level: "3.1",
3098
+ width: 1280,
3099
+ height: 720,
3100
+ fps: 25,
3101
+ bitrateKbps: 2500,
3102
+ gopFrames: 25,
3103
+ bf: 0,
3104
+ preset: "veryfast",
3105
+ tune: "zerolatency"
3106
+ },
3107
+ audio: "passthrough"
3108
+ };
3109
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
3110
+ ({ ...BASE_LIVE_EGRESS_PROFILE });
3111
+ /**
3081
3112
  * Deep wiring healthcheck — snapshot of active reachability probes across
3082
3113
  * every declared capability + widget of every installed plugin, on every
3083
3114
  * node. Produced by the backend `WiringHealthService` and surfaced via
@@ -3126,6 +3157,105 @@ zod.z.object({
3126
3157
  unreachable: zod.z.number()
3127
3158
  })
3128
3159
  });
3160
+ /**
3161
+ * Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
3162
+ * pipeline functions an operator thinks in terms of.
3163
+ *
3164
+ * ## This file adds no state
3165
+ *
3166
+ * Every switch here is a VIEW onto an authority that already existed
3167
+ * ([D61](../../../../docs/decisions/adr-0062.md)). The whole point of the
3168
+ * group is that there is exactly one place each function is turned off, and
3169
+ * the group routes to it:
3170
+ *
3171
+ * | Switch | Authority | Proven "off stops the work" gate |
3172
+ * | --- | --- | --- |
3173
+ * | `stream-broker` | `deviceManager.setDisabled` | `StreamBrokerManager.reconcileAllCatalogs` releases the brokers; `ensureBroker` refuses re-creation |
3174
+ * | `object-detection` | `deviceManager.setWrapperActive('detection-pipeline')` | `PipelineSettingsStore.resolvePipelineForDevice` returns `{ steps: [], audio: null }` |
3175
+ * | `audio-analysis` | `deviceManager.setWrapperActive('audio-analysis')` | `AudioSubscriptionController.subscribeAudioStream` returns `null` before opening the stream |
3176
+ * | `recording` | `recording.setDeviceConfig` → `RecordingConfig.enabled` | `band-decision.shouldRecord` returns false; the controller detaches the device |
3177
+ * | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
3178
+ *
3179
+ * The wrapper-binding pair is not a new idea: `legacy-migrations.ts` already
3180
+ * migrated the legacy `audioEnabled` / `pipelineEnabled` /
3181
+ * `motionDetectionEnabled` booleans ONTO `setWrapperActive`. The group is the
3182
+ * surface that decision never got.
3183
+ *
3184
+ * ## Two rules that are load-bearing
3185
+ *
3186
+ * - **Recording's switch is `enabled`, never the bands.** `bands` is the only
3187
+ * authored intent and `mode` is derived from it (`deriveRecordingMode`).
3188
+ * Expressing "off" by clearing bands destroys the operator's schedule and
3189
+ * turning the camera back on would then silently record nothing.
3190
+ * - **A switch that is off must be reported as off**, not merely produce
3191
+ * nothing. {@link CameraSwitch.enabled} is what a status surface renders as
3192
+ * "disabled by an operator" instead of "broken" — see
3193
+ * `CameraStatus.switchedOff`.
3194
+ */
3195
+ /**
3196
+ * The five functions the operator named (2026-08-05). Deliberately NOT one id
3197
+ * per pipeline step: face recognition and plate/LPR are per-step toggles on
3198
+ * `pipelineOrchestrator.setCameraStepToggle` and belong in the pipeline
3199
+ * editor, not in a five-button safety group.
3200
+ */
3201
+ var CameraSwitchIdSchema = zod.z.enum([
3202
+ "stream-broker",
3203
+ "object-detection",
3204
+ "audio-analysis",
3205
+ "recording",
3206
+ "notifications"
3207
+ ]);
3208
+ /**
3209
+ * WHERE the switch's state actually lives. A discriminated union rather than a
3210
+ * string so both the writer (the orchestrator's `setCameraSwitch`) and any
3211
+ * reader can exhaustively narrow — and so "the group added a parallel map" is
3212
+ * a compile error rather than a review comment.
3213
+ */
3214
+ var CameraSwitchAuthoritySchema = zod.z.discriminatedUnion("kind", [
3215
+ zod.z.object({ kind: zod.z.literal("device-disabled") }),
3216
+ zod.z.object({
3217
+ kind: zod.z.literal("wrapper-binding"),
3218
+ capName: zod.z.string()
3219
+ }),
3220
+ zod.z.object({ kind: zod.z.literal("recording-config") }),
3221
+ zod.z.object({ kind: zod.z.literal("notification-mute") })
3222
+ ]);
3223
+ /**
3224
+ * Why a switch is not offered for this camera. Rendered instead of the
3225
+ * control, never as a dead control — an absent function and a broken one must
3226
+ * not look the same.
3227
+ */
3228
+ var CameraSwitchUnavailableReasonSchema = zod.z.enum(["no-provider", "source-unreachable"]);
3229
+ /**
3230
+ * One switch, resolved for one camera.
3231
+ *
3232
+ * `label` and `costWhenOff` travel ON THE WIRE rather than being looked up
3233
+ * client-side: the viewer is a separate repository that does not import
3234
+ * `@camstack/types`, and a cost line duplicated in two clients is a cost line
3235
+ * that will disagree with itself. Five rows per camera is nothing.
3236
+ */
3237
+ var CameraSwitchSchema = zod.z.object({
3238
+ id: CameraSwitchIdSchema,
3239
+ label: zod.z.string(),
3240
+ /**
3241
+ * What the operator LOSES while this is off, in one sentence. Required, not
3242
+ * optional: a switch that cannot say what it costs should not ship.
3243
+ */
3244
+ costWhenOff: zod.z.string(),
3245
+ /** False = do not render a control. `unavailableReason` says why. */
3246
+ available: zod.z.boolean(),
3247
+ unavailableReason: CameraSwitchUnavailableReasonSchema.optional(),
3248
+ /** Current state. Meaningless when `available` is false — read it as `true`. */
3249
+ enabled: zod.z.boolean(),
3250
+ authority: CameraSwitchAuthoritySchema
3251
+ });
3252
+ /** The whole group for one camera. */
3253
+ var CameraSwitchGroupSchema = zod.z.object({
3254
+ deviceId: zod.z.number().int(),
3255
+ switches: zod.z.array(CameraSwitchSchema).readonly(),
3256
+ /** Unix ms when the group was composed server-side. */
3257
+ fetchedAt: zod.z.number()
3258
+ });
3129
3259
  /** Friendly display labels for stream quality IDs. */
3130
3260
  var STREAM_QUALITY_LABELS = {
3131
3261
  high: "High",
@@ -3175,14 +3305,16 @@ var OpsLogOpSchema = zod.z.enum([
3175
3305
  "manual-delete",
3176
3306
  "rescan",
3177
3307
  "retention-run",
3178
- "relocate"
3308
+ "relocate",
3309
+ "orphan-audit"
3179
3310
  ]);
3180
3311
  /** Why the operation ran. */
3181
3312
  var OpsLogReasonSchema = zod.z.enum([
3182
3313
  "retention",
3183
3314
  "quota",
3184
3315
  "manual",
3185
- "operator"
3316
+ "operator",
3317
+ "maintenance"
3186
3318
  ]);
3187
3319
  /** One audit row, shared verbatim by both domains. */
3188
3320
  var OpsLogEntrySchema = zod.z.object({
@@ -5409,6 +5541,100 @@ var RtpSourceSchema = zod.z.object({
5409
5541
  encoder: zod.z.string(),
5410
5542
  pipelineKey: zod.z.string()
5411
5543
  });
5544
+ /**
5545
+ * The encode request — **structured and serialisable, with NO raw-flag escape
5546
+ * hatch.** This is deliberate and it is the one lesson taken from
5547
+ * `getStreamWithCodec`: that method's `outputArgs: string[]` is simultaneously
5548
+ * its extensibility mechanism AND part of `pipelineKeyFor`'s sharing key, so
5549
+ * adding a flag silently forks the shared child, and two consumers that mean
5550
+ * the same thing but spell it differently never share. Here every knob is a
5551
+ * NAMED field: a new requirement becomes a schema field (and a codegen run),
5552
+ * never an opaque array.
5553
+ *
5554
+ * `inputArgs` / `outputArgs` are omitted from the profile for the same reason.
5555
+ * The operator-facing derived-stream transform editor still has them — that is
5556
+ * a different surface (`publishCameraStream({ kind: 'derived' })`) with a
5557
+ * different purpose (reshaping a badly-behaved SOURCE), and it is unchanged.
5558
+ */
5559
+ var EgressEncodeSchema = EncodeProfileSchema.omit({
5560
+ inputArgs: true,
5561
+ outputArgs: true
5562
+ });
5563
+ /**
5564
+ * How the encoder is bounded. `'tight'` is a one-second VBV window for a
5565
+ * consumer whose budget is enforced per second (HomeKit); `'relaxed'` is two
5566
+ * seconds, letting a keyframe spike borrow from the next second (a browser,
5567
+ * an Echo). Named rather than numeric so the INTENT survives.
5568
+ */
5569
+ var EgressRateControlSchema = zod.z.enum(["tight", "relaxed"]);
5570
+ var EgressTranscodeRequestSchema = zod.z.object({
5571
+ deviceId: zod.z.number().int().nonnegative(),
5572
+ /** Which published stream to read. */
5573
+ source: zod.z.discriminatedUnion("kind", [zod.z.object({
5574
+ kind: zod.z.literal("profile"),
5575
+ profile: CamProfileSchema
5576
+ }), zod.z.object({
5577
+ kind: zod.z.literal("cam-stream"),
5578
+ camStreamId: zod.z.string().min(1)
5579
+ })]),
5580
+ encode: EgressEncodeSchema,
5581
+ rateControl: EgressRateControlSchema.optional(),
5582
+ /**
5583
+ * `-bsf:v`. A consumer that negotiates its OWN SDP (HomeKit) cannot carry
5584
+ * out-of-band extradata and needs `dump_extra` on both the copy and encode
5585
+ * branches. Enumerated, not free text.
5586
+ */
5587
+ bitstreamFilter: zod.z.enum([
5588
+ "dump_extra",
5589
+ "h264_mp4toannexb",
5590
+ "hevc_mp4toannexb"
5591
+ ]).optional(),
5592
+ pixelFormat: zod.z.enum(["yuv420p", "nv12"]).optional(),
5593
+ /**
5594
+ * Operator/consumer override for decode hardware. ABSENT is the normal case
5595
+ * and the one that matters: the broker then resolves the backend from the
5596
+ * DECODER ADDON's per-node `probedBestHwaccel` (see
5597
+ * `@camstack/types` `ffmpeg/hwaccel.ts`), which is the ranking known to work
5598
+ * on this hardware — never the raw kernel resolver's qsv-first order.
5599
+ */
5600
+ decodeHwAccel: zod.z.enum([
5601
+ "auto",
5602
+ "none",
5603
+ "videotoolbox",
5604
+ "vaapi",
5605
+ "qsv",
5606
+ "cuda"
5607
+ ]).optional(),
5608
+ /**
5609
+ * Host to embed in the returned restream `url`. The broker mints hub-local
5610
+ * `127.0.0.1` URLs; a consumer on another node passes a cluster-resolvable
5611
+ * host (`NodeTopologyService.reachableHostByNode`) so the returned URL is
5612
+ * dialable from there. Same contract as `getStreamWithCodec.hostname` —
5613
+ * `substituteRtspHost` rewrites only the dial address, never the restreamer.
5614
+ */
5615
+ hostname: zod.z.string().optional(),
5616
+ /** Attribution for the broker panel. Never part of the sharing key. */
5617
+ tag: zod.z.string().optional()
5618
+ });
5619
+ var EgressTranscodeSchema = zod.z.object({
5620
+ /** Dial-able RTSP url (host-substituted when `hostname` was supplied). */
5621
+ url: zod.z.string(),
5622
+ /** Release handle. Refcounted — the child dies when the last holder releases. */
5623
+ pipelineKey: zod.z.string(),
5624
+ videoCodec: zod.z.enum(["H264", "H265"]),
5625
+ resolution: zod.z.object({
5626
+ width: zod.z.number().int().positive(),
5627
+ height: zod.z.number().int().positive()
5628
+ }),
5629
+ transcoded: zod.z.boolean(),
5630
+ encoder: zod.z.string(),
5631
+ /**
5632
+ * The decode backend the child ACTUALLY ran with — `null` for software.
5633
+ * Returned rather than assumed: a consumer that asked for hardware and got
5634
+ * software needs to be able to see that without reading the broker's logs.
5635
+ */
5636
+ decodeHwAccel: zod.z.string().nullable()
5637
+ });
5412
5638
  var streamBrokerCapability = {
5413
5639
  name: "stream-broker",
5414
5640
  scope: "system",
@@ -5580,6 +5806,40 @@ var streamBrokerCapability = {
5580
5806
  auth: "admin"
5581
5807
  }),
5582
5808
  /**
5809
+ * THE ffmpeg primitive. Acquire an encoded stream matching a structured
5810
+ * encode plan; the broker builds the argv through the ONE builder
5811
+ * (`@camstack/types` `ffmpeg/invocation.ts`), resolves decode hardware from
5812
+ * the DECODER ADDON's per-node ranking, and returns a dialable RTSP url.
5813
+ *
5814
+ * **Refcounted and deduplicated on EXACT match.** Two requesters whose
5815
+ * requests produce the same `egressTranscodeSharingKey` receive the SAME
5816
+ * `pipelineKey` and the same child process. Nearly-identical requests are
5817
+ * NOT merged.
5818
+ *
5819
+ * **The handle is immutable.** There is deliberately no `reconfigure`
5820
+ * method and this one never accepts a `pipelineKey` alongside encode
5821
+ * parameters: a consumer whose requirements change releases and
5822
+ * re-acquires. A mutable shared handle is exactly what made Alexa's old
5823
+ * `derived:alexa-<id>` stream a co-tenant hazard — one consumer's
5824
+ * downgrade dragged every other consumer down with it.
5825
+ *
5826
+ * Placement: unpinned, `classifyCapRoute` serves this hub-in-process
5827
+ * (Priority 1). A caller that wants the transcode elsewhere passes
5828
+ * `nodePin(nodeId)` and a `hostname` it can dial.
5829
+ */
5830
+ acquireEgressTranscode: method(EgressTranscodeRequestSchema, EgressTranscodeSchema, {
5831
+ kind: "mutation",
5832
+ auth: "admin"
5833
+ }),
5834
+ /** Drop one reference. The child dies when the last holder releases. */
5835
+ releaseEgressTranscode: method(zod.z.object({ pipelineKey: zod.z.string() }), zod.z.object({
5836
+ released: zod.z.boolean(),
5837
+ refcount: zod.z.number().int().nonnegative()
5838
+ }), {
5839
+ kind: "mutation",
5840
+ auth: "admin"
5841
+ }),
5842
+ /**
5583
5843
  * ── Decoded audio-chunk plane (Phase 5 / D9) ──────────────────────
5584
5844
  *
5585
5845
  * The serialisable replacement for the live-object `IStreamBroker.
@@ -11467,12 +11727,13 @@ var NcConditionsSchema = zod.z.object({
11467
11727
  * source; otherwise the subject's source must equal it. Legacy records
11468
11728
  * with no stamped source are treated as `pipeline`. The union spans both
11469
11729
  * record kinds — object events carry `pipeline` | `onboard`, synthetic
11470
- * tracks carry `sensor`.
11730
+ * tracks carry `sensor` (a linked device) or `audio` (a D62 audio marker).
11471
11731
  */
11472
11732
  source: zod.z.enum([
11473
11733
  "pipeline",
11474
11734
  "onboard",
11475
11735
  "sensor",
11736
+ "audio",
11476
11737
  "any"
11477
11738
  ]).optional(),
11478
11739
  /**
@@ -12060,6 +12321,35 @@ var notificationRulesCapability = {
12060
12321
  auth: "admin"
12061
12322
  }),
12062
12323
  /**
12324
+ * PERMANENT per-camera mute — the notifications half of the per-camera
12325
+ * function switch group ([D61](../../../../docs/decisions/adr-0067.md)).
12326
+ *
12327
+ * Deliberately NOT a snooze. A snooze is bounded at
12328
+ * {@link NC_SNOOZE_MAX_MINUTES} on purpose — "a snooze that could not
12329
+ * expire would be an outage the operator asked for once and forgot" — and
12330
+ * widening it to express "this camera never notifies" would destroy that
12331
+ * property for every snooze. A mute is the other thing: an explicit,
12332
+ * indefinite, admin-only decision, visible in the switch group next to the
12333
+ * other four, and reported on `CameraStatus.switchedOff` so a silent
12334
+ * camera never reads as a working one.
12335
+ *
12336
+ * Returned as ONE list rather than a per-camera query: the group's reader
12337
+ * needs every camera's state, and a per-camera fan-out over the viewer's
12338
+ * single WebSocket is N frames serialised on one socket.
12339
+ */
12340
+ listDeviceMutes: method(zod.z.object({}), zod.z.object({ mutedDeviceIds: zod.z.array(zod.z.number().int()).readonly() }), { auth: "admin" }),
12341
+ /**
12342
+ * Mute or unmute one camera. Idempotent; an unmute of a camera that was
12343
+ * never muted succeeds.
12344
+ */
12345
+ setDeviceMuted: method(zod.z.object({
12346
+ deviceId: zod.z.number().int(),
12347
+ muted: zod.z.boolean()
12348
+ }), zod.z.object({ success: zod.z.literal(true) }), {
12349
+ kind: "mutation",
12350
+ auth: "admin"
12351
+ }),
12352
+ /**
12063
12353
  * Dry-run a rule against recently persisted records (object events for
12064
12354
  * `immediate`, closed tracks for `track-end`). Mutation kind only to
12065
12355
  * carry the full rule object safely; no side effects.
@@ -12471,12 +12761,60 @@ var TrackAudioLabelSchema = zod.z.object({
12471
12761
  });
12472
12762
  /**
12473
12763
  * How a track was produced. `pipeline` (default / absent) = the spatial
12474
- * detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
12475
- * linked sensor/control state change (no positions; carries a snapshot). The
12476
- * spatial subsystems (tracker association, occupancy count, re-id/embedding,
12477
- * resurrection) MUST skip `sensor` tracks they have no bbox trajectory.
12764
+ * detection+tracking pipeline. Every OTHER value is a SYNTHETIC projection
12765
+ * no positions, a single snapshot, and no bbox trajectory at all:
12766
+ *
12767
+ * - `sensor` — a linked sensor/control device state change.
12768
+ * - `audio` — an audio event on the camera itself that was anomalous for
12769
+ * THAT camera, loud, and heard while nothing visual was happening (D62).
12770
+ *
12771
+ * The spatial subsystems (tracker association, occupancy count, re-id /
12772
+ * embedding, resurrection) MUST skip every synthetic source. Test for that
12773
+ * with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
12774
+ * check silently readmits every source added after it was written.
12775
+ */
12776
+ var TrackSourceSchema = zod.z.enum([
12777
+ "pipeline",
12778
+ "sensor",
12779
+ "audio"
12780
+ ]);
12781
+ /**
12782
+ * Per-track OPERATOR flags — set by hand from the admin UI or the viewer, never
12783
+ * by the pipeline. Spread into `TrackSchema` and `KeyEventSchema` from one place
12784
+ * so the two surfaces cannot drift.
12785
+ *
12786
+ * **Absent ≠ false.** A track that has never been touched omits the field; an
12787
+ * explicitly un-flagged track carries `false`. Legacy rows written before the
12788
+ * columns existed read as absent, and a consumer that needs a boolean should say
12789
+ * `flag === true`, not `flag !== false`.
12790
+ *
12791
+ * What the flags DO is deliberately UNDEFINED at the time of writing: they are
12792
+ * operator curation, and the behaviour they drive will be specified separately.
12793
+ * In particular a `markForTrain` track is NOT pinned against retention — see
12794
+ * `docs/decisions/adr-0059.md` for why that is a store-level change, not a flag.
12795
+ */
12796
+ var TrackFlagFields = {
12797
+ /** Operator marked this track as training material. */
12798
+ markForTrain: zod.z.boolean().optional(),
12799
+ /** Operator marked this track for diagnostic attention. */
12800
+ debug: zod.z.boolean().optional()
12801
+ };
12802
+ /**
12803
+ * The write half: a PARTIAL patch. An omitted key is left untouched, so setting
12804
+ * one flag can never clear the other — the toggles are independent and are
12805
+ * driven from three surfaces that do not know about each other.
12806
+ */
12807
+ var TrackFlagsPatchSchema = zod.z.object(TrackFlagFields);
12808
+ /**
12809
+ * The resolved flag state after a write. Both fields are REQUIRED here (absent
12810
+ * collapses to `false`) so a caller can drive a toggle's checked state off the
12811
+ * mutation result without a re-fetch.
12478
12812
  */
12479
- var TrackSourceSchema = zod.z.enum(["pipeline", "sensor"]);
12813
+ var TrackFlagsSchema = zod.z.object({
12814
+ trackId: zod.z.string(),
12815
+ markForTrain: zod.z.boolean(),
12816
+ debug: zod.z.boolean()
12817
+ });
12480
12818
  var TrackSchema = zod.z.object({
12481
12819
  trackId: zod.z.string(),
12482
12820
  deviceId: zod.z.number(),
@@ -12519,7 +12857,8 @@ var TrackSchema = zod.z.object({
12519
12857
  /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
12520
12858
  * Populated from the persisted envelope columns on historical reads;
12521
12859
  * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
12522
- envelope: TrackEnvelopeSchema.optional()
12860
+ envelope: TrackEnvelopeSchema.optional(),
12861
+ ...TrackFlagFields
12523
12862
  });
12524
12863
  var BaseEventFields = {
12525
12864
  id: zod.z.string(),
@@ -12740,7 +13079,8 @@ var KeyEventSchema = zod.z.object({
12740
13079
  /** Highest-confidence ObjectEvent id for the track (empty when none). */
12741
13080
  bestEventId: zod.z.string(),
12742
13081
  /** Track lifetime in ms (lastSeen - firstSeen). */
12743
- windowMs: zod.z.number().optional()
13082
+ windowMs: zod.z.number().optional(),
13083
+ ...TrackFlagFields
12744
13084
  });
12745
13085
  zod.z.object({
12746
13086
  trackId: zod.z.string(),
@@ -12825,16 +13165,32 @@ var RebuildObjectEmbeddingsInput = zod.z.object({
12825
13165
  deviceId: zod.z.number().optional(),
12826
13166
  since: zod.z.number().optional(),
12827
13167
  until: zod.z.number().optional(),
13168
+ /** Stop after this many tracks; the result reports whether more remain. */
13169
+ maxTracks: zod.z.number().int().positive().optional(),
12828
13170
  /**
12829
- * Fraction added on EACH side of the detection box before cropping.
12830
- * ~0.2 (a 1.4x window) gives CLIP the surroundings it is trained on; 0 is
12831
- * the pixel-tight crop the first implementation used.
13171
+ * Run every embedding on THIS node instead of round-robining the fleet.
13172
+ *
13173
+ * Named `executeOnNodeId` and not `nodeId` on purpose: an inline `nodeId`
13174
+ * field in cap args is read by `parent-unowned-call.ts` as a ROUTING PIN, so
13175
+ * calling it that would pin the rebuild REQUEST itself to that node — the
13176
+ * rebuild orchestration lives on the hub, and only the per-track step runs
13177
+ * remotely. This field is data; the per-track pin is applied inside.
13178
+ *
13179
+ * Absent ⇒ round-robin over every online node whose runner can serve the
13180
+ * pinned model.
12832
13181
  */
12833
- cropMargin: zod.z.number().min(0).max(4).optional(),
12834
- /** Square the window before extracting, so a tall subject is not squashed. */
12835
- square: zod.z.boolean().optional(),
12836
- /** Stop after this many tracks; the result reports whether more remain. */
12837
- maxTracks: zod.z.number().int().positive().optional()
13182
+ executeOnNodeId: zod.z.string().optional(),
13183
+ /**
13184
+ * Milliseconds to wait between tracks; omit for the built-in default, `0` to
13185
+ * run flat out.
13186
+ *
13187
+ * A rebuild is bulk maintenance on hub-main's single thread. Measured
13188
+ * 2026-08-06, an unpaced pass held that thread busy 82.2 s out of 120 and
13189
+ * pushed `nodes.topology` from 0.25 s to 26 s for 43 minutes. The value in
13190
+ * force is logged at start and finish so a deliberately slow pass reads
13191
+ * differently from a stalled one.
13192
+ */
13193
+ pacingMs: zod.z.number().int().nonnegative().optional()
12838
13194
  });
12839
13195
  /**
12840
13196
  * Result of emptying the CLIP index.
@@ -12867,6 +13223,24 @@ var RebuildStatusSchema = zod.z.object({
12867
13223
  missingKeyFrame: zod.z.number(),
12868
13224
  /** Tracks with no usable detection box. */
12869
13225
  missingBbox: zod.z.number(),
13226
+ /**
13227
+ * Tracks an executing node REFUSED rather than broke on — an unreadable key
13228
+ * frame, a step that threw. Separate from `failed` because the remedy is
13229
+ * different, and because a whole camera silently contributing zero vectors
13230
+ * is the shape of failure a rebuild must never hide.
13231
+ */
13232
+ notRunnable: zod.z.number(),
13233
+ /**
13234
+ * The pass stopped because NO node could serve the pinned model.
13235
+ *
13236
+ * Distinct from `notRunnable` on purpose: that one says "this track was
13237
+ * refused", this one says "the cluster cannot do this work at all" — every
13238
+ * candidate node either lacks the `clip-embedding` step, lacks a build of the
13239
+ * pinned model for its engine format, or dropped out. The remedy is a model /
13240
+ * engine change, not a per-camera one. Non-zero here always comes with
13241
+ * `complete: false`.
13242
+ */
13243
+ noCapableNode: zod.z.number(),
12870
13244
  failed: zod.z.number(),
12871
13245
  /** Set once a pass ends: true only when EVERYTHING was covered. */
12872
13246
  complete: zod.z.boolean().nullable(),
@@ -13056,6 +13430,31 @@ var pipelineAnalyticsCapability = {
13056
13430
  auth: "admin"
13057
13431
  }),
13058
13432
  /**
13433
+ * Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
13434
+ * The patch is PARTIAL — an omitted key is left untouched — because the
13435
+ * three surfaces that write it (admin Events grid, viewer track detail,
13436
+ * viewer cluster detail) each own one toggle and must not clobber the other.
13437
+ *
13438
+ * Writes the track ROW: `markForTrain`/`debug` are per-TRACK state, so they
13439
+ * live where `label` and `importance` live, not in any per-device settings
13440
+ * store. Updates the in-RAM active track too, so a flag set on a live track
13441
+ * survives its expiry-time persist.
13442
+ *
13443
+ * `auth: 'protected'` (the default), NOT `admin`: the viewer is an
13444
+ * authenticated non-admin surface and two of the three call sites are
13445
+ * there. Revisit if a flag ever gains an effect that costs storage —
13446
+ * `deleteTracks` next door is admin for exactly that reason.
13447
+ *
13448
+ * Returns the RESOLVED state of both flags (absent → `false`) so a caller
13449
+ * can drive its toggle without a re-fetch. Rejects an unknown track.
13450
+ */
13451
+ setTrackFlags: method(zod.z.object({
13452
+ /** Log/audit scope only — the trackId is globally unique on its own. */
13453
+ deviceId: zod.z.number(),
13454
+ trackId: zod.z.string(),
13455
+ flags: TrackFlagsPatchSchema
13456
+ }), TrackFlagsSchema, { kind: "mutation" }),
13457
+ /**
13059
13458
  * Durable event-store footprint for the management UI: event rows
13060
13459
  * (motion + object + audio) counted per camera + total, plus the
13061
13460
  * event-owned media bytes on disk per camera + total. Stat/count-based,
@@ -13935,6 +14334,53 @@ var DetailResultSchema = zod.z.object({
13935
14334
  nativeFaceShortSidePx: zod.z.number().optional()
13936
14335
  });
13937
14336
  /**
14337
+ * Why an executing node REFUSED a stateless step run (`runStatelessStep`).
14338
+ *
14339
+ * A refusal is a first-class answer, not an error, because the caller's next
14340
+ * move depends on WHICH one it is — and because "the pass produced nothing"
14341
+ * must never be reachable without a named, counted cause. The two tiers:
14342
+ *
14343
+ * - **node-level** (`unknown-step`, `model-not-servable`) — this node can
14344
+ * never serve this (step, model) pair. The caller drops it from its rotation
14345
+ * and retries the same work elsewhere; nothing about the work changes.
14346
+ * - **work-level** (`unreadable-frame`, `execution-failed`) — this node is
14347
+ * fine, this one request is not. Retrying it on another node would only
14348
+ * spread the same failure.
14349
+ */
14350
+ var StatelessStepRefusalSchema = zod.z.enum([
14351
+ "unknown-step",
14352
+ "model-not-servable",
14353
+ "unreadable-frame",
14354
+ "execution-failed"
14355
+ ]);
14356
+ /**
14357
+ * Answer to `runStatelessStep` — a discriminated union rather than a nullable
14358
+ * result, because `null` is exactly what made the camera-bound detail path
14359
+ * unable to tell "refused" from "never asked".
14360
+ */
14361
+ var RunStatelessStepResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
14362
+ kind: zod.z.literal("ran"),
14363
+ /** The node that actually executed it — the pin, echoed back for the log. */
14364
+ nodeId: zod.z.string(),
14365
+ /**
14366
+ * The model the step ran with.
14367
+ *
14368
+ * The node verified this exact id has a build for the format it dispatched
14369
+ * on BEFORE running, so the executor's format resolution returns it
14370
+ * unchanged. A caller that pinned a model must compare this field and
14371
+ * treat a mismatch as a refusal — the whole point of the pin is that a
14372
+ * pass writes one feature space.
14373
+ */
14374
+ modelId: zod.z.string(),
14375
+ details: zod.z.array(DetailResultSchema)
14376
+ }), zod.z.object({
14377
+ kind: zod.z.literal("refused"),
14378
+ nodeId: zod.z.string(),
14379
+ reason: StatelessStepRefusalSchema,
14380
+ /** Human-readable specifics — the format tried, the formats shipped, etc. */
14381
+ detail: zod.z.string()
14382
+ })]);
14383
+ /**
13938
14384
  * Per-camera tunable ranges + defaults. Single source of truth used
13939
14385
  * by both the Zod data schema (validation + default fallback) and
13940
14386
  * the device settings UI (slider min/max/step). Touch one place and
@@ -14338,20 +14784,118 @@ var pipelineRunnerCapability = {
14338
14784
  * for a single tracked detection. The per-frame plane (`runPipeline`
14339
14785
  * with `plane: 'frame'`) skips crop children entirely; a track-level
14340
14786
  * caller invokes this per-track, on its own cadence, instead of on
14341
- * every frame. Takes either a `frameHandle` (shm lease/session
14342
- * preferred, zero-copy) or a `cropJpeg` fallback when the lease/
14343
- * session backing the frame is already gone. `steps` narrows which
14344
- * configured children to run (default: all configured children for
14345
- * `parent.className`). Returns `null` when neither frame source is
14346
- * resolvable (handle evicted and no cropJpeg fallback supplied).
14787
+ * every frame. `steps` narrows which configured children to run
14788
+ * (default: all configured children for `parent.className`).
14789
+ *
14790
+ * ## Three pixel sources, and WHO decides the rectangle
14791
+ *
14792
+ * Tried in this order; the difference between them is not the pixels but
14793
+ * which side derives the crop, and confusing the two is how the CLIP index
14794
+ * ended up holding two incomparable feature spaces:
14795
+ *
14796
+ * 1. `frameHandle` — shm lease/session, preferred and zero-copy. **The
14797
+ * runner cuts**, applying the cluster crop convention.
14798
+ * 2. `frameJpeg` — a FULL FRAME supplied by the caller (the embedding
14799
+ * rebuild's stored key frame). **The runner cuts**, applying the same
14800
+ * convention to the same function, so a rebuilt vector lands in the same
14801
+ * feature space as a live one.
14802
+ * 3. `cropJpeg` — an ALREADY-CUT tile. **The caller decided the
14803
+ * rectangle**; the runner applies NO padding and no squaring and feeds
14804
+ * it to the model verbatim. Only for the lease-miss retry, where the
14805
+ * caller holds pixels the runner can no longer reach.
14806
+ *
14807
+ * Returns `null` when no source resolves (handle evicted and no fallback
14808
+ * supplied), when the camera is not attached, or when no enabled step
14809
+ * matches — every one of those is logged on the runner with the deviceId.
14347
14810
  */
14348
14811
  runDetailSubtree: method(zod.z.object({
14349
14812
  deviceId: zod.z.number(),
14350
14813
  frameHandle: FrameHandleSchema.optional(),
14814
+ /**
14815
+ * FULL FRAME (base64 JPEG). The runner derives the crop rectangle from
14816
+ * `parent.bbox` with the cluster crop convention and cuts it itself —
14817
+ * do NOT pre-crop for this field, that is what `cropJpeg` is.
14818
+ */
14819
+ frameJpeg: zod.z.string().optional(),
14820
+ /**
14821
+ * PRE-CUT tile (base64 JPEG), used verbatim — NO padding is applied.
14822
+ * The fallback when the lease/session backing the frame is gone and the
14823
+ * caller already holds a crop.
14824
+ */
14351
14825
  cropJpeg: zod.z.string().optional(),
14352
14826
  parent: DetailParentSchema,
14353
14827
  steps: zod.z.array(zod.z.string()).optional()
14354
- }), zod.z.object({ details: zod.z.array(DetailResultSchema) }).nullable(), { kind: "mutation" })
14828
+ }), zod.z.object({ details: zod.z.array(DetailResultSchema) }).nullable(), { kind: "mutation" }),
14829
+ /**
14830
+ * Run ONE enrichment step against caller-supplied pixels, with NO camera
14831
+ * session — no attach, no frame handle, no device affinity.
14832
+ *
14833
+ * ## Why this exists next to `runDetailSubtree` and not inside it
14834
+ *
14835
+ * `runDetailSubtree` resolves its step tree from the LIVE ATTACH STATE. That
14836
+ * is correct for it: its reason to exist is a frame HANDLE, and a handle is
14837
+ * only resolvable while a decode session is open. But it makes the method
14838
+ * useless to anything walking history — cameras run `detectionMode:
14839
+ * 'on-motion'` and detach ~30 s after motion stops, so a fleet-wide
14840
+ * embedding rebuild found most cameras detached and rebuilt only whatever
14841
+ * happened to be attached at that second (measured 2026-08-06: 1125 tracks
14842
+ * scanned, 121 rebuilt, 601 refused as "camera is not attached").
14843
+ *
14844
+ * A caller that ships its own pixels needs none of that machinery. So this
14845
+ * method takes the three things a step actually needs — an image, a box, a
14846
+ * step id — resolves the step from the CATALOG rather than from an
14847
+ * attachment, and runs it on whichever node the caller pinned.
14848
+ *
14849
+ * ## What it deliberately keeps
14850
+ *
14851
+ * The crop rectangle is derived by the SAME `deriveDetailCropRect` call the
14852
+ * live detail plane uses, from the same cluster-wide convention
14853
+ * ([D52](../../../docs/decisions/adr-0052.md)). `frameJpeg` is a FULL frame,
14854
+ * never a pre-cut tile, for exactly the reason `runDetailSubtree` documents:
14855
+ * a caller that cuts is a second feature space.
14856
+ *
14857
+ * ## What it deliberately drops
14858
+ *
14859
+ * No device jump and no `deviceKey`: the jump roster comes from the attach
14860
+ * config, which does not exist here. The step runs on the node's default
14861
+ * engine. This is a maintenance path, not a latency-sensitive one.
14862
+ *
14863
+ * ## Routing
14864
+ *
14865
+ * NOT device-bound. `sourceDeviceId` is DIAGNOSTIC — the camera whose track
14866
+ * these pixels came from, so every log line on the executing node can carry
14867
+ * `tags: { deviceId }`. It is deliberately not named `deviceId`: that field
14868
+ * is a routing hint that would send the call to the camera's owning node,
14869
+ * which is the placement constraint this method exists to remove. Callers
14870
+ * choose the node with `nodePin(nodeId)`; unpinned, an unowned call is
14871
+ * served hub-in-process like any other singleton.
14872
+ */
14873
+ runStatelessStep: method(zod.z.object({
14874
+ /** Catalog step id, e.g. `clip-embedding`. */
14875
+ stepId: zod.z.string(),
14876
+ /**
14877
+ * REQUIRED model pin. The node runs this exact model or refuses with
14878
+ * `model-not-servable` — it never substitutes a format default, because
14879
+ * a fleet pass that round-robins across nodes would then fill one index
14880
+ * from several encoders.
14881
+ */
14882
+ modelId: zod.z.string(),
14883
+ /** FULL FRAME, base64 JPEG. The runner cuts — do NOT pre-crop. */
14884
+ frameJpeg: zod.z.string(),
14885
+ /**
14886
+ * The subject box, NORMALISED [0,1] against `frameJpeg`. Normalised on
14887
+ * purpose: the caller stores boxes against a downscaled analysis frame
14888
+ * while the stored key frame is native-resolution, and the only side
14889
+ * that reliably knows the image's pixel dimensions is the side that
14890
+ * decodes it. Denormalising here removes a second reader of the
14891
+ * dimensions and the class of mismatch that comes with it.
14892
+ */
14893
+ bbox: NativeCropBboxSchema,
14894
+ /** Parent class of the subject (`person`, `vehicle`, …) — carried into the result. */
14895
+ className: zod.z.string(),
14896
+ /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
14897
+ sourceDeviceId: zod.z.number()
14898
+ }), RunStatelessStepResultSchema, { kind: "mutation" })
14355
14899
  }
14356
14900
  };
14357
14901
  var CameraPipelineConfigSchema = zod.z.object({
@@ -14659,6 +15203,20 @@ var CameraStatusSchema = zod.z.object({
14659
15203
  detection: CameraDetectionStatusSchema.nullable(),
14660
15204
  audio: CameraAudioStatusSchema.nullable(),
14661
15205
  recording: CameraRecordingStatusSchema.nullable(),
15206
+ /**
15207
+ * Per-camera function switches an OPERATOR has turned off
15208
+ * ([D61](../../../../docs/decisions/adr-0067.md)).
15209
+ *
15210
+ * This is the difference between DISABLED and BROKEN. A camera whose
15211
+ * `detection` block reports zero fps and whose `switchedOff` contains
15212
+ * `'object-detection'` was switched off by a person; the same camera with an
15213
+ * empty list is failing. Every status surface must render the two
15214
+ * differently — a quiet camera that looks identical to a dead one is the
15215
+ * silence-reads-as-never-happened trap this repo keeps paying for.
15216
+ *
15217
+ * Empty when nothing is off. Never contains a switch no provider offers.
15218
+ */
15219
+ switchedOff: zod.z.array(CameraSwitchIdSchema).readonly(),
14662
15220
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
14663
15221
  fetchedAt: zod.z.number()
14664
15222
  });
@@ -15058,6 +15616,43 @@ var pipelineOrchestratorCapability = {
15058
15616
  agentNodeId: zod.z.string().optional()
15059
15617
  }), CameraPipelineConfigSchema),
15060
15618
  /**
15619
+ * The whole per-camera function switch group, DERIVED — never a stored
15620
+ * list ([D61](../../../../docs/decisions/adr-0067.md)).
15621
+ *
15622
+ * The group adds no state. Each switch is a view onto the authority that
15623
+ * already owned it (`deviceManager.setDisabled`,
15624
+ * `deviceManager.setWrapperActive`, `RecordingConfig.enabled`,
15625
+ * `notificationRules.setDeviceMuted`), and `switch.authority` says which.
15626
+ * Availability comes from `deviceManager.listBindableCapsForDeviceType`,
15627
+ * so a deployment with no audio analyzer renders no audio switch.
15628
+ *
15629
+ * `auth: 'view'` deliberately — a NON-admin must be able to see that a
15630
+ * camera is quiet because somebody switched it off. Only the mutation is
15631
+ * admin-gated.
15632
+ */
15633
+ getCameraSwitches: method(zod.z.object({ deviceId: zod.z.number() }), CameraSwitchGroupSchema),
15634
+ /**
15635
+ * Flip ONE switch, routed to its existing authority.
15636
+ *
15637
+ * Never writes a parallel map: `recording` patches `RecordingConfig.enabled`
15638
+ * and leaves `bands` byte-identical (clearing bands to express "off"
15639
+ * destroys the operator's authored schedule and turning the camera back on
15640
+ * would silently record nothing), and the two pipeline switches write the
15641
+ * SAME wrapper binding the legacy `pipelineEnabled` / `audioEnabled`
15642
+ * booleans were migrated onto.
15643
+ *
15644
+ * Rejects a switch this camera does not offer rather than persisting a
15645
+ * write nothing reads.
15646
+ */
15647
+ setCameraSwitch: method(zod.z.object({
15648
+ deviceId: zod.z.number(),
15649
+ switchId: CameraSwitchIdSchema,
15650
+ enabled: zod.z.boolean()
15651
+ }), CameraSwitchGroupSchema, {
15652
+ kind: "mutation",
15653
+ auth: "admin"
15654
+ }),
15655
+ /**
15061
15656
  * Server-composed aggregated status for a single camera.
15062
15657
  *
15063
15658
  * Fans out in parallel (bounded, per-stage graceful degradation) to
@@ -27783,6 +28378,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27783
28378
  addonId: null,
27784
28379
  access: "view"
27785
28380
  },
28381
+ "notificationRules.listDeviceMutes": {
28382
+ capName: "notification-rules",
28383
+ capScope: "system",
28384
+ addonId: null,
28385
+ access: "view"
28386
+ },
27786
28387
  "notificationRules.listRules": {
27787
28388
  capName: "notification-rules",
27788
28389
  capScope: "system",
@@ -27801,6 +28402,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27801
28402
  addonId: null,
27802
28403
  access: "create"
27803
28404
  },
28405
+ "notificationRules.setDeviceMuted": {
28406
+ capName: "notification-rules",
28407
+ capScope: "system",
28408
+ addonId: null,
28409
+ access: "create"
28410
+ },
27804
28411
  "notificationRules.setRuleEnabled": {
27805
28412
  capName: "notification-rules",
27806
28413
  capScope: "system",
@@ -28077,6 +28684,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
28077
28684
  addonId: null,
28078
28685
  access: "view"
28079
28686
  },
28687
+ "pipelineAnalytics.setTrackFlags": {
28688
+ capName: "pipeline-analytics",
28689
+ capScope: "device",
28690
+ addonId: null,
28691
+ access: "create"
28692
+ },
28080
28693
  "pipelineAnalytics.wipeAllAnalytics": {
28081
28694
  capName: "pipeline-analytics",
28082
28695
  capScope: "device",
@@ -28383,6 +28996,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
28383
28996
  addonId: null,
28384
28997
  access: "view"
28385
28998
  },
28999
+ "pipelineOrchestrator.getCameraSwitches": {
29000
+ capName: "pipeline-orchestrator",
29001
+ capScope: "system",
29002
+ addonId: null,
29003
+ access: "view"
29004
+ },
28386
29005
  "pipelineOrchestrator.getCapabilityBindings": {
28387
29006
  capName: "pipeline-orchestrator",
28388
29007
  capScope: "system",
@@ -28515,6 +29134,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
28515
29134
  addonId: null,
28516
29135
  access: "create"
28517
29136
  },
29137
+ "pipelineOrchestrator.setCameraSwitch": {
29138
+ capName: "pipeline-orchestrator",
29139
+ capScope: "system",
29140
+ addonId: null,
29141
+ access: "create"
29142
+ },
28518
29143
  "pipelineOrchestrator.setCapabilityBinding": {
28519
29144
  capName: "pipeline-orchestrator",
28520
29145
  capScope: "system",
@@ -28605,6 +29230,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
28605
29230
  addonId: null,
28606
29231
  access: "create"
28607
29232
  },
29233
+ "pipelineRunner.runStatelessStep": {
29234
+ capName: "pipeline-runner",
29235
+ capScope: "system",
29236
+ addonId: null,
29237
+ access: "create"
29238
+ },
28608
29239
  "plateGallery.assignPlate": {
28609
29240
  capName: "plate-gallery",
28610
29241
  capScope: "system",
@@ -29421,6 +30052,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
29421
30052
  addonId: null,
29422
30053
  access: "create"
29423
30054
  },
30055
+ "streamBroker.acquireEgressTranscode": {
30056
+ capName: "stream-broker",
30057
+ capScope: "system",
30058
+ addonId: null,
30059
+ access: "create"
30060
+ },
29424
30061
  "streamBroker.assignProfile": {
29425
30062
  capName: "stream-broker",
29426
30063
  capScope: "system",
@@ -29529,6 +30166,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
29529
30166
  addonId: null,
29530
30167
  access: "create"
29531
30168
  },
30169
+ "streamBroker.releaseEgressTranscode": {
30170
+ capName: "stream-broker",
30171
+ capScope: "system",
30172
+ addonId: null,
30173
+ access: "create"
30174
+ },
29532
30175
  "streamBroker.releaseStreamWithCodec": {
29533
30176
  capName: "stream-broker",
29534
30177
  capScope: "system",
@@ -30307,6 +30950,30 @@ function decodeVectorBase64(encoded) {
30307
30950
  function vectorDimFromBase64(encoded) {
30308
30951
  return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
30309
30952
  }
30953
+ zod.z.object({
30954
+ /**
30955
+ * Fraction of the box's own size added on EACH side before cutting.
30956
+ *
30957
+ * CLIP is trained on natural images WITH surroundings; a pixel-tight crop
30958
+ * removes exactly the context it is strongest on (a dog cut to its outline
30959
+ * is a dark blob). The right value is an empirical question, which is why it
30960
+ * is a setting: 0 / 0.15 / 0.2 / 0.5 are the interesting points.
30961
+ */
30962
+ paddingRatio: zod.z.number().min(0).max(4),
30963
+ /**
30964
+ * Square the window (in PIXELS) before cutting.
30965
+ *
30966
+ * CLIP's input is square, so a tall bbox resized straight to NxN is squashed
30967
+ * — a standing person becomes a shape the model never saw. Squaring costs
30968
+ * extra background, which is context the model wants anyway. Off by default
30969
+ * because the live path has never squared and the stored index reflects that.
30970
+ */
30971
+ square: zod.z.boolean()
30972
+ });
30973
+ ({
30974
+ paddingRatio: .15,
30975
+ square: false
30976
+ }).paddingRatio;
30310
30977
  /**
30311
30978
  * Scores all applicable inference backends for the given hardware.
30312
30979
  *