@camstack/addon-terminal 0.1.33 → 0.1.35

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 (3) hide show
  1. package/dist/addon.js +939 -693
  2. package/dist/addon.mjs +939 -693
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -6721,7 +6721,7 @@ function method(input, output, options) {
6721
6721
  input,
6722
6722
  output,
6723
6723
  kind: options?.kind ?? "query",
6724
- auth: options?.auth ?? "protected",
6724
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6725
6725
  ...options?.access !== void 0 ? { access: options.access } : {},
6726
6726
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6727
6727
  timeoutMs: options?.timeoutMs
@@ -6745,7 +6745,7 @@ function event(data) {
6745
6745
  }
6746
6746
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6747
6747
  var VersionOutputSchema$1 = object({ version: string() });
6748
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6748
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6749
6749
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6750
6750
  DeviceType["Camera"] = "camera";
6751
6751
  DeviceType["Hub"] = "hub";
@@ -7066,7 +7066,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7066
7066
  }({});
7067
7067
  var StaticDirOutputSchema = object({ staticDir: string() });
7068
7068
  var VersionOutputSchema = object({ version: string() });
7069
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7069
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7070
7070
  /**
7071
7071
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7072
7072
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7700,24 +7700,6 @@ var RecordingRetentionSchema = object({
7700
7700
  maxSizeGb: number().min(0).optional()
7701
7701
  });
7702
7702
  /**
7703
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7704
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7705
- * previews at. Five graduated steps; absent on a config = `standard` (the
7706
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7707
- *
7708
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7709
- * Each window's index sidecar carries its own tile dims, so a camera whose
7710
- * preset changed over time renders every historical window at the dims it was
7711
- * written with.
7712
- */
7713
- var ScrubThumbnailPresetSchema = _enum([
7714
- "minimal",
7715
- "low",
7716
- "standard",
7717
- "high",
7718
- "max"
7719
- ]);
7720
- /**
7721
7703
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7722
7704
  *
7723
7705
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7725,7 +7707,11 @@ var ScrubThumbnailPresetSchema = _enum([
7725
7707
  * other field is a storage knob (profiles, segment length, retention, scrub).
7726
7708
  *
7727
7709
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7728
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7710
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7711
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7712
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7713
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7714
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7729
7715
  * A stale caller must fail loudly — silently stripping its legacy intent would
7730
7716
  * persist a band-less config, i.e. silently stop recording the camera.
7731
7717
  */
@@ -7748,14 +7734,7 @@ var RecordingConfigSchema = object({
7748
7734
  * "off" is the absence of a covering band, never a band value.
7749
7735
  */
7750
7736
  bands: array(RecordingBandSchema).default([]),
7751
- retention: RecordingRetentionSchema.optional(),
7752
- /**
7753
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7754
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7755
- * windows only — existing sheets are immutable, and each window's index
7756
- * carries its own tile dims so mixed-preset history renders correctly.
7757
- */
7758
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7737
+ retention: RecordingRetentionSchema.optional()
7759
7738
  }).strict();
7760
7739
  /**
7761
7740
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7831,10 +7810,11 @@ var RelocateFootageInputSchema = object({
7831
7810
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7832
7811
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7833
7812
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7834
- var StorageMigrationMediaMoveInputSchema = object({
7813
+ var RelocateMediaInputSchema = object({
7835
7814
  toLocationId: string(),
7836
7815
  throttleMbps: number().min(1).max(1e3).optional()
7837
- }).extend({ leaseId: string().min(1) });
7816
+ });
7817
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7838
7818
  /** The independently selectable logical storage classes. `recordings`
7839
7819
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7840
7820
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8129,7 +8109,26 @@ var LabelDefinitionSchema = object({
8129
8109
  description: string().optional(),
8130
8110
  icon: string().optional()
8131
8111
  });
8132
- var ClassMapDefinitionSchema = object({
8112
+ /**
8113
+ * Wire schema for a per-model CATALOG classMap override
8114
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8115
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8116
+ * detection pipeline executor actually routes.
8117
+ *
8118
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8119
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8120
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8121
+ * enum) — the two used to share the name `ClassMapDefinition`/
8122
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8123
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8124
+ * are not: it is two different concepts colliding on a name. Keep this type
8125
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8126
+ * would either narrow every `ClassMapDefinition` consumer to the four
8127
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8128
+ * schema exists for (see the "rejects a classMap whose target is not a
8129
+ * detection macro" test in `model-catalog-schema.test.ts`).
8130
+ */
8131
+ var DetectionCatalogClassMapSchema = object({
8133
8132
  mapping: record(string(), _enum([
8134
8133
  "person",
8135
8134
  "vehicle",
@@ -8334,7 +8333,7 @@ var ModelCatalogEntrySchema = object({
8334
8333
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8335
8334
  * labels already ARE the CamStack macros (Scrypted identity map).
8336
8335
  */
8337
- classMap: ClassMapDefinitionSchema.optional()
8336
+ classMap: DetectionCatalogClassMapSchema.optional()
8338
8337
  });
8339
8338
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8340
8339
  format: literal("openvino"),
@@ -8364,7 +8363,7 @@ var ModelConvertMetadataSchema = object({
8364
8363
  "segmentation"
8365
8364
  ]),
8366
8365
  faceAlignment: boolean().optional(),
8367
- classMap: ClassMapDefinitionSchema.optional()
8366
+ classMap: DetectionCatalogClassMapSchema.optional()
8368
8367
  });
8369
8368
  var ConvertResultSchema = object({
8370
8369
  entry: ModelCatalogEntrySchema,
@@ -9227,7 +9226,7 @@ var AddonPageDeclarationSchema = object({
9227
9226
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9228
9227
  sectionLabel: string().optional()
9229
9228
  });
9230
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9229
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9231
9230
  var AddonHttpRouteSchema = object({
9232
9231
  method: _enum([
9233
9232
  "GET",
@@ -9462,7 +9461,7 @@ var WidgetMetadataSchema = object({
9462
9461
  defaultColumns: number().int().min(1).max(12).default(6),
9463
9462
  defaultRows: number().int().min(1).max(12).default(1)
9464
9463
  });
9465
- method(_void(), array(WidgetMetadataSchema).readonly());
9464
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9466
9465
  /**
9467
9466
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9468
9467
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11086,7 +11085,7 @@ var CustomModelDescriptorSchema = object({
11086
11085
  stepId: string(),
11087
11086
  entry: ModelCatalogEntrySchema
11088
11087
  });
11089
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11088
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11090
11089
  /**
11091
11090
  * Query filter for settings-store collections.
11092
11091
  */
@@ -11173,7 +11172,8 @@ method(object({
11173
11172
  }), _void(), { kind: "mutation" }), method(object({
11174
11173
  namespace: string().optional(),
11175
11174
  collection: string(),
11176
- filter: QueryFilterSchema.optional()
11175
+ filter: QueryFilterSchema.optional(),
11176
+ columns: array(string()).readonly().optional()
11177
11177
  }), array(SettingsRecordSchema).readonly()), method(object({
11178
11178
  namespace: string().optional(),
11179
11179
  collection: string(),
@@ -11236,46 +11236,87 @@ var EngineInfoSchema = object({
11236
11236
  kind: _enum(["relational", "vector"]),
11237
11237
  displayName: string()
11238
11238
  });
11239
- method(_void(), EngineInfoSchema), method(object({
11239
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11240
11240
  namespace: string().optional(),
11241
11241
  collection: string(),
11242
11242
  key: string()
11243
- }), unknown()), method(object({
11243
+ }), unknown(), { auth: "admin" }), method(object({
11244
11244
  namespace: string().optional(),
11245
11245
  collection: string(),
11246
11246
  key: string(),
11247
11247
  value: unknown()
11248
- }), _void(), { kind: "mutation" }), method(object({
11248
+ }), _void(), {
11249
+ kind: "mutation",
11250
+ auth: "admin"
11251
+ }), method(object({
11249
11252
  namespace: string().optional(),
11250
11253
  collection: string(),
11251
- filter: QueryFilterSchema.optional()
11252
- }), array(SettingsRecordSchema).readonly()), method(object({
11254
+ filter: QueryFilterSchema.optional(),
11255
+ /**
11256
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11257
+ *
11258
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11259
+ * was wrong — corrected 2026-08-26 after the hop map
11260
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11261
+ * There is **no Zod parse at all** between the door and the engine: the
11262
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11263
+ * field declared here reaches `SqliteSettingsBackend` either way.
11264
+ *
11265
+ * What actually lost `columns` was the THIRD declaration of this shape:
11266
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11267
+ * interface the engine destructures from. The field existed on both
11268
+ * schemas and the engine still never read it, because nothing checks a
11269
+ * registered provider against `InferProvider<cap>` —
11270
+ * `ProviderRegistration.provider` is typed `object`.
11271
+ *
11272
+ * It is declared here anyway, and must stay in step with
11273
+ * `settings-store.query`: a caller reading only the cap definitions has
11274
+ * to be able to see that this call carries a projection.
11275
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11276
+ */
11277
+ columns: array(string()).readonly().optional()
11278
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11253
11279
  namespace: string().optional(),
11254
11280
  collection: string(),
11255
11281
  record: SettingsRecordSchema
11256
- }), _void(), { kind: "mutation" }), method(object({
11282
+ }), _void(), {
11283
+ kind: "mutation",
11284
+ auth: "admin"
11285
+ }), method(object({
11257
11286
  namespace: string().optional(),
11258
11287
  collection: string(),
11259
11288
  id: string(),
11260
11289
  data: record(string(), unknown())
11261
- }), _void(), { kind: "mutation" }), method(object({
11290
+ }), _void(), {
11291
+ kind: "mutation",
11292
+ auth: "admin"
11293
+ }), method(object({
11262
11294
  namespace: string().optional(),
11263
11295
  collection: string(),
11264
11296
  key: string()
11265
- }), _void(), { kind: "mutation" }), method(object({
11297
+ }), _void(), {
11298
+ kind: "mutation",
11299
+ auth: "admin"
11300
+ }), method(object({
11266
11301
  namespace: string().optional(),
11267
11302
  collection: string(),
11268
11303
  filter: MutationFilterSchema
11269
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11304
+ }), object({ deleted: number().int() }), {
11305
+ kind: "mutation",
11306
+ auth: "admin"
11307
+ }), method(object({
11270
11308
  namespace: string().optional(),
11271
11309
  collection: string(),
11272
11310
  filter: MutationFilterSchema,
11273
11311
  data: record(string(), unknown())
11274
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11312
+ }), object({ updated: number().int() }), {
11313
+ kind: "mutation",
11314
+ auth: "admin"
11315
+ }), method(object({
11275
11316
  namespace: string().optional(),
11276
11317
  collection: string(),
11277
11318
  filter: QueryFilterSchema.optional()
11278
- }), number()), method(object({
11319
+ }), number(), { auth: "admin" }), method(object({
11279
11320
  namespace: string().optional(),
11280
11321
  collection: string(),
11281
11322
  field: string(),
@@ -11285,15 +11326,18 @@ method(_void(), EngineInfoSchema), method(object({
11285
11326
  }), array(object({
11286
11327
  bucket: number().int(),
11287
11328
  count: number().int()
11288
- })).readonly()), method(object({
11329
+ })).readonly(), { auth: "admin" }), method(object({
11289
11330
  namespace: string().optional(),
11290
11331
  collection: string()
11291
- }), boolean()), method(object({
11332
+ }), boolean(), { auth: "admin" }), method(object({
11292
11333
  namespace: string().optional(),
11293
11334
  collection: string(),
11294
11335
  columns: array(CollectionColumnSchema).readonly(),
11295
11336
  indexes: array(CollectionIndexSchema).readonly().optional()
11296
- }), _void(), { kind: "mutation" });
11337
+ }), _void(), {
11338
+ kind: "mutation",
11339
+ auth: "admin"
11340
+ });
11297
11341
  /**
11298
11342
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11299
11343
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -12528,7 +12572,7 @@ method(object({
12528
12572
  crop: _instanceof(Uint8Array),
12529
12573
  width: number(),
12530
12574
  height: number()
12531
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12575
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12532
12576
  /**
12533
12577
  * filesystem-browse — per-node capability for browsing the node's local
12534
12578
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12821,19 +12865,22 @@ method(LlmGenerateBaseInputSchema.extend({
12821
12865
  runtime: ManagedRuntimeConfigSchema,
12822
12866
  /** The managed profile's timeout, threaded by the hub provider. */
12823
12867
  timeoutMs: number().int().positive().optional()
12824
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12868
+ }), LlmGenerateResultSchema, {
12869
+ kind: "mutation",
12870
+ auth: "admin"
12871
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12825
12872
  kind: "mutation",
12826
12873
  auth: "admin"
12827
12874
  }), method(object({}), _void(), {
12828
12875
  kind: "mutation",
12829
12876
  auth: "admin"
12830
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12877
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12831
12878
  kind: "mutation",
12832
12879
  auth: "admin"
12833
12880
  }), method(object({ file: string() }), _void(), {
12834
12881
  kind: "mutation",
12835
12882
  auth: "admin"
12836
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12883
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12837
12884
  /**
12838
12885
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12839
12886
  * methods concat-fan across providers; single-row methods route to ONE
@@ -16344,7 +16391,647 @@ var OauthIntegrationDescriptorSchema = object({
16344
16391
  */
16345
16392
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16346
16393
  });
16347
- method(_void(), OauthIntegrationDescriptorSchema);
16394
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16395
+ /**
16396
+ * Reference to the frame's retained NATIVE surface + the parent crop's placement
16397
+ * within the frame, so the executor can re-cut a leaf child ROI at native
16398
+ * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
16399
+ */
16400
+ var NativeCropRefSchema = object({
16401
+ /** Handle keying the retained native surface (node-pinned to its owner). */
16402
+ handle: FrameHandleSchema,
16403
+ /** The parent crop's padded/clamped rectangle in FRAME-space pixels. */
16404
+ cropFrameSpace: object({
16405
+ x: number(),
16406
+ y: number(),
16407
+ w: number(),
16408
+ h: number()
16409
+ })
16410
+ });
16411
+ object({
16412
+ crop: object({
16413
+ left: number(),
16414
+ top: number(),
16415
+ width: number().positive(),
16416
+ height: number().positive()
16417
+ }).optional(),
16418
+ content: object({
16419
+ width: number().int().positive(),
16420
+ height: number().int().positive()
16421
+ }),
16422
+ fit: _enum(["stretch", "contain"]),
16423
+ format: _enum([
16424
+ "rgb",
16425
+ "gray",
16426
+ "jpeg"
16427
+ ])
16428
+ });
16429
+ /**
16430
+ * Process-local frame identity. It is serializable so it can ride an in-process
16431
+ * capability call, but `registryId` deliberately prevents resolution in any
16432
+ * other process or execution group.
16433
+ */
16434
+ var FrameRefSchema = object({
16435
+ registryId: string().min(1),
16436
+ id: string().min(1),
16437
+ width: number().int().positive(),
16438
+ height: number().int().positive(),
16439
+ format: _enum(["rgb", "gray"]),
16440
+ timestamp: number(),
16441
+ capturedAt: number().optional()
16442
+ });
16443
+ var ModelFormatSchema$1 = _enum([
16444
+ "onnx",
16445
+ "coreml",
16446
+ "openvino",
16447
+ "tflite",
16448
+ "pt",
16449
+ "gguf"
16450
+ ]);
16451
+ var PipelineSlotSchema = _enum([
16452
+ "detector",
16453
+ "cropper",
16454
+ "classifier",
16455
+ "refiner",
16456
+ "audio-classifier"
16457
+ ]);
16458
+ var PipelineEngineChoiceSchema = object({
16459
+ runtime: _enum(["node", "python"]),
16460
+ backend: string(),
16461
+ format: ModelFormatSchema$1,
16462
+ device: string().optional()
16463
+ });
16464
+ var AvailableEngineSchema = object({
16465
+ engine: PipelineEngineChoiceSchema,
16466
+ devices: array(object({
16467
+ id: string(),
16468
+ label: string(),
16469
+ description: string().optional()
16470
+ })).readonly(),
16471
+ defaultDevice: string()
16472
+ });
16473
+ var PipelineDefaultStepSchema = lazy(() => object({
16474
+ addonId: string(),
16475
+ addonName: string(),
16476
+ slot: PipelineSlotSchema,
16477
+ inputClasses: array(string()).readonly(),
16478
+ outputClasses: array(string()).readonly(),
16479
+ enabled: boolean(),
16480
+ modelId: string(),
16481
+ children: array(PipelineDefaultStepSchema).readonly(),
16482
+ group: string().optional(),
16483
+ settings: record(string(), unknown()).optional()
16484
+ }));
16485
+ var PipelineTemplateStepSchema = lazy(() => object({
16486
+ addonId: string(),
16487
+ enabled: boolean(),
16488
+ modelId: string(),
16489
+ children: array(PipelineTemplateStepSchema).readonly(),
16490
+ settings: record(string(), unknown()).optional()
16491
+ }));
16492
+ var PipelineTemplateSchema$1 = object({
16493
+ id: string(),
16494
+ name: string(),
16495
+ createdAt: string(),
16496
+ updatedAt: string(),
16497
+ engine: PipelineEngineChoiceSchema,
16498
+ steps: array(PipelineTemplateStepSchema).readonly()
16499
+ });
16500
+ var PipelineModelOptionSchema = object({
16501
+ id: string(),
16502
+ name: string(),
16503
+ formats: record(string(), object({
16504
+ downloaded: boolean(),
16505
+ sizeMB: number()
16506
+ })),
16507
+ group: ModelVariantGroupSchema.optional(),
16508
+ legacy: boolean().optional(),
16509
+ provider: ModelProviderIdSchema.optional()
16510
+ });
16511
+ var ConfigFieldBridge = custom();
16512
+ var PipelineAddonSchemaSchema = object({
16513
+ id: string(),
16514
+ name: string(),
16515
+ slot: PipelineSlotSchema,
16516
+ inputClasses: array(string()).readonly(),
16517
+ outputClasses: array(string()).readonly(),
16518
+ childSlots: array(PipelineSlotSchema).readonly(),
16519
+ models: array(PipelineModelOptionSchema).readonly(),
16520
+ defaultModelId: string(),
16521
+ defaultModelIdByFormat: record(string(), string()).optional(),
16522
+ enabledByDefault: boolean().optional(),
16523
+ backfillIntoExistingOverrides: boolean().optional(),
16524
+ defaultConfidence: number(),
16525
+ group: string().optional(),
16526
+ configSchema: array(ConfigFieldBridge).readonly().optional()
16527
+ });
16528
+ var PipelineSlotSchemaSchema = object({
16529
+ id: PipelineSlotSchema,
16530
+ label: string(),
16531
+ priority: number(),
16532
+ parentSlot: PipelineSlotSchema.nullable(),
16533
+ addons: array(PipelineAddonSchemaSchema).readonly()
16534
+ });
16535
+ var PipelineSchemaSchema = object({
16536
+ availableEngines: array(AvailableEngineSchema).readonly(),
16537
+ selectedEngine: PipelineEngineChoiceSchema,
16538
+ slots: array(PipelineSlotSchemaSchema).readonly()
16539
+ });
16540
+ var EngineProvisioningSchema = object({
16541
+ runtimeId: _enum([
16542
+ "onnx",
16543
+ "openvino",
16544
+ "coreml",
16545
+ "edgetpu"
16546
+ ]).nullable(),
16547
+ device: string().nullable(),
16548
+ state: _enum([
16549
+ "idle",
16550
+ "installing",
16551
+ "verifying",
16552
+ "ready",
16553
+ "failed"
16554
+ ]),
16555
+ progress: number().optional(),
16556
+ error: string().optional(),
16557
+ nextRetryAt: number().optional(),
16558
+ /**
16559
+ * Gate A (config-correctness gate at engine change): human-readable
16560
+ * config issues surfaced EAGERLY when the node's engine changes — model
16561
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
16562
+ * has a <format> build"). Additive/optional: informational only, never
16563
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
16564
+ * Absent/empty when the node-default tree resolves cleanly.
16565
+ */
16566
+ configIssues: array(string()).optional()
16567
+ });
16568
+ var PipelineStepInputSchema = lazy(() => object({
16569
+ addonId: string(),
16570
+ modelId: string().optional(),
16571
+ enabled: boolean().default(true),
16572
+ children: array(PipelineStepInputSchema).optional(),
16573
+ settings: record(string(), unknown()).optional(),
16574
+ jumpDeviceKey: string().optional()
16575
+ }));
16576
+ var ModelSubstitutionSchema = object({
16577
+ addonId: string(),
16578
+ chosen: string(),
16579
+ running: string(),
16580
+ format: string()
16581
+ });
16582
+ var PipelineValidationIssueSchema = object({
16583
+ addonId: string(),
16584
+ kind: _enum(["unknown-addon", "no-format-build"]),
16585
+ detail: string()
16586
+ });
16587
+ var PipelineValidationResultSchema = object({
16588
+ ok: boolean(),
16589
+ issues: array(PipelineValidationIssueSchema).readonly(),
16590
+ substitutions: array(ModelSubstitutionSchema).readonly(),
16591
+ /** The node's `currentEngine.format` this validation ran against. */
16592
+ format: string()
16593
+ });
16594
+ var ReferenceImageEntrySchema = object({
16595
+ filename: string(),
16596
+ stepIds: array(string()).readonly().optional()
16597
+ });
16598
+ var ReferenceImageBodySchema = object({
16599
+ base64: string(),
16600
+ filename: string()
16601
+ });
16602
+ var ReferenceAudioEntrySchema = object({
16603
+ filename: string(),
16604
+ sizeKb: number()
16605
+ });
16606
+ var ReferenceAudioBodySchema = object({ base64: string() });
16607
+ var AudioBackendSchema = object({
16608
+ id: string(),
16609
+ name: string(),
16610
+ description: string(),
16611
+ available: boolean(),
16612
+ /**
16613
+ * Raw classifier labels this backend can emit (e.g. YAMNet's
16614
+ * 521-class set or Apple SoundAnalysis's 303-class set). Used by
16615
+ * the benchmark UI to populate the `enabledMicroClasses` filter
16616
+ * specific to the selected backend without a separate fetch.
16617
+ */
16618
+ rawLabels: array(string()).readonly().optional()
16619
+ });
16620
+ var AudioCapabilitiesSchema = object({
16621
+ activeBackend: string(),
16622
+ availableBackends: array(AudioBackendSchema).readonly(),
16623
+ sampleRate: number(),
16624
+ chunkDurationMs: number()
16625
+ });
16626
+ var DownloadModelResultSchema = object({
16627
+ filePath: string(),
16628
+ sizeMB: number(),
16629
+ durationMs: number()
16630
+ });
16631
+ /**
16632
+ * Wrapper carrying a single test run's result. Replaces the legacy
16633
+ * ad-hoc `{labels: [{className, originalClass, score}]}` shape with the
16634
+ * canonical `AudioResult` from the Phase 6 output rework: one
16635
+ * `AudioDetection` per class above `minScore`, top-N candidates in
16636
+ * `debug.alternateLabels['audio-classifier']`, per-source timings in
16637
+ * `debug.stepTimings`. The outer `success`/`error` fields stay so the
16638
+ * benchmark UI can still report a clean failure when the classifier
16639
+ * cap isn't available.
16640
+ */
16641
+ var AudioTestResultSchema = object({
16642
+ success: boolean(),
16643
+ error: string().optional(),
16644
+ frame: custom().optional()
16645
+ });
16646
+ var PipelineConfigBridge = custom();
16647
+ var ConfigUISchemaBridge = custom();
16648
+ var ConfigUISchemaNullableBridge = custom();
16649
+ var InferenceCapabilitiesBridge = custom();
16650
+ var ModelAvailabilityListBridge = custom();
16651
+ var PipelineRunResultBridge = custom();
16652
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
16653
+ modelId: string(),
16654
+ settings: record(string(), unknown()).readonly()
16655
+ }))), method(object({ steps: record(string(), object({
16656
+ modelId: string(),
16657
+ settings: record(string(), unknown()).readonly()
16658
+ })) }), object({ success: literal(true) }), {
16659
+ kind: "mutation",
16660
+ auth: "admin"
16661
+ }), method(object({ nodeId: string() }), object({
16662
+ success: literal(true),
16663
+ clearedDevices: number()
16664
+ }), {
16665
+ kind: "mutation",
16666
+ auth: "admin"
16667
+ }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
16668
+ /** `<backend>:<device>`, e.g. `openvino:gpu`. */
16669
+ deviceKey: string(),
16670
+ /**
16671
+ * `failed` — the per-device restart budget is exhausted; no pool
16672
+ * will be spawned until an operator re-arms it or the runner
16673
+ * respawns. `backoff` — under budget, waiting out the backoff (or
16674
+ * a cached pool observed dead and not yet condemned).
16675
+ */
16676
+ state: _enum(["failed", "backoff"]),
16677
+ /** Epoch ms of the death that produced this state. */
16678
+ since: number(),
16679
+ /** Pool deaths inside the current window. */
16680
+ deaths: number(),
16681
+ /** The last death's message. */
16682
+ lastError: string()
16683
+ })).readonly() })), method(object({
16684
+ nodeId: string(),
16685
+ deviceKey: string()
16686
+ }), object({ rearmed: boolean() }), {
16687
+ kind: "mutation",
16688
+ auth: "admin"
16689
+ }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
16690
+ name: string(),
16691
+ steps: array(PipelineTemplateStepSchema).readonly(),
16692
+ engine: PipelineEngineChoiceSchema
16693
+ }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
16694
+ id: string(),
16695
+ name: string().optional(),
16696
+ steps: array(PipelineTemplateStepSchema).readonly().optional()
16697
+ }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
16698
+ addonId: string(),
16699
+ modelId: string(),
16700
+ format: ModelFormatSchema$1
16701
+ }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
16702
+ addonId: string(),
16703
+ modelId: string(),
16704
+ format: ModelFormatSchema$1
16705
+ }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
16706
+ engine: PipelineEngineChoiceSchema.optional(),
16707
+ steps: array(PipelineStepInputSchema).min(1),
16708
+ frame: FrameInputSchema.optional(),
16709
+ /**
16710
+ * Process-local lazy frame. Valid only when caller and provider resolve
16711
+ * in the same execution-group process; split/cross-node callers use
16712
+ * `frame`/`image` inline compatibility instead.
16713
+ */
16714
+ frameRef: FrameRefSchema.optional(),
16715
+ /**
16716
+ * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
16717
+ * the decoded pixels live in. One more member of the one-of
16718
+ * frame/frameHandle/image/imageBase64/referenceImage group.
16719
+ */
16720
+ frameHandle: FrameHandleSchema.optional(),
16721
+ imageBase64: string().optional(),
16722
+ /**
16723
+ * Binary JPEG bytes — preferred over `imageBase64` on internal
16724
+ * hops (hub → forked worker via Moleculer MsgPack) because it
16725
+ * skips the 33% base64 overhead + the per-call base64 decode on
16726
+ * the detection-pipeline worker. Callers can pass either; exactly
16727
+ * one of `frame`/`image`/`imageBase64`/`referenceImage` is required.
16728
+ */
16729
+ image: _instanceof(Uint8Array).optional(),
16730
+ referenceImage: string().optional(),
16731
+ deviceId: number().optional(),
16732
+ sessionId: string().optional(),
16733
+ /**
16734
+ * Execution plane. 'full' (default) runs the whole tree — benchmark,
16735
+ * reference-image, and detail-subtree calls. 'frame' is the live
16736
+ * per-frame dispatch: ONLY root-plane steps run; crop children
16737
+ * (inputClasses ≠ null) are skipped and served per-track via
16738
+ * pipelineRunner.runDetailSubtree (two-plane design).
16739
+ */
16740
+ plane: _enum(["full", "frame"]).optional(),
16741
+ /**
16742
+ * Inference-device selector (Phase 2 multi-device). Format
16743
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
16744
+ * Omitted ⇒ the runner's default device (current single-engine
16745
+ * behaviour). Selects WHICH device pool of the node runs the call.
16746
+ */
16747
+ deviceKey: string().optional(),
16748
+ /**
16749
+ * Two-plane NATIVE child-crop reference. Set by `runDetailSubtree` ONLY
16750
+ * when the parent crop was resolved from the frame's retained NATIVE
16751
+ * surface (a frameHandle HIT). Lets the executor re-cut a LEAF crop
16752
+ * child's ROI (plate-ocr, face-embedding, leaf classifiers) at native
16753
+ * resolution from that surface — the SAME quality path faces already
16754
+ * had — instead of the downscaled parent tile. `handle` keys the native
16755
+ * surface (node-pinned to its owner); `cropFrameSpace` is the parent
16756
+ * crop's padded/clamped rectangle in FRAME-space pixels, used to compose
16757
+ * the executor's crop-normalized child ROI back into frame-normalized
16758
+ * coordinates. Auxiliary to the image source (`image`/`frame`/…), NOT one
16759
+ * of the mutually-exclusive image inputs. Absent ⇒ tile-crop children
16760
+ * (today's behaviour on the fallback path).
16761
+ */
16762
+ nativeCropRef: NativeCropRefSchema.optional()
16763
+ }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
16764
+ engine: PipelineEngineChoiceSchema.optional(),
16765
+ steps: array(PipelineStepInputSchema).min(1),
16766
+ frames: array(FrameInputSchema).min(1).max(255),
16767
+ deviceId: number().optional(),
16768
+ sessionId: string().optional(),
16769
+ /**
16770
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
16771
+ * the batch to the Python pool's bench preprocess cache
16772
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
16773
+ * preprocessed ONCE and every later inference is a pure-inference cache
16774
+ * hit — the sustained-throughput run measures inference, not
16775
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
16776
+ * full preprocess every call, correct). Fresh per sustained run;
16777
+ * released via `uncacheFrame`.
16778
+ */
16779
+ frameId: number().int().nonnegative().optional(),
16780
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
16781
+ deviceKey: string().optional()
16782
+ }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
16783
+ data: _instanceof(Uint8Array),
16784
+ width: number().int().positive(),
16785
+ height: number().int().positive(),
16786
+ format: _enum([
16787
+ "rgb",
16788
+ "bgr",
16789
+ "gray"
16790
+ ])
16791
+ }), object({
16792
+ frameId: number(),
16793
+ width: number(),
16794
+ height: number()
16795
+ }), { kind: "mutation" }), method(object({
16796
+ stepId: string(),
16797
+ frameId: number().int()
16798
+ }), record(string(), unknown()), { kind: "mutation" }), method(object({ frameId: number().int() }), _void(), { kind: "mutation" }), method(_void(), object({
16799
+ batchMode: string(),
16800
+ windowMs: number(),
16801
+ maxBatchSize: number(),
16802
+ concurrency: number()
16803
+ })), method(_void(), array(object({
16804
+ engineKey: string(),
16805
+ engine: PipelineEngineChoiceSchema,
16806
+ modelsLoaded: array(string()).readonly(),
16807
+ inUseByCameras: array(number()).readonly(),
16808
+ /**
16809
+ * Origin of this resident factory.
16810
+ * - `runtime` — main camera-serving engine (no idle TTL).
16811
+ * - `warm-override` — benchmark/test override held in the warm
16812
+ * cache; auto-disposed after the idle TTL.
16813
+ * - `device-pool` — a concurrent per-device pool (Phase 2
16814
+ * multi-device, keyed by `deviceKey`) resolved
16815
+ * via `resolveDeviceFactory`. Runs alongside the
16816
+ * `runtime` engine on a DIFFERENT accelerator
16817
+ * (NPU / iGPU / Coral) — this is how the
16818
+ * Engines tab shows all pools running at once.
16819
+ */
16820
+ kind: _enum([
16821
+ "runtime",
16822
+ "warm-override",
16823
+ "device-pool"
16824
+ ]),
16825
+ /** Native pid of the underlying Python pool (null when no pool). */
16826
+ poolPid: number().nullable(),
16827
+ /** ms since this factory was last used (null when not warm-tracked). */
16828
+ idleMs: number().nullable(),
16829
+ /** Idle TTL after which `warm-override` factories self-evict (null when not applicable). */
16830
+ idleTtlMs: number().nullable()
16831
+ })).readonly()), method(object({ engine: PipelineEngineChoiceSchema }), object({ success: literal(true) }), {
16832
+ kind: "mutation",
16833
+ auth: "admin"
16834
+ }), method(object({
16835
+ engine: PipelineEngineChoiceSchema,
16836
+ force: boolean().optional()
16837
+ }), object({
16838
+ success: boolean(),
16839
+ reason: string().optional()
16840
+ }), {
16841
+ kind: "mutation",
16842
+ auth: "admin"
16843
+ }), method(_void(), array(ReferenceImageEntrySchema).readonly()), method(object({ filename: string() }), ReferenceImageBodySchema.nullable()), method(_void(), array(ReferenceAudioEntrySchema).readonly()), method(object({ filename: string() }), ReferenceAudioBodySchema.nullable()), method(_void(), AudioCapabilitiesSchema), method(object({
16844
+ addonId: string(),
16845
+ modelId: string(),
16846
+ filename: string().optional(),
16847
+ settings: record(string(), unknown()).optional()
16848
+ }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
16849
+ /**
16850
+ * Per-stage gating mode applied to the zones a rule references.
16851
+ *
16852
+ * - `include`: the rule contributes to a **whitelist** for its stage.
16853
+ * When at least one `include` rule fires for a stage, only entities
16854
+ * inside one of those zones pass that stage.
16855
+ * - `exclude`: the rule contributes to a **blacklist** for its stage.
16856
+ * Entities inside one of those zones are dropped at that stage.
16857
+ *
16858
+ * `monitor`-style observation (count without filtering) is not a rule
16859
+ * mode — zones without any matching rule are observed naturally by
16860
+ * `zone-analytics` (live snapshot + history), so an "I just want to
16861
+ * count, not filter" use case needs no rule at all.
16862
+ */
16863
+ var ZoneRuleModeEnum = _enum(["include", "exclude"]);
16864
+ /**
16865
+ * Per-consumer rule that references existing zones (geometry) and
16866
+ * defines how a specific pipeline stage should treat them. Each
16867
+ * consumer addon owns its own `ZoneRule[]` array in its per-device
16868
+ * settings:
16869
+ *
16870
+ * - `addon-motion-wasm` → `motionZoneRules: ZoneRule[]` (motion stage)
16871
+ * - `addon-detection-pipeline` → `detectionZoneRules: ZoneRule[]` (detection stage)
16872
+ * - future: notification rules, audio gating, etc.
16873
+ *
16874
+ * One rule applies to N zones (`zoneIds[]`) so the operator can
16875
+ * express "ignore motion in ALL of {garden, street}" with a single
16876
+ * rule. `classFilter` narrows the rule to specific object classes —
16877
+ * "drop person detections in the street, but keep cars" is one
16878
+ * `exclude` rule with `classFilter: ['person']`.
16879
+ *
16880
+ * `enabled` is a soft toggle — the operator can keep the rule
16881
+ * configured but inert without deleting it.
16882
+ */
16883
+ var ZoneRuleSchema = object({
16884
+ /** Stable rule id — survives edits, used by the UI for diffing. */
16885
+ id: string(),
16886
+ /** Optional human-readable label rendered in the rule editor. */
16887
+ name: string().optional(),
16888
+ /** Zones this rule targets. The rule's `mode` applies to ALL
16889
+ * listed zones (OR-set: a detection in any one of them counts).
16890
+ * At least one zone id required — a rule with no targets is a
16891
+ * configuration mistake and the form validator rejects it. */
16892
+ zoneIds: array(string()).min(1).readonly(),
16893
+ mode: ZoneRuleModeEnum,
16894
+ /**
16895
+ * Class names this rule applies to. Empty / undefined ⇒ rule
16896
+ * applies to every class. Class strings match the `macroClass`
16897
+ * field on detections (e.g. `person`, `car`, `dog`).
16898
+ */
16899
+ classFilter: array(string()).readonly().optional(),
16900
+ /**
16901
+ * Minimum bbox/mask overlap (0–1) with any of the rule's zones
16902
+ * required to consider an entity "in the zone". Defaults to the
16903
+ * consumer's stage default when omitted. Kept for back-compat with
16904
+ * existing per-rule overrides; new operators pick the value via
16905
+ * `bboxInclusionPct` (operator-friendly 0–100). Whichever field is
16906
+ * set, the lower-level engine reads it as a 0–1 fraction.
16907
+ */
16908
+ overlapThreshold: number().min(0).max(1).optional(),
16909
+ /**
16910
+ * Operator-friendly version of `overlapThreshold` — the percentage
16911
+ * of the detection's bbox that must lie inside the zone for the
16912
+ * rule to match. Documented default is 85%; the engine substitutes
16913
+ * that when the field is omitted (kept optional so existing rules
16914
+ * stored without it stay valid).
16915
+ *
16916
+ * When BOTH `overlapThreshold` and `bboxInclusionPct` are set on a
16917
+ * rule, the engine prefers `bboxInclusionPct` because it's the
16918
+ * field exposed in the UI. Internally both feed the same gate.
16919
+ */
16920
+ bboxInclusionPct: number().min(0).max(100).optional(),
16921
+ /**
16922
+ * When `true` and a detection has a segmentation mask, use the
16923
+ * mask for overlap instead of the bbox. Detection-stage only;
16924
+ * motion rules ignore this field.
16925
+ */
16926
+ preferMask: boolean().optional(),
16927
+ /**
16928
+ * Soft-toggle: `false` disables the rule without deleting it.
16929
+ * Defaults to `true` so operators creating a rule via the UI
16930
+ * see it active immediately.
16931
+ */
16932
+ enabled: boolean().default(true)
16933
+ });
16934
+ array(ZoneRuleSchema).readonly();
16935
+ /**
16936
+ * Zone — pure geometry + identity. NO filtering behaviour.
16937
+ *
16938
+ * Zones describe **where** in the frame the operator wants to flag
16939
+ * something; consumer-owned {@link ZoneRule} arrays describe **how**
16940
+ * each pipeline stage uses them. Splitting the two means a single
16941
+ * polygon "Driveway" can simultaneously back a motion-exclude rule,
16942
+ * a detection-include rule on `['car']`, and an occupancy aggregate
16943
+ * — without three duplicated polygons.
16944
+ *
16945
+ * Owned by the orchestrator addon (provider) and mirrored into the
16946
+ * `zones` device-state slice on every mutation. Consumers
16947
+ * (motion-wasm, pipeline-executor, analytics, admin UI) read either
16948
+ * via `api.zones.listZones` (one-shot) or via `dev.state.zones` (live
16949
+ * mirror with `onChanged`).
16950
+ *
16951
+ * Coordinates are normalised fractions of the frame (0–1) so zones
16952
+ * survive resolution changes and stream profile switches.
16953
+ *
16954
+ * `kind` discriminates between full polygons (closed regions used
16955
+ * for intrusion / occupancy filters) and tripwires (open 2-point
16956
+ * line segments used for cross events). Onboard / firmware-reported
16957
+ * zones (Reolink, ONVIF) are out of scope for now — see the deferred
16958
+ * task list.
16959
+ */
16960
+ var ZoneKindEnum = _enum(["polygon", "tripwire"]);
16961
+ /** Polygon vertex in fraction-of-frame coordinates (0–1). */
16962
+ var PolygonPointSchema = object({
16963
+ x: number(),
16964
+ y: number()
16965
+ });
16966
+ /** A camera detection zone — pure geometry/identity. */
16967
+ var ZoneSchema = object({
16968
+ id: string(),
16969
+ name: string(),
16970
+ kind: ZoneKindEnum.default("polygon"),
16971
+ /** Polygon vertices, fraction of frame (0–1). */
16972
+ polygon: array(PolygonPointSchema).readonly(),
16973
+ /** Visual color for UI rendering. */
16974
+ color: string().default("#3b82f6")
16975
+ });
16976
+ /**
16977
+ * Zones capability — per-camera CRUD over polygon detection zones.
16978
+ *
16979
+ * Provider lives in `addon-pipeline-orchestrator` (hub-only). Persists
16980
+ * to per-device settings and mirrors into the `zones` device-state
16981
+ * slice on every mutation, so downstream consumers can subscribe via
16982
+ * `dev.state.zones.onChanged`.
16983
+ *
16984
+ * The cap surface only handles geometry + identity; filtering
16985
+ * behaviour (per-class, include/exclude, threshold) lives in the
16986
+ * consumer addons' rule arrays — see `ZoneRuleSchema` exported from
16987
+ * `capabilities/schemas/zone-rule.js`.
16988
+ */
16989
+ var zonesCapability = {
16990
+ name: "zones",
16991
+ scope: "device",
16992
+ mode: "singleton",
16993
+ deviceTypes: [DeviceType.Camera],
16994
+ methods: {
16995
+ listZones: method(object({ deviceId: number() }), array(ZoneSchema).readonly()),
16996
+ addZone: method(object({
16997
+ deviceId: number(),
16998
+ zone: ZoneSchema
16999
+ }), _void(), {
17000
+ kind: "mutation",
17001
+ auth: "admin"
17002
+ }),
17003
+ removeZone: method(object({
17004
+ deviceId: number(),
17005
+ zoneId: string()
17006
+ }), _void(), {
17007
+ kind: "mutation",
17008
+ auth: "admin"
17009
+ }),
17010
+ updateZone: method(object({
17011
+ deviceId: number(),
17012
+ zone: ZoneSchema
17013
+ }), _void(), {
17014
+ kind: "mutation",
17015
+ auth: "admin"
17016
+ })
17017
+ },
17018
+ /**
17019
+ * Runtime-state slice — the live zone catalogue mirrored by the
17020
+ * orchestrator on every CRUD mutation. Consumers read via
17021
+ * `device.state.zones.value` / `.watch(...)` without round-tripping
17022
+ * the cap, and the codegen DeviceProxy auto-wires the reactive
17023
+ * handle. Slice shape is `{ zones: Zone[] }` so future extensions
17024
+ * (e.g. zone groupings) can sit alongside the polygon list.
17025
+ */
17026
+ runtimeState: object({ zones: array(ZoneSchema).readonly() }),
17027
+ /**
17028
+ * Runtime-state durability: **restored** — written only on operator mutation, so a camera that never had one has nothing to re-derive from. This is the slice `zone-mirror-hydration.ts` exists to paper over.
17029
+ *
17030
+ * See `RuntimeStateDurability`. Enforced by
17031
+ * `scripts/check-runtime-state-durability.ts`.
17032
+ */
17033
+ durability: "restored"
17034
+ };
16348
17035
  /**
16349
17036
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16350
17037
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17434,6 +18121,24 @@ var RebuildStatusSchema = object({
17434
18121
  /** Present when the pass ended by throwing. */
17435
18122
  error: string().nullable()
17436
18123
  });
18124
+ var ReplayFrameInputSchema = object({
18125
+ timestamp: number(),
18126
+ frame: PipelineRunResultBridge
18127
+ });
18128
+ var RunReplayFrameProcessorResultSchema = object({ tracks: array(object({
18129
+ className: string(),
18130
+ firstSeenMs: number(),
18131
+ lastSeenMs: number(),
18132
+ /** Bbox of the track's FIRST matched detection, pixel-space in the clip's
18133
+ * frame — a representative box for the diff's `(className, window, IoU)`
18134
+ * pairing (`replay-diff.ts`). A replay does not need the full per-frame
18135
+ * trajectory production's `Track.positions` keeps. */
18136
+ bbox: BoundingBoxSchema,
18137
+ /** How many of the input frames this track matched a real detection on
18138
+ * (never a coasted/extrapolated frame) — the replay's own signal for "how
18139
+ * solid is this track", cheaper than re-deriving it from a trajectory. */
18140
+ framesMatched: number().int()
18141
+ })).readonly() });
17437
18142
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
17438
18143
  deviceId: number(),
17439
18144
  trackId: string()
@@ -17539,6 +18244,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17539
18244
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17540
18245
  kind: "mutation",
17541
18246
  auth: "admin"
18247
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18248
+ kind: "mutation",
18249
+ auth: "admin"
18250
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
18251
+ kind: "query",
18252
+ auth: "admin"
18253
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
18254
+ kind: "mutation",
18255
+ auth: "admin"
17542
18256
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17543
18257
  kind: "query",
17544
18258
  auth: "admin"
@@ -17595,6 +18309,16 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17595
18309
  }), RetrainAssistResultSchema, {
17596
18310
  kind: "mutation",
17597
18311
  auth: "admin"
18312
+ }), method(object({
18313
+ deviceId: number(),
18314
+ source: DetectionSourceSchema,
18315
+ zones: array(ZoneSchema).readonly().optional(),
18316
+ detectionRules: array(ZoneRuleSchema).readonly().optional(),
18317
+ zoneMembershipMinOverlap: number().min(0).max(1).optional(),
18318
+ frames: array(ReplayFrameInputSchema).min(1)
18319
+ }), RunReplayFrameProcessorResultSchema, {
18320
+ kind: "mutation",
18321
+ auth: "admin"
17598
18322
  }), method(object({ trackId: string() }), array(RetrainAnnotationSchema).readonly(), {
17599
18323
  kind: "query",
17600
18324
  auth: "admin"
@@ -17659,433 +18383,6 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17659
18383
  eventId: string(),
17660
18384
  timestamp: number()
17661
18385
  });
17662
- /**
17663
- * Reference to the frame's retained NATIVE surface + the parent crop's placement
17664
- * within the frame, so the executor can re-cut a leaf child ROI at native
17665
- * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
17666
- */
17667
- var NativeCropRefSchema = object({
17668
- /** Handle keying the retained native surface (node-pinned to its owner). */
17669
- handle: FrameHandleSchema,
17670
- /** The parent crop's padded/clamped rectangle in FRAME-space pixels. */
17671
- cropFrameSpace: object({
17672
- x: number(),
17673
- y: number(),
17674
- w: number(),
17675
- h: number()
17676
- })
17677
- });
17678
- object({
17679
- crop: object({
17680
- left: number(),
17681
- top: number(),
17682
- width: number().positive(),
17683
- height: number().positive()
17684
- }).optional(),
17685
- content: object({
17686
- width: number().int().positive(),
17687
- height: number().int().positive()
17688
- }),
17689
- fit: _enum(["stretch", "contain"]),
17690
- format: _enum([
17691
- "rgb",
17692
- "gray",
17693
- "jpeg"
17694
- ])
17695
- });
17696
- var FrameRefSchema = object({
17697
- registryId: string().min(1),
17698
- id: string().min(1),
17699
- width: number().int().positive(),
17700
- height: number().int().positive(),
17701
- format: _enum(["rgb", "gray"]),
17702
- timestamp: number(),
17703
- capturedAt: number().optional()
17704
- });
17705
- var ModelFormatSchema$1 = _enum([
17706
- "onnx",
17707
- "coreml",
17708
- "openvino",
17709
- "tflite",
17710
- "pt",
17711
- "gguf"
17712
- ]);
17713
- var PipelineSlotSchema = _enum([
17714
- "detector",
17715
- "cropper",
17716
- "classifier",
17717
- "refiner",
17718
- "audio-classifier"
17719
- ]);
17720
- var PipelineEngineChoiceSchema = object({
17721
- runtime: _enum(["node", "python"]),
17722
- backend: string(),
17723
- format: ModelFormatSchema$1,
17724
- device: string().optional()
17725
- });
17726
- var AvailableEngineSchema = object({
17727
- engine: PipelineEngineChoiceSchema,
17728
- devices: array(object({
17729
- id: string(),
17730
- label: string(),
17731
- description: string().optional()
17732
- })).readonly(),
17733
- defaultDevice: string()
17734
- });
17735
- var PipelineDefaultStepSchema = lazy(() => object({
17736
- addonId: string(),
17737
- addonName: string(),
17738
- slot: PipelineSlotSchema,
17739
- inputClasses: array(string()).readonly(),
17740
- outputClasses: array(string()).readonly(),
17741
- enabled: boolean(),
17742
- modelId: string(),
17743
- children: array(PipelineDefaultStepSchema).readonly(),
17744
- group: string().optional(),
17745
- settings: record(string(), unknown()).optional()
17746
- }));
17747
- var PipelineTemplateStepSchema = lazy(() => object({
17748
- addonId: string(),
17749
- enabled: boolean(),
17750
- modelId: string(),
17751
- children: array(PipelineTemplateStepSchema).readonly(),
17752
- settings: record(string(), unknown()).optional()
17753
- }));
17754
- var PipelineTemplateSchema$1 = object({
17755
- id: string(),
17756
- name: string(),
17757
- createdAt: string(),
17758
- updatedAt: string(),
17759
- engine: PipelineEngineChoiceSchema,
17760
- steps: array(PipelineTemplateStepSchema).readonly()
17761
- });
17762
- var PipelineModelOptionSchema = object({
17763
- id: string(),
17764
- name: string(),
17765
- formats: record(string(), object({
17766
- downloaded: boolean(),
17767
- sizeMB: number()
17768
- })),
17769
- group: ModelVariantGroupSchema.optional(),
17770
- legacy: boolean().optional(),
17771
- provider: ModelProviderIdSchema.optional()
17772
- });
17773
- var ConfigFieldBridge = custom();
17774
- var PipelineAddonSchemaSchema = object({
17775
- id: string(),
17776
- name: string(),
17777
- slot: PipelineSlotSchema,
17778
- inputClasses: array(string()).readonly(),
17779
- outputClasses: array(string()).readonly(),
17780
- childSlots: array(PipelineSlotSchema).readonly(),
17781
- models: array(PipelineModelOptionSchema).readonly(),
17782
- defaultModelId: string(),
17783
- defaultModelIdByFormat: record(string(), string()).optional(),
17784
- enabledByDefault: boolean().optional(),
17785
- backfillIntoExistingOverrides: boolean().optional(),
17786
- defaultConfidence: number(),
17787
- group: string().optional(),
17788
- configSchema: array(ConfigFieldBridge).readonly().optional()
17789
- });
17790
- var PipelineSlotSchemaSchema = object({
17791
- id: PipelineSlotSchema,
17792
- label: string(),
17793
- priority: number(),
17794
- parentSlot: PipelineSlotSchema.nullable(),
17795
- addons: array(PipelineAddonSchemaSchema).readonly()
17796
- });
17797
- var PipelineSchemaSchema = object({
17798
- availableEngines: array(AvailableEngineSchema).readonly(),
17799
- selectedEngine: PipelineEngineChoiceSchema,
17800
- slots: array(PipelineSlotSchemaSchema).readonly()
17801
- });
17802
- var EngineProvisioningSchema = object({
17803
- runtimeId: _enum([
17804
- "onnx",
17805
- "openvino",
17806
- "coreml",
17807
- "edgetpu"
17808
- ]).nullable(),
17809
- device: string().nullable(),
17810
- state: _enum([
17811
- "idle",
17812
- "installing",
17813
- "verifying",
17814
- "ready",
17815
- "failed"
17816
- ]),
17817
- progress: number().optional(),
17818
- error: string().optional(),
17819
- nextRetryAt: number().optional(),
17820
- /**
17821
- * Gate A (config-correctness gate at engine change): human-readable
17822
- * config issues surfaced EAGERLY when the node's engine changes — model
17823
- * substitutions ("chose X, running Y") and zero-build steps ("no model
17824
- * has a <format> build"). Additive/optional: informational only, never
17825
- * enforced here — `assertEngineReady` (readiness) still gates inference.
17826
- * Absent/empty when the node-default tree resolves cleanly.
17827
- */
17828
- configIssues: array(string()).optional()
17829
- });
17830
- var PipelineStepInputSchema = lazy(() => object({
17831
- addonId: string(),
17832
- modelId: string().optional(),
17833
- enabled: boolean().default(true),
17834
- children: array(PipelineStepInputSchema).optional(),
17835
- settings: record(string(), unknown()).optional(),
17836
- jumpDeviceKey: string().optional()
17837
- }));
17838
- var ModelSubstitutionSchema = object({
17839
- addonId: string(),
17840
- chosen: string(),
17841
- running: string(),
17842
- format: string()
17843
- });
17844
- var PipelineValidationIssueSchema = object({
17845
- addonId: string(),
17846
- kind: _enum(["unknown-addon", "no-format-build"]),
17847
- detail: string()
17848
- });
17849
- var PipelineValidationResultSchema = object({
17850
- ok: boolean(),
17851
- issues: array(PipelineValidationIssueSchema).readonly(),
17852
- substitutions: array(ModelSubstitutionSchema).readonly(),
17853
- /** The node's `currentEngine.format` this validation ran against. */
17854
- format: string()
17855
- });
17856
- var ReferenceImageEntrySchema = object({
17857
- filename: string(),
17858
- stepIds: array(string()).readonly().optional()
17859
- });
17860
- var ReferenceImageBodySchema = object({
17861
- base64: string(),
17862
- filename: string()
17863
- });
17864
- var ReferenceAudioEntrySchema = object({
17865
- filename: string(),
17866
- sizeKb: number()
17867
- });
17868
- var ReferenceAudioBodySchema = object({ base64: string() });
17869
- var AudioBackendSchema = object({
17870
- id: string(),
17871
- name: string(),
17872
- description: string(),
17873
- available: boolean(),
17874
- /**
17875
- * Raw classifier labels this backend can emit (e.g. YAMNet's
17876
- * 521-class set or Apple SoundAnalysis's 303-class set). Used by
17877
- * the benchmark UI to populate the `enabledMicroClasses` filter
17878
- * specific to the selected backend without a separate fetch.
17879
- */
17880
- rawLabels: array(string()).readonly().optional()
17881
- });
17882
- var AudioCapabilitiesSchema = object({
17883
- activeBackend: string(),
17884
- availableBackends: array(AudioBackendSchema).readonly(),
17885
- sampleRate: number(),
17886
- chunkDurationMs: number()
17887
- });
17888
- var DownloadModelResultSchema = object({
17889
- filePath: string(),
17890
- sizeMB: number(),
17891
- durationMs: number()
17892
- });
17893
- /**
17894
- * Wrapper carrying a single test run's result. Replaces the legacy
17895
- * ad-hoc `{labels: [{className, originalClass, score}]}` shape with the
17896
- * canonical `AudioResult` from the Phase 6 output rework: one
17897
- * `AudioDetection` per class above `minScore`, top-N candidates in
17898
- * `debug.alternateLabels['audio-classifier']`, per-source timings in
17899
- * `debug.stepTimings`. The outer `success`/`error` fields stay so the
17900
- * benchmark UI can still report a clean failure when the classifier
17901
- * cap isn't available.
17902
- */
17903
- var AudioTestResultSchema = object({
17904
- success: boolean(),
17905
- error: string().optional(),
17906
- frame: custom().optional()
17907
- });
17908
- var PipelineConfigBridge = custom();
17909
- var ConfigUISchemaBridge = custom();
17910
- var ConfigUISchemaNullableBridge = custom();
17911
- var InferenceCapabilitiesBridge = custom();
17912
- var ModelAvailabilityListBridge = custom();
17913
- var PipelineRunResultBridge = custom();
17914
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
17915
- modelId: string(),
17916
- settings: record(string(), unknown()).readonly()
17917
- }))), method(object({ steps: record(string(), object({
17918
- modelId: string(),
17919
- settings: record(string(), unknown()).readonly()
17920
- })) }), object({ success: literal(true) }), {
17921
- kind: "mutation",
17922
- auth: "admin"
17923
- }), method(object({ nodeId: string() }), object({
17924
- success: literal(true),
17925
- clearedDevices: number()
17926
- }), {
17927
- kind: "mutation",
17928
- auth: "admin"
17929
- }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
17930
- name: string(),
17931
- steps: array(PipelineTemplateStepSchema).readonly(),
17932
- engine: PipelineEngineChoiceSchema
17933
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
17934
- id: string(),
17935
- name: string().optional(),
17936
- steps: array(PipelineTemplateStepSchema).readonly().optional()
17937
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
17938
- addonId: string(),
17939
- modelId: string(),
17940
- format: ModelFormatSchema$1
17941
- }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
17942
- addonId: string(),
17943
- modelId: string(),
17944
- format: ModelFormatSchema$1
17945
- }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
17946
- engine: PipelineEngineChoiceSchema.optional(),
17947
- steps: array(PipelineStepInputSchema).min(1),
17948
- frame: FrameInputSchema.optional(),
17949
- /**
17950
- * Process-local lazy frame. Valid only when caller and provider resolve
17951
- * in the same execution-group process; split/cross-node callers use
17952
- * `frame`/`image` inline compatibility instead.
17953
- */
17954
- frameRef: FrameRefSchema.optional(),
17955
- /**
17956
- * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17957
- * the decoded pixels live in. One more member of the one-of
17958
- * frame/frameHandle/image/imageBase64/referenceImage group.
17959
- */
17960
- frameHandle: FrameHandleSchema.optional(),
17961
- imageBase64: string().optional(),
17962
- /**
17963
- * Binary JPEG bytes — preferred over `imageBase64` on internal
17964
- * hops (hub → forked worker via Moleculer MsgPack) because it
17965
- * skips the 33% base64 overhead + the per-call base64 decode on
17966
- * the detection-pipeline worker. Callers can pass either; exactly
17967
- * one of `frame`/`image`/`imageBase64`/`referenceImage` is required.
17968
- */
17969
- image: _instanceof(Uint8Array).optional(),
17970
- referenceImage: string().optional(),
17971
- deviceId: number().optional(),
17972
- sessionId: string().optional(),
17973
- /**
17974
- * Execution plane. 'full' (default) runs the whole tree — benchmark,
17975
- * reference-image, and detail-subtree calls. 'frame' is the live
17976
- * per-frame dispatch: ONLY root-plane steps run; crop children
17977
- * (inputClasses ≠ null) are skipped and served per-track via
17978
- * pipelineRunner.runDetailSubtree (two-plane design).
17979
- */
17980
- plane: _enum(["full", "frame"]).optional(),
17981
- /**
17982
- * Inference-device selector (Phase 2 multi-device). Format
17983
- * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
17984
- * Omitted ⇒ the runner's default device (current single-engine
17985
- * behaviour). Selects WHICH device pool of the node runs the call.
17986
- */
17987
- deviceKey: string().optional(),
17988
- /**
17989
- * Two-plane NATIVE child-crop reference. Set by `runDetailSubtree` ONLY
17990
- * when the parent crop was resolved from the frame's retained NATIVE
17991
- * surface (a frameHandle HIT). Lets the executor re-cut a LEAF crop
17992
- * child's ROI (plate-ocr, face-embedding, leaf classifiers) at native
17993
- * resolution from that surface — the SAME quality path faces already
17994
- * had — instead of the downscaled parent tile. `handle` keys the native
17995
- * surface (node-pinned to its owner); `cropFrameSpace` is the parent
17996
- * crop's padded/clamped rectangle in FRAME-space pixels, used to compose
17997
- * the executor's crop-normalized child ROI back into frame-normalized
17998
- * coordinates. Auxiliary to the image source (`image`/`frame`/…), NOT one
17999
- * of the mutually-exclusive image inputs. Absent ⇒ tile-crop children
18000
- * (today's behaviour on the fallback path).
18001
- */
18002
- nativeCropRef: NativeCropRefSchema.optional()
18003
- }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
18004
- engine: PipelineEngineChoiceSchema.optional(),
18005
- steps: array(PipelineStepInputSchema).min(1),
18006
- frames: array(FrameInputSchema).min(1).max(255),
18007
- deviceId: number().optional(),
18008
- sessionId: string().optional(),
18009
- /**
18010
- * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
18011
- * the batch to the Python pool's bench preprocess cache
18012
- * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
18013
- * preprocessed ONCE and every later inference is a pure-inference cache
18014
- * hit — the sustained-throughput run measures inference, not
18015
- * decode+preprocess+infer. Omitted/0 for live frames (all different →
18016
- * full preprocess every call, correct). Fresh per sustained run;
18017
- * released via `uncacheFrame`.
18018
- */
18019
- frameId: number().int().nonnegative().optional(),
18020
- /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
18021
- deviceKey: string().optional()
18022
- }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
18023
- data: _instanceof(Uint8Array),
18024
- width: number().int().positive(),
18025
- height: number().int().positive(),
18026
- format: _enum([
18027
- "rgb",
18028
- "bgr",
18029
- "gray"
18030
- ])
18031
- }), object({
18032
- frameId: number(),
18033
- width: number(),
18034
- height: number()
18035
- }), { kind: "mutation" }), method(object({
18036
- stepId: string(),
18037
- frameId: number().int()
18038
- }), record(string(), unknown()), { kind: "mutation" }), method(object({ frameId: number().int() }), _void(), { kind: "mutation" }), method(_void(), object({
18039
- batchMode: string(),
18040
- windowMs: number(),
18041
- maxBatchSize: number(),
18042
- concurrency: number()
18043
- })), method(_void(), array(object({
18044
- engineKey: string(),
18045
- engine: PipelineEngineChoiceSchema,
18046
- modelsLoaded: array(string()).readonly(),
18047
- inUseByCameras: array(number()).readonly(),
18048
- /**
18049
- * Origin of this resident factory.
18050
- * - `runtime` — main camera-serving engine (no idle TTL).
18051
- * - `warm-override` — benchmark/test override held in the warm
18052
- * cache; auto-disposed after the idle TTL.
18053
- * - `device-pool` — a concurrent per-device pool (Phase 2
18054
- * multi-device, keyed by `deviceKey`) resolved
18055
- * via `resolveDeviceFactory`. Runs alongside the
18056
- * `runtime` engine on a DIFFERENT accelerator
18057
- * (NPU / iGPU / Coral) — this is how the
18058
- * Engines tab shows all pools running at once.
18059
- */
18060
- kind: _enum([
18061
- "runtime",
18062
- "warm-override",
18063
- "device-pool"
18064
- ]),
18065
- /** Native pid of the underlying Python pool (null when no pool). */
18066
- poolPid: number().nullable(),
18067
- /** ms since this factory was last used (null when not warm-tracked). */
18068
- idleMs: number().nullable(),
18069
- /** Idle TTL after which `warm-override` factories self-evict (null when not applicable). */
18070
- idleTtlMs: number().nullable()
18071
- })).readonly()), method(object({ engine: PipelineEngineChoiceSchema }), object({ success: literal(true) }), {
18072
- kind: "mutation",
18073
- auth: "admin"
18074
- }), method(object({
18075
- engine: PipelineEngineChoiceSchema,
18076
- force: boolean().optional()
18077
- }), object({
18078
- success: boolean(),
18079
- reason: string().optional()
18080
- }), {
18081
- kind: "mutation",
18082
- auth: "admin"
18083
- }), method(_void(), array(ReferenceImageEntrySchema).readonly()), method(object({ filename: string() }), ReferenceImageBodySchema.nullable()), method(_void(), array(ReferenceAudioEntrySchema).readonly()), method(object({ filename: string() }), ReferenceAudioBodySchema.nullable()), method(_void(), AudioCapabilitiesSchema), method(object({
18084
- addonId: string(),
18085
- modelId: string(),
18086
- filename: string().optional(),
18087
- settings: record(string(), unknown()).optional()
18088
- }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
18089
18386
  object({
18090
18387
  activeCameras: number(),
18091
18388
  throttledCameras: number(),
@@ -18111,106 +18408,6 @@ var CameraMetricsSchema = object({
18111
18408
  });
18112
18409
  var CameraMetricsWithDeviceIdSchema = CameraMetricsSchema.extend({ deviceId: number() });
18113
18410
  /**
18114
- * Zone — pure geometry + identity. NO filtering behaviour.
18115
- *
18116
- * Zones describe **where** in the frame the operator wants to flag
18117
- * something; consumer-owned {@link ZoneRule} arrays describe **how**
18118
- * each pipeline stage uses them. Splitting the two means a single
18119
- * polygon "Driveway" can simultaneously back a motion-exclude rule,
18120
- * a detection-include rule on `['car']`, and an occupancy aggregate
18121
- * — without three duplicated polygons.
18122
- *
18123
- * Owned by the orchestrator addon (provider) and mirrored into the
18124
- * `zones` device-state slice on every mutation. Consumers
18125
- * (motion-wasm, pipeline-executor, analytics, admin UI) read either
18126
- * via `api.zones.listZones` (one-shot) or via `dev.state.zones` (live
18127
- * mirror with `onChanged`).
18128
- *
18129
- * Coordinates are normalised fractions of the frame (0–1) so zones
18130
- * survive resolution changes and stream profile switches.
18131
- *
18132
- * `kind` discriminates between full polygons (closed regions used
18133
- * for intrusion / occupancy filters) and tripwires (open 2-point
18134
- * line segments used for cross events). Onboard / firmware-reported
18135
- * zones (Reolink, ONVIF) are out of scope for now — see the deferred
18136
- * task list.
18137
- */
18138
- var ZoneKindEnum = _enum(["polygon", "tripwire"]);
18139
- /** Polygon vertex in fraction-of-frame coordinates (0–1). */
18140
- var PolygonPointSchema = object({
18141
- x: number(),
18142
- y: number()
18143
- });
18144
- /** A camera detection zone — pure geometry/identity. */
18145
- var ZoneSchema = object({
18146
- id: string(),
18147
- name: string(),
18148
- kind: ZoneKindEnum.default("polygon"),
18149
- /** Polygon vertices, fraction of frame (0–1). */
18150
- polygon: array(PolygonPointSchema).readonly(),
18151
- /** Visual color for UI rendering. */
18152
- color: string().default("#3b82f6")
18153
- });
18154
- /**
18155
- * Zones capability — per-camera CRUD over polygon detection zones.
18156
- *
18157
- * Provider lives in `addon-pipeline-orchestrator` (hub-only). Persists
18158
- * to per-device settings and mirrors into the `zones` device-state
18159
- * slice on every mutation, so downstream consumers can subscribe via
18160
- * `dev.state.zones.onChanged`.
18161
- *
18162
- * The cap surface only handles geometry + identity; filtering
18163
- * behaviour (per-class, include/exclude, threshold) lives in the
18164
- * consumer addons' rule arrays — see `ZoneRuleSchema` exported from
18165
- * `capabilities/schemas/zone-rule.js`.
18166
- */
18167
- var zonesCapability = {
18168
- name: "zones",
18169
- scope: "device",
18170
- mode: "singleton",
18171
- deviceTypes: [DeviceType.Camera],
18172
- methods: {
18173
- listZones: method(object({ deviceId: number() }), array(ZoneSchema).readonly()),
18174
- addZone: method(object({
18175
- deviceId: number(),
18176
- zone: ZoneSchema
18177
- }), _void(), {
18178
- kind: "mutation",
18179
- auth: "admin"
18180
- }),
18181
- removeZone: method(object({
18182
- deviceId: number(),
18183
- zoneId: string()
18184
- }), _void(), {
18185
- kind: "mutation",
18186
- auth: "admin"
18187
- }),
18188
- updateZone: method(object({
18189
- deviceId: number(),
18190
- zone: ZoneSchema
18191
- }), _void(), {
18192
- kind: "mutation",
18193
- auth: "admin"
18194
- })
18195
- },
18196
- /**
18197
- * Runtime-state slice — the live zone catalogue mirrored by the
18198
- * orchestrator on every CRUD mutation. Consumers read via
18199
- * `device.state.zones.value` / `.watch(...)` without round-tripping
18200
- * the cap, and the codegen DeviceProxy auto-wires the reactive
18201
- * handle. Slice shape is `{ zones: Zone[] }` so future extensions
18202
- * (e.g. zone groupings) can sit alongside the polygon list.
18203
- */
18204
- runtimeState: object({ zones: array(ZoneSchema).readonly() }),
18205
- /**
18206
- * Runtime-state durability: **restored** — written only on operator mutation, so a camera that never had one has nothing to re-derive from. This is the slice `zone-mirror-hydration.ts` exists to paper over.
18207
- *
18208
- * See `RuntimeStateDurability`. Enforced by
18209
- * `scripts/check-runtime-state-durability.ts`.
18210
- */
18211
- durability: "restored"
18212
- };
18213
- /**
18214
18411
  * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
18215
18412
  * decode worker resolves it against the RETAINED native frame's real pixel dims,
18216
18413
  * so the caller supplies only the detection-res bbox divided by the detection
@@ -20002,7 +20199,7 @@ method(object({
20002
20199
  * linking rather than produce an eternal token.
20003
20200
  */
20004
20201
  ttlSec: union([number().int().positive(), literal("never")]).optional()
20005
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
20202
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
20006
20203
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
20007
20204
  providerId: string().min(1),
20008
20205
  displayName: string().min(1),
@@ -20097,10 +20294,13 @@ var EvictResultSchema = object({
20097
20294
  /** True when the provider has nothing left it is willing to drop on this location. */
20098
20295
  exhausted: boolean()
20099
20296
  });
20100
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20297
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
20101
20298
  locationId: string(),
20102
20299
  targetBytes: number().int().positive()
20103
- }), EvictResultSchema, { kind: "mutation" });
20300
+ }), EvictResultSchema, {
20301
+ kind: "mutation",
20302
+ auth: "admin"
20303
+ });
20104
20304
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
20105
20305
  kind: "mutation",
20106
20306
  auth: "admin"
@@ -20160,26 +20360,50 @@ var ReadChunkInputSchema = object({
20160
20360
  length: number()
20161
20361
  });
20162
20362
  var EndDownloadInputSchema = object({ downloadId: string() });
20163
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20363
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20164
20364
  location: StorageLocationSchema,
20165
20365
  relativePath: string()
20166
- }), string()), method(object({
20366
+ }), string(), { auth: "admin" }), method(object({
20167
20367
  location: StorageLocationSchema,
20168
20368
  relativePath: string(),
20169
20369
  data: _instanceof(Uint8Array)
20170
- }), _void(), { kind: "mutation" }), method(object({
20370
+ }), _void(), {
20371
+ kind: "mutation",
20372
+ auth: "admin"
20373
+ }), method(object({
20171
20374
  location: StorageLocationSchema,
20172
20375
  relativePath: string()
20173
- }), _instanceof(Uint8Array)), method(object({
20376
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
20174
20377
  location: StorageLocationSchema,
20175
20378
  relativePath: string()
20176
- }), boolean()), method(object({
20379
+ }), boolean(), { auth: "admin" }), method(object({
20177
20380
  location: StorageLocationSchema,
20178
20381
  prefix: string().optional()
20179
- }), array(string()).readonly()), method(object({
20382
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
20180
20383
  location: StorageLocationSchema,
20181
20384
  relativePath: string()
20182
- }), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
20385
+ }), _void(), {
20386
+ kind: "mutation",
20387
+ auth: "admin"
20388
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20389
+ kind: "mutation",
20390
+ auth: "admin"
20391
+ }), method(WriteChunkInputSchema, _void(), {
20392
+ kind: "mutation",
20393
+ auth: "admin"
20394
+ }), method(FinalizeUploadInputSchema, _void(), {
20395
+ kind: "mutation",
20396
+ auth: "admin"
20397
+ }), method(AbortUploadInputSchema, _void(), {
20398
+ kind: "mutation",
20399
+ auth: "admin"
20400
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20401
+ kind: "mutation",
20402
+ auth: "admin"
20403
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20404
+ kind: "mutation",
20405
+ auth: "admin"
20406
+ });
20183
20407
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20184
20408
  var ProfileSettingsSchemaBridge = unknown().nullable();
20185
20409
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20481,7 +20705,8 @@ method(object({
20481
20705
  access: "create"
20482
20706
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20483
20707
  kind: "mutation",
20484
- access: "view"
20708
+ access: "view",
20709
+ auth: "admin"
20485
20710
  }), method(object({
20486
20711
  /** Required — the user the assertion belongs to (verified). */
20487
20712
  userId: string(),
@@ -20489,10 +20714,12 @@ method(object({
20489
20714
  response: record(string(), unknown())
20490
20715
  }), object({ verified: boolean() }), {
20491
20716
  kind: "mutation",
20492
- access: "view"
20717
+ access: "view",
20718
+ auth: "admin"
20493
20719
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20494
20720
  kind: "mutation",
20495
- access: "view"
20721
+ access: "view",
20722
+ auth: "admin"
20496
20723
  }), method(object({
20497
20724
  /** AuthenticationResponseJSON from the browser. */
20498
20725
  response: record(string(), unknown()) }), object({
@@ -20500,7 +20727,8 @@ response: record(string(), unknown()) }), object({
20500
20727
  userId: string().nullable()
20501
20728
  }), {
20502
20729
  kind: "mutation",
20503
- access: "view"
20730
+ access: "view",
20731
+ auth: "admin"
20504
20732
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20505
20733
  userId: string(),
20506
20734
  credentialId: string()
@@ -20672,7 +20900,19 @@ var VectorStatsResultSchema = object({
20672
20900
  /** False when the backend ranks approximately. */
20673
20901
  exact: boolean()
20674
20902
  });
20675
- method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
20903
+ method(VectorDeclareIndexInputSchema, _void(), {
20904
+ kind: "mutation",
20905
+ auth: "admin"
20906
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20907
+ kind: "mutation",
20908
+ auth: "admin"
20909
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20910
+ kind: "mutation",
20911
+ auth: "admin"
20912
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20913
+ kind: "mutation",
20914
+ auth: "admin"
20915
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20676
20916
  var ClipSchema = object({
20677
20917
  /** Opaque, provider-namespaced id. The default provider encodes the time
20678
20918
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -23125,7 +23365,27 @@ var MediaFileLiteSchema$1 = object({
23125
23365
  sizeBytes: number(),
23126
23366
  timestamp: number()
23127
23367
  });
23128
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23368
+ method(object({
23369
+ /**
23370
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23371
+ *
23372
+ * Default `false`, the same inversion `listRecentFaces` and
23373
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23374
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23375
+ * on the live hub the same day: four identities cost 40,979 B with the
23376
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23377
+ * four times and the viewer holds at `staleTime: 30_000`.
23378
+ *
23379
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23380
+ * the `event-media` plane serves that key `immutable` with an ETag.
23381
+ *
23382
+ * **This is an INPUT field, so it does not reach the addon until the
23383
+ * next train** — the hub router validates cap inputs against its own
23384
+ * compiled Zod and strips a key it does not know. Until then the
23385
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23386
+ * is what ships, and the opt-in becomes reachable when the train lands.
23387
+ */
23388
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23129
23389
  kind: "mutation",
23130
23390
  auth: "admin"
23131
23391
  }), method(object({
@@ -26015,8 +26275,10 @@ var PlateInfoSchema = object({
26015
26275
  keyFrameMediaKey: string().optional(),
26016
26276
  base64: string().optional(),
26017
26277
  /**
26018
- * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26019
- * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26278
+ * Same crop as a data-plane URL, always present when the plate has a stored
26279
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26280
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26281
+ * left at its `true` default.
26020
26282
  */
26021
26283
  cropUrl: string().optional()
26022
26284
  });
@@ -26036,14 +26298,34 @@ var PlateClusterSchema = object({
26036
26298
  });
26037
26299
  method(object({
26038
26300
  deviceId: number().int().optional(),
26039
- limit: number().int().positive().optional()
26301
+ limit: number().int().positive().optional(),
26302
+ /**
26303
+ * Inline the base64 crop on every row. Default `true` — the existing
26304
+ * behaviour, kept so no caller breaks.
26305
+ *
26306
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26307
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26308
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26309
+ * metadata without them — and the browser then caches the images.
26310
+ *
26311
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26312
+ * plates were the one gallery list left without it.
26313
+ *
26314
+ * **This is an INPUT field, so it does not reach the addon until the
26315
+ * next train.** The hub router validates cap inputs against its own
26316
+ * compiled Zod and strips a key it does not know. Until the train
26317
+ * ships, sending `false` is harmless and keeps the crops inline.
26318
+ */
26319
+ includeCrops: boolean().optional()
26040
26320
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
26041
26321
  deviceId: number().int(),
26042
26322
  trackId: string()
26043
26323
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
26044
26324
  text: string().min(1),
26045
26325
  maxDistance: number().int().min(0).optional(),
26046
- limit: number().int().positive().optional()
26326
+ limit: number().int().positive().optional(),
26327
+ /** See `listPlates.includeCrops`. Default `true`. */
26328
+ includeCrops: boolean().optional()
26047
26329
  }), array(PlateInfoSchema).readonly()), method(object({
26048
26330
  maxDistance: number().int().min(0).optional(),
26049
26331
  minClusterSize: number().int().min(2).optional(),
@@ -26057,7 +26339,13 @@ method(object({
26057
26339
  }), method(object({ plateId: string() }), _void(), {
26058
26340
  kind: "mutation",
26059
26341
  auth: "admin"
26060
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26342
+ }), method(object({
26343
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26344
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26345
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26346
+ * INPUT field: stripped by the hub router until the train ships, which
26347
+ * resolves to `false` and is exactly the intended default. */
26348
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26061
26349
  kind: "mutation",
26062
26350
  auth: "admin"
26063
26351
  }), method(object({
@@ -27578,92 +27866,6 @@ var sceneMonitorCapability = {
27578
27866
  durability: "session"
27579
27867
  };
27580
27868
  /**
27581
- * Per-stage gating mode applied to the zones a rule references.
27582
- *
27583
- * - `include`: the rule contributes to a **whitelist** for its stage.
27584
- * When at least one `include` rule fires for a stage, only entities
27585
- * inside one of those zones pass that stage.
27586
- * - `exclude`: the rule contributes to a **blacklist** for its stage.
27587
- * Entities inside one of those zones are dropped at that stage.
27588
- *
27589
- * `monitor`-style observation (count without filtering) is not a rule
27590
- * mode — zones without any matching rule are observed naturally by
27591
- * `zone-analytics` (live snapshot + history), so an "I just want to
27592
- * count, not filter" use case needs no rule at all.
27593
- */
27594
- var ZoneRuleModeEnum = _enum(["include", "exclude"]);
27595
- /**
27596
- * Per-consumer rule that references existing zones (geometry) and
27597
- * defines how a specific pipeline stage should treat them. Each
27598
- * consumer addon owns its own `ZoneRule[]` array in its per-device
27599
- * settings:
27600
- *
27601
- * - `addon-motion-wasm` → `motionZoneRules: ZoneRule[]` (motion stage)
27602
- * - `addon-detection-pipeline` → `detectionZoneRules: ZoneRule[]` (detection stage)
27603
- * - future: notification rules, audio gating, etc.
27604
- *
27605
- * One rule applies to N zones (`zoneIds[]`) so the operator can
27606
- * express "ignore motion in ALL of {garden, street}" with a single
27607
- * rule. `classFilter` narrows the rule to specific object classes —
27608
- * "drop person detections in the street, but keep cars" is one
27609
- * `exclude` rule with `classFilter: ['person']`.
27610
- *
27611
- * `enabled` is a soft toggle — the operator can keep the rule
27612
- * configured but inert without deleting it.
27613
- */
27614
- var ZoneRuleSchema = object({
27615
- /** Stable rule id — survives edits, used by the UI for diffing. */
27616
- id: string(),
27617
- /** Optional human-readable label rendered in the rule editor. */
27618
- name: string().optional(),
27619
- /** Zones this rule targets. The rule's `mode` applies to ALL
27620
- * listed zones (OR-set: a detection in any one of them counts).
27621
- * At least one zone id required — a rule with no targets is a
27622
- * configuration mistake and the form validator rejects it. */
27623
- zoneIds: array(string()).min(1).readonly(),
27624
- mode: ZoneRuleModeEnum,
27625
- /**
27626
- * Class names this rule applies to. Empty / undefined ⇒ rule
27627
- * applies to every class. Class strings match the `macroClass`
27628
- * field on detections (e.g. `person`, `car`, `dog`).
27629
- */
27630
- classFilter: array(string()).readonly().optional(),
27631
- /**
27632
- * Minimum bbox/mask overlap (0–1) with any of the rule's zones
27633
- * required to consider an entity "in the zone". Defaults to the
27634
- * consumer's stage default when omitted. Kept for back-compat with
27635
- * existing per-rule overrides; new operators pick the value via
27636
- * `bboxInclusionPct` (operator-friendly 0–100). Whichever field is
27637
- * set, the lower-level engine reads it as a 0–1 fraction.
27638
- */
27639
- overlapThreshold: number().min(0).max(1).optional(),
27640
- /**
27641
- * Operator-friendly version of `overlapThreshold` — the percentage
27642
- * of the detection's bbox that must lie inside the zone for the
27643
- * rule to match. Documented default is 85%; the engine substitutes
27644
- * that when the field is omitted (kept optional so existing rules
27645
- * stored without it stay valid).
27646
- *
27647
- * When BOTH `overlapThreshold` and `bboxInclusionPct` are set on a
27648
- * rule, the engine prefers `bboxInclusionPct` because it's the
27649
- * field exposed in the UI. Internally both feed the same gate.
27650
- */
27651
- bboxInclusionPct: number().min(0).max(100).optional(),
27652
- /**
27653
- * When `true` and a detection has a segmentation mask, use the
27654
- * mask for overlap instead of the bbox. Detection-stage only;
27655
- * motion rules ignore this field.
27656
- */
27657
- preferMask: boolean().optional(),
27658
- /**
27659
- * Soft-toggle: `false` disables the rule without deleting it.
27660
- * Defaults to `true` so operators creating a rule via the UI
27661
- * see it active immediately.
27662
- */
27663
- enabled: boolean().default(true)
27664
- });
27665
- array(ZoneRuleSchema).readonly();
27666
- /**
27667
27869
  * Script-runner cap. Models HA `script.*` entities on
27668
27870
  * `DeviceType.Script`. A Script is a pre-recorded action sequence
27669
27871
  * that can be invoked imperatively — optionally with a variables
@@ -33316,6 +33518,12 @@ Object.freeze({
33316
33518
  addonId: null,
33317
33519
  access: "create"
33318
33520
  },
33521
+ "pipelineAnalytics.cancelRelocateMedia": {
33522
+ capName: "pipeline-analytics",
33523
+ capScope: "device",
33524
+ addonId: null,
33525
+ access: "create"
33526
+ },
33319
33527
  "pipelineAnalytics.cancelStorageMigrationMove": {
33320
33528
  capName: "pipeline-analytics",
33321
33529
  capScope: "device",
@@ -33490,6 +33698,12 @@ Object.freeze({
33490
33698
  addonId: null,
33491
33699
  access: "view"
33492
33700
  },
33701
+ "pipelineAnalytics.listRelocateMediaJobs": {
33702
+ capName: "pipeline-analytics",
33703
+ capScope: "device",
33704
+ addonId: null,
33705
+ access: "view"
33706
+ },
33493
33707
  "pipelineAnalytics.listRetrainAnnotations": {
33494
33708
  capName: "pipeline-analytics",
33495
33709
  capScope: "device",
@@ -33568,6 +33782,12 @@ Object.freeze({
33568
33782
  addonId: null,
33569
33783
  access: "create"
33570
33784
  },
33785
+ "pipelineAnalytics.relocateMedia": {
33786
+ capName: "pipeline-analytics",
33787
+ capScope: "device",
33788
+ addonId: null,
33789
+ access: "create"
33790
+ },
33571
33791
  "pipelineAnalytics.restageRetrainTrack": {
33572
33792
  capName: "pipeline-analytics",
33573
33793
  capScope: "device",
@@ -33580,6 +33800,12 @@ Object.freeze({
33580
33800
  addonId: null,
33581
33801
  access: "create"
33582
33802
  },
33803
+ "pipelineAnalytics.runReplayFrameProcessor": {
33804
+ capName: "pipeline-analytics",
33805
+ capScope: "device",
33806
+ addonId: null,
33807
+ access: "create"
33808
+ },
33583
33809
  "pipelineAnalytics.saveRetrainAnnotations": {
33584
33810
  capName: "pipeline-analytics",
33585
33811
  capScope: "device",
@@ -33712,6 +33938,12 @@ Object.freeze({
33712
33938
  addonId: null,
33713
33939
  access: "view"
33714
33940
  },
33941
+ "pipelineExecutor.getInferenceDeviceHealth": {
33942
+ capName: "pipeline-executor",
33943
+ capScope: "system",
33944
+ addonId: null,
33945
+ access: "view"
33946
+ },
33715
33947
  "pipelineExecutor.getOrchestratorConfigSchema": {
33716
33948
  capName: "pipeline-executor",
33717
33949
  capScope: "system",
@@ -33784,6 +34016,12 @@ Object.freeze({
33784
34016
  addonId: null,
33785
34017
  access: "view"
33786
34018
  },
34019
+ "pipelineExecutor.rearmInferenceDevice": {
34020
+ capName: "pipeline-executor",
34021
+ capScope: "system",
34022
+ addonId: null,
34023
+ access: "create"
34024
+ },
33787
34025
  "pipelineExecutor.runAudioTest": {
33788
34026
  capName: "pipeline-executor",
33789
34027
  capScope: "system",
@@ -37032,6 +37270,11 @@ Object.freeze({
37032
37270
  form: "single",
37033
37271
  optional: false
37034
37272
  }],
37273
+ "pipelineAnalytics.runReplayFrameProcessor": [{
37274
+ name: "deviceId",
37275
+ form: "single",
37276
+ optional: false
37277
+ }],
37035
37278
  "pipelineAnalytics.saveRetrainAnnotations": [{
37036
37279
  name: "deviceId",
37037
37280
  form: "single",
@@ -44431,7 +44674,10 @@ function sanitizeProfileSettings(profileId, raw) {
44431
44674
  showContainers: true,
44432
44675
  showSensors: true
44433
44676
  };
44434
- for (const plugin of GLANCES_PLUGINS) if (typeof bag[plugin.key] === "boolean") out[plugin.key] = bag[plugin.key];
44677
+ for (const plugin of GLANCES_PLUGINS) {
44678
+ const value = bag[plugin.key];
44679
+ if (typeof value === "boolean") out[plugin.key] = value;
44680
+ }
44435
44681
  return out;
44436
44682
  }
44437
44683
  function profileSettingsToArgs(profileId, settings) {