@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.mjs CHANGED
@@ -6698,7 +6698,7 @@ function method(input, output, options) {
6698
6698
  input,
6699
6699
  output,
6700
6700
  kind: options?.kind ?? "query",
6701
- auth: options?.auth ?? "protected",
6701
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6702
6702
  ...options?.access !== void 0 ? { access: options.access } : {},
6703
6703
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6704
6704
  timeoutMs: options?.timeoutMs
@@ -6722,7 +6722,7 @@ function event(data) {
6722
6722
  }
6723
6723
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6724
6724
  var VersionOutputSchema$1 = object({ version: string() });
6725
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6725
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6726
6726
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6727
6727
  DeviceType["Camera"] = "camera";
6728
6728
  DeviceType["Hub"] = "hub";
@@ -7043,7 +7043,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7043
7043
  }({});
7044
7044
  var StaticDirOutputSchema = object({ staticDir: string() });
7045
7045
  var VersionOutputSchema = object({ version: string() });
7046
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7046
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7047
7047
  /**
7048
7048
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7049
7049
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7677,24 +7677,6 @@ var RecordingRetentionSchema = object({
7677
7677
  maxSizeGb: number().min(0).optional()
7678
7678
  });
7679
7679
  /**
7680
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7681
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7682
- * previews at. Five graduated steps; absent on a config = `standard` (the
7683
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7684
- *
7685
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7686
- * Each window's index sidecar carries its own tile dims, so a camera whose
7687
- * preset changed over time renders every historical window at the dims it was
7688
- * written with.
7689
- */
7690
- var ScrubThumbnailPresetSchema = _enum([
7691
- "minimal",
7692
- "low",
7693
- "standard",
7694
- "high",
7695
- "max"
7696
- ]);
7697
- /**
7698
7680
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7699
7681
  *
7700
7682
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7702,7 +7684,11 @@ var ScrubThumbnailPresetSchema = _enum([
7702
7684
  * other field is a storage knob (profiles, segment length, retention, scrub).
7703
7685
  *
7704
7686
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7705
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7687
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7688
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7689
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7690
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7691
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7706
7692
  * A stale caller must fail loudly — silently stripping its legacy intent would
7707
7693
  * persist a band-less config, i.e. silently stop recording the camera.
7708
7694
  */
@@ -7725,14 +7711,7 @@ var RecordingConfigSchema = object({
7725
7711
  * "off" is the absence of a covering band, never a band value.
7726
7712
  */
7727
7713
  bands: array(RecordingBandSchema).default([]),
7728
- retention: RecordingRetentionSchema.optional(),
7729
- /**
7730
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7731
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7732
- * windows only — existing sheets are immutable, and each window's index
7733
- * carries its own tile dims so mixed-preset history renders correctly.
7734
- */
7735
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7714
+ retention: RecordingRetentionSchema.optional()
7736
7715
  }).strict();
7737
7716
  /**
7738
7717
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7808,10 +7787,11 @@ var RelocateFootageInputSchema = object({
7808
7787
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7809
7788
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7810
7789
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7811
- var StorageMigrationMediaMoveInputSchema = object({
7790
+ var RelocateMediaInputSchema = object({
7812
7791
  toLocationId: string(),
7813
7792
  throttleMbps: number().min(1).max(1e3).optional()
7814
- }).extend({ leaseId: string().min(1) });
7793
+ });
7794
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7815
7795
  /** The independently selectable logical storage classes. `recordings`
7816
7796
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7817
7797
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8106,7 +8086,26 @@ var LabelDefinitionSchema = object({
8106
8086
  description: string().optional(),
8107
8087
  icon: string().optional()
8108
8088
  });
8109
- var ClassMapDefinitionSchema = object({
8089
+ /**
8090
+ * Wire schema for a per-model CATALOG classMap override
8091
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8092
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8093
+ * detection pipeline executor actually routes.
8094
+ *
8095
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8096
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8097
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8098
+ * enum) — the two used to share the name `ClassMapDefinition`/
8099
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8100
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8101
+ * are not: it is two different concepts colliding on a name. Keep this type
8102
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8103
+ * would either narrow every `ClassMapDefinition` consumer to the four
8104
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8105
+ * schema exists for (see the "rejects a classMap whose target is not a
8106
+ * detection macro" test in `model-catalog-schema.test.ts`).
8107
+ */
8108
+ var DetectionCatalogClassMapSchema = object({
8110
8109
  mapping: record(string(), _enum([
8111
8110
  "person",
8112
8111
  "vehicle",
@@ -8311,7 +8310,7 @@ var ModelCatalogEntrySchema = object({
8311
8310
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8312
8311
  * labels already ARE the CamStack macros (Scrypted identity map).
8313
8312
  */
8314
- classMap: ClassMapDefinitionSchema.optional()
8313
+ classMap: DetectionCatalogClassMapSchema.optional()
8315
8314
  });
8316
8315
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8317
8316
  format: literal("openvino"),
@@ -8341,7 +8340,7 @@ var ModelConvertMetadataSchema = object({
8341
8340
  "segmentation"
8342
8341
  ]),
8343
8342
  faceAlignment: boolean().optional(),
8344
- classMap: ClassMapDefinitionSchema.optional()
8343
+ classMap: DetectionCatalogClassMapSchema.optional()
8345
8344
  });
8346
8345
  var ConvertResultSchema = object({
8347
8346
  entry: ModelCatalogEntrySchema,
@@ -9204,7 +9203,7 @@ var AddonPageDeclarationSchema = object({
9204
9203
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9205
9204
  sectionLabel: string().optional()
9206
9205
  });
9207
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9206
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9208
9207
  var AddonHttpRouteSchema = object({
9209
9208
  method: _enum([
9210
9209
  "GET",
@@ -9439,7 +9438,7 @@ var WidgetMetadataSchema = object({
9439
9438
  defaultColumns: number().int().min(1).max(12).default(6),
9440
9439
  defaultRows: number().int().min(1).max(12).default(1)
9441
9440
  });
9442
- method(_void(), array(WidgetMetadataSchema).readonly());
9441
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9443
9442
  /**
9444
9443
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9445
9444
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11063,7 +11062,7 @@ var CustomModelDescriptorSchema = object({
11063
11062
  stepId: string(),
11064
11063
  entry: ModelCatalogEntrySchema
11065
11064
  });
11066
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11065
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11067
11066
  /**
11068
11067
  * Query filter for settings-store collections.
11069
11068
  */
@@ -11150,7 +11149,8 @@ method(object({
11150
11149
  }), _void(), { kind: "mutation" }), method(object({
11151
11150
  namespace: string().optional(),
11152
11151
  collection: string(),
11153
- filter: QueryFilterSchema.optional()
11152
+ filter: QueryFilterSchema.optional(),
11153
+ columns: array(string()).readonly().optional()
11154
11154
  }), array(SettingsRecordSchema).readonly()), method(object({
11155
11155
  namespace: string().optional(),
11156
11156
  collection: string(),
@@ -11213,46 +11213,87 @@ var EngineInfoSchema = object({
11213
11213
  kind: _enum(["relational", "vector"]),
11214
11214
  displayName: string()
11215
11215
  });
11216
- method(_void(), EngineInfoSchema), method(object({
11216
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11217
11217
  namespace: string().optional(),
11218
11218
  collection: string(),
11219
11219
  key: string()
11220
- }), unknown()), method(object({
11220
+ }), unknown(), { auth: "admin" }), method(object({
11221
11221
  namespace: string().optional(),
11222
11222
  collection: string(),
11223
11223
  key: string(),
11224
11224
  value: unknown()
11225
- }), _void(), { kind: "mutation" }), method(object({
11225
+ }), _void(), {
11226
+ kind: "mutation",
11227
+ auth: "admin"
11228
+ }), method(object({
11226
11229
  namespace: string().optional(),
11227
11230
  collection: string(),
11228
- filter: QueryFilterSchema.optional()
11229
- }), array(SettingsRecordSchema).readonly()), method(object({
11231
+ filter: QueryFilterSchema.optional(),
11232
+ /**
11233
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11234
+ *
11235
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11236
+ * was wrong — corrected 2026-08-26 after the hop map
11237
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11238
+ * There is **no Zod parse at all** between the door and the engine: the
11239
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11240
+ * field declared here reaches `SqliteSettingsBackend` either way.
11241
+ *
11242
+ * What actually lost `columns` was the THIRD declaration of this shape:
11243
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11244
+ * interface the engine destructures from. The field existed on both
11245
+ * schemas and the engine still never read it, because nothing checks a
11246
+ * registered provider against `InferProvider<cap>` —
11247
+ * `ProviderRegistration.provider` is typed `object`.
11248
+ *
11249
+ * It is declared here anyway, and must stay in step with
11250
+ * `settings-store.query`: a caller reading only the cap definitions has
11251
+ * to be able to see that this call carries a projection.
11252
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11253
+ */
11254
+ columns: array(string()).readonly().optional()
11255
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11230
11256
  namespace: string().optional(),
11231
11257
  collection: string(),
11232
11258
  record: SettingsRecordSchema
11233
- }), _void(), { kind: "mutation" }), method(object({
11259
+ }), _void(), {
11260
+ kind: "mutation",
11261
+ auth: "admin"
11262
+ }), method(object({
11234
11263
  namespace: string().optional(),
11235
11264
  collection: string(),
11236
11265
  id: string(),
11237
11266
  data: record(string(), unknown())
11238
- }), _void(), { kind: "mutation" }), method(object({
11267
+ }), _void(), {
11268
+ kind: "mutation",
11269
+ auth: "admin"
11270
+ }), method(object({
11239
11271
  namespace: string().optional(),
11240
11272
  collection: string(),
11241
11273
  key: string()
11242
- }), _void(), { kind: "mutation" }), method(object({
11274
+ }), _void(), {
11275
+ kind: "mutation",
11276
+ auth: "admin"
11277
+ }), method(object({
11243
11278
  namespace: string().optional(),
11244
11279
  collection: string(),
11245
11280
  filter: MutationFilterSchema
11246
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11281
+ }), object({ deleted: number().int() }), {
11282
+ kind: "mutation",
11283
+ auth: "admin"
11284
+ }), method(object({
11247
11285
  namespace: string().optional(),
11248
11286
  collection: string(),
11249
11287
  filter: MutationFilterSchema,
11250
11288
  data: record(string(), unknown())
11251
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11289
+ }), object({ updated: number().int() }), {
11290
+ kind: "mutation",
11291
+ auth: "admin"
11292
+ }), method(object({
11252
11293
  namespace: string().optional(),
11253
11294
  collection: string(),
11254
11295
  filter: QueryFilterSchema.optional()
11255
- }), number()), method(object({
11296
+ }), number(), { auth: "admin" }), method(object({
11256
11297
  namespace: string().optional(),
11257
11298
  collection: string(),
11258
11299
  field: string(),
@@ -11262,15 +11303,18 @@ method(_void(), EngineInfoSchema), method(object({
11262
11303
  }), array(object({
11263
11304
  bucket: number().int(),
11264
11305
  count: number().int()
11265
- })).readonly()), method(object({
11306
+ })).readonly(), { auth: "admin" }), method(object({
11266
11307
  namespace: string().optional(),
11267
11308
  collection: string()
11268
- }), boolean()), method(object({
11309
+ }), boolean(), { auth: "admin" }), method(object({
11269
11310
  namespace: string().optional(),
11270
11311
  collection: string(),
11271
11312
  columns: array(CollectionColumnSchema).readonly(),
11272
11313
  indexes: array(CollectionIndexSchema).readonly().optional()
11273
- }), _void(), { kind: "mutation" });
11314
+ }), _void(), {
11315
+ kind: "mutation",
11316
+ auth: "admin"
11317
+ });
11274
11318
  /**
11275
11319
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11276
11320
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -12505,7 +12549,7 @@ method(object({
12505
12549
  crop: _instanceof(Uint8Array),
12506
12550
  width: number(),
12507
12551
  height: number()
12508
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12552
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12509
12553
  /**
12510
12554
  * filesystem-browse — per-node capability for browsing the node's local
12511
12555
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12798,19 +12842,22 @@ method(LlmGenerateBaseInputSchema.extend({
12798
12842
  runtime: ManagedRuntimeConfigSchema,
12799
12843
  /** The managed profile's timeout, threaded by the hub provider. */
12800
12844
  timeoutMs: number().int().positive().optional()
12801
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12845
+ }), LlmGenerateResultSchema, {
12846
+ kind: "mutation",
12847
+ auth: "admin"
12848
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12802
12849
  kind: "mutation",
12803
12850
  auth: "admin"
12804
12851
  }), method(object({}), _void(), {
12805
12852
  kind: "mutation",
12806
12853
  auth: "admin"
12807
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12854
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12808
12855
  kind: "mutation",
12809
12856
  auth: "admin"
12810
12857
  }), method(object({ file: string() }), _void(), {
12811
12858
  kind: "mutation",
12812
12859
  auth: "admin"
12813
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12860
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12814
12861
  /**
12815
12862
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12816
12863
  * methods concat-fan across providers; single-row methods route to ONE
@@ -16321,7 +16368,647 @@ var OauthIntegrationDescriptorSchema = object({
16321
16368
  */
16322
16369
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16323
16370
  });
16324
- method(_void(), OauthIntegrationDescriptorSchema);
16371
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16372
+ /**
16373
+ * Reference to the frame's retained NATIVE surface + the parent crop's placement
16374
+ * within the frame, so the executor can re-cut a leaf child ROI at native
16375
+ * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
16376
+ */
16377
+ var NativeCropRefSchema = object({
16378
+ /** Handle keying the retained native surface (node-pinned to its owner). */
16379
+ handle: FrameHandleSchema,
16380
+ /** The parent crop's padded/clamped rectangle in FRAME-space pixels. */
16381
+ cropFrameSpace: object({
16382
+ x: number(),
16383
+ y: number(),
16384
+ w: number(),
16385
+ h: number()
16386
+ })
16387
+ });
16388
+ object({
16389
+ crop: object({
16390
+ left: number(),
16391
+ top: number(),
16392
+ width: number().positive(),
16393
+ height: number().positive()
16394
+ }).optional(),
16395
+ content: object({
16396
+ width: number().int().positive(),
16397
+ height: number().int().positive()
16398
+ }),
16399
+ fit: _enum(["stretch", "contain"]),
16400
+ format: _enum([
16401
+ "rgb",
16402
+ "gray",
16403
+ "jpeg"
16404
+ ])
16405
+ });
16406
+ /**
16407
+ * Process-local frame identity. It is serializable so it can ride an in-process
16408
+ * capability call, but `registryId` deliberately prevents resolution in any
16409
+ * other process or execution group.
16410
+ */
16411
+ var FrameRefSchema = object({
16412
+ registryId: string().min(1),
16413
+ id: string().min(1),
16414
+ width: number().int().positive(),
16415
+ height: number().int().positive(),
16416
+ format: _enum(["rgb", "gray"]),
16417
+ timestamp: number(),
16418
+ capturedAt: number().optional()
16419
+ });
16420
+ var ModelFormatSchema$1 = _enum([
16421
+ "onnx",
16422
+ "coreml",
16423
+ "openvino",
16424
+ "tflite",
16425
+ "pt",
16426
+ "gguf"
16427
+ ]);
16428
+ var PipelineSlotSchema = _enum([
16429
+ "detector",
16430
+ "cropper",
16431
+ "classifier",
16432
+ "refiner",
16433
+ "audio-classifier"
16434
+ ]);
16435
+ var PipelineEngineChoiceSchema = object({
16436
+ runtime: _enum(["node", "python"]),
16437
+ backend: string(),
16438
+ format: ModelFormatSchema$1,
16439
+ device: string().optional()
16440
+ });
16441
+ var AvailableEngineSchema = object({
16442
+ engine: PipelineEngineChoiceSchema,
16443
+ devices: array(object({
16444
+ id: string(),
16445
+ label: string(),
16446
+ description: string().optional()
16447
+ })).readonly(),
16448
+ defaultDevice: string()
16449
+ });
16450
+ var PipelineDefaultStepSchema = lazy(() => object({
16451
+ addonId: string(),
16452
+ addonName: string(),
16453
+ slot: PipelineSlotSchema,
16454
+ inputClasses: array(string()).readonly(),
16455
+ outputClasses: array(string()).readonly(),
16456
+ enabled: boolean(),
16457
+ modelId: string(),
16458
+ children: array(PipelineDefaultStepSchema).readonly(),
16459
+ group: string().optional(),
16460
+ settings: record(string(), unknown()).optional()
16461
+ }));
16462
+ var PipelineTemplateStepSchema = lazy(() => object({
16463
+ addonId: string(),
16464
+ enabled: boolean(),
16465
+ modelId: string(),
16466
+ children: array(PipelineTemplateStepSchema).readonly(),
16467
+ settings: record(string(), unknown()).optional()
16468
+ }));
16469
+ var PipelineTemplateSchema$1 = object({
16470
+ id: string(),
16471
+ name: string(),
16472
+ createdAt: string(),
16473
+ updatedAt: string(),
16474
+ engine: PipelineEngineChoiceSchema,
16475
+ steps: array(PipelineTemplateStepSchema).readonly()
16476
+ });
16477
+ var PipelineModelOptionSchema = object({
16478
+ id: string(),
16479
+ name: string(),
16480
+ formats: record(string(), object({
16481
+ downloaded: boolean(),
16482
+ sizeMB: number()
16483
+ })),
16484
+ group: ModelVariantGroupSchema.optional(),
16485
+ legacy: boolean().optional(),
16486
+ provider: ModelProviderIdSchema.optional()
16487
+ });
16488
+ var ConfigFieldBridge = custom();
16489
+ var PipelineAddonSchemaSchema = object({
16490
+ id: string(),
16491
+ name: string(),
16492
+ slot: PipelineSlotSchema,
16493
+ inputClasses: array(string()).readonly(),
16494
+ outputClasses: array(string()).readonly(),
16495
+ childSlots: array(PipelineSlotSchema).readonly(),
16496
+ models: array(PipelineModelOptionSchema).readonly(),
16497
+ defaultModelId: string(),
16498
+ defaultModelIdByFormat: record(string(), string()).optional(),
16499
+ enabledByDefault: boolean().optional(),
16500
+ backfillIntoExistingOverrides: boolean().optional(),
16501
+ defaultConfidence: number(),
16502
+ group: string().optional(),
16503
+ configSchema: array(ConfigFieldBridge).readonly().optional()
16504
+ });
16505
+ var PipelineSlotSchemaSchema = object({
16506
+ id: PipelineSlotSchema,
16507
+ label: string(),
16508
+ priority: number(),
16509
+ parentSlot: PipelineSlotSchema.nullable(),
16510
+ addons: array(PipelineAddonSchemaSchema).readonly()
16511
+ });
16512
+ var PipelineSchemaSchema = object({
16513
+ availableEngines: array(AvailableEngineSchema).readonly(),
16514
+ selectedEngine: PipelineEngineChoiceSchema,
16515
+ slots: array(PipelineSlotSchemaSchema).readonly()
16516
+ });
16517
+ var EngineProvisioningSchema = object({
16518
+ runtimeId: _enum([
16519
+ "onnx",
16520
+ "openvino",
16521
+ "coreml",
16522
+ "edgetpu"
16523
+ ]).nullable(),
16524
+ device: string().nullable(),
16525
+ state: _enum([
16526
+ "idle",
16527
+ "installing",
16528
+ "verifying",
16529
+ "ready",
16530
+ "failed"
16531
+ ]),
16532
+ progress: number().optional(),
16533
+ error: string().optional(),
16534
+ nextRetryAt: number().optional(),
16535
+ /**
16536
+ * Gate A (config-correctness gate at engine change): human-readable
16537
+ * config issues surfaced EAGERLY when the node's engine changes — model
16538
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
16539
+ * has a <format> build"). Additive/optional: informational only, never
16540
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
16541
+ * Absent/empty when the node-default tree resolves cleanly.
16542
+ */
16543
+ configIssues: array(string()).optional()
16544
+ });
16545
+ var PipelineStepInputSchema = lazy(() => object({
16546
+ addonId: string(),
16547
+ modelId: string().optional(),
16548
+ enabled: boolean().default(true),
16549
+ children: array(PipelineStepInputSchema).optional(),
16550
+ settings: record(string(), unknown()).optional(),
16551
+ jumpDeviceKey: string().optional()
16552
+ }));
16553
+ var ModelSubstitutionSchema = object({
16554
+ addonId: string(),
16555
+ chosen: string(),
16556
+ running: string(),
16557
+ format: string()
16558
+ });
16559
+ var PipelineValidationIssueSchema = object({
16560
+ addonId: string(),
16561
+ kind: _enum(["unknown-addon", "no-format-build"]),
16562
+ detail: string()
16563
+ });
16564
+ var PipelineValidationResultSchema = object({
16565
+ ok: boolean(),
16566
+ issues: array(PipelineValidationIssueSchema).readonly(),
16567
+ substitutions: array(ModelSubstitutionSchema).readonly(),
16568
+ /** The node's `currentEngine.format` this validation ran against. */
16569
+ format: string()
16570
+ });
16571
+ var ReferenceImageEntrySchema = object({
16572
+ filename: string(),
16573
+ stepIds: array(string()).readonly().optional()
16574
+ });
16575
+ var ReferenceImageBodySchema = object({
16576
+ base64: string(),
16577
+ filename: string()
16578
+ });
16579
+ var ReferenceAudioEntrySchema = object({
16580
+ filename: string(),
16581
+ sizeKb: number()
16582
+ });
16583
+ var ReferenceAudioBodySchema = object({ base64: string() });
16584
+ var AudioBackendSchema = object({
16585
+ id: string(),
16586
+ name: string(),
16587
+ description: string(),
16588
+ available: boolean(),
16589
+ /**
16590
+ * Raw classifier labels this backend can emit (e.g. YAMNet's
16591
+ * 521-class set or Apple SoundAnalysis's 303-class set). Used by
16592
+ * the benchmark UI to populate the `enabledMicroClasses` filter
16593
+ * specific to the selected backend without a separate fetch.
16594
+ */
16595
+ rawLabels: array(string()).readonly().optional()
16596
+ });
16597
+ var AudioCapabilitiesSchema = object({
16598
+ activeBackend: string(),
16599
+ availableBackends: array(AudioBackendSchema).readonly(),
16600
+ sampleRate: number(),
16601
+ chunkDurationMs: number()
16602
+ });
16603
+ var DownloadModelResultSchema = object({
16604
+ filePath: string(),
16605
+ sizeMB: number(),
16606
+ durationMs: number()
16607
+ });
16608
+ /**
16609
+ * Wrapper carrying a single test run's result. Replaces the legacy
16610
+ * ad-hoc `{labels: [{className, originalClass, score}]}` shape with the
16611
+ * canonical `AudioResult` from the Phase 6 output rework: one
16612
+ * `AudioDetection` per class above `minScore`, top-N candidates in
16613
+ * `debug.alternateLabels['audio-classifier']`, per-source timings in
16614
+ * `debug.stepTimings`. The outer `success`/`error` fields stay so the
16615
+ * benchmark UI can still report a clean failure when the classifier
16616
+ * cap isn't available.
16617
+ */
16618
+ var AudioTestResultSchema = object({
16619
+ success: boolean(),
16620
+ error: string().optional(),
16621
+ frame: custom().optional()
16622
+ });
16623
+ var PipelineConfigBridge = custom();
16624
+ var ConfigUISchemaBridge = custom();
16625
+ var ConfigUISchemaNullableBridge = custom();
16626
+ var InferenceCapabilitiesBridge = custom();
16627
+ var ModelAvailabilityListBridge = custom();
16628
+ var PipelineRunResultBridge = custom();
16629
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
16630
+ modelId: string(),
16631
+ settings: record(string(), unknown()).readonly()
16632
+ }))), method(object({ steps: record(string(), object({
16633
+ modelId: string(),
16634
+ settings: record(string(), unknown()).readonly()
16635
+ })) }), object({ success: literal(true) }), {
16636
+ kind: "mutation",
16637
+ auth: "admin"
16638
+ }), method(object({ nodeId: string() }), object({
16639
+ success: literal(true),
16640
+ clearedDevices: number()
16641
+ }), {
16642
+ kind: "mutation",
16643
+ auth: "admin"
16644
+ }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
16645
+ /** `<backend>:<device>`, e.g. `openvino:gpu`. */
16646
+ deviceKey: string(),
16647
+ /**
16648
+ * `failed` — the per-device restart budget is exhausted; no pool
16649
+ * will be spawned until an operator re-arms it or the runner
16650
+ * respawns. `backoff` — under budget, waiting out the backoff (or
16651
+ * a cached pool observed dead and not yet condemned).
16652
+ */
16653
+ state: _enum(["failed", "backoff"]),
16654
+ /** Epoch ms of the death that produced this state. */
16655
+ since: number(),
16656
+ /** Pool deaths inside the current window. */
16657
+ deaths: number(),
16658
+ /** The last death's message. */
16659
+ lastError: string()
16660
+ })).readonly() })), method(object({
16661
+ nodeId: string(),
16662
+ deviceKey: string()
16663
+ }), object({ rearmed: boolean() }), {
16664
+ kind: "mutation",
16665
+ auth: "admin"
16666
+ }), 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({
16667
+ name: string(),
16668
+ steps: array(PipelineTemplateStepSchema).readonly(),
16669
+ engine: PipelineEngineChoiceSchema
16670
+ }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
16671
+ id: string(),
16672
+ name: string().optional(),
16673
+ steps: array(PipelineTemplateStepSchema).readonly().optional()
16674
+ }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
16675
+ addonId: string(),
16676
+ modelId: string(),
16677
+ format: ModelFormatSchema$1
16678
+ }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
16679
+ addonId: string(),
16680
+ modelId: string(),
16681
+ format: ModelFormatSchema$1
16682
+ }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
16683
+ engine: PipelineEngineChoiceSchema.optional(),
16684
+ steps: array(PipelineStepInputSchema).min(1),
16685
+ frame: FrameInputSchema.optional(),
16686
+ /**
16687
+ * Process-local lazy frame. Valid only when caller and provider resolve
16688
+ * in the same execution-group process; split/cross-node callers use
16689
+ * `frame`/`image` inline compatibility instead.
16690
+ */
16691
+ frameRef: FrameRefSchema.optional(),
16692
+ /**
16693
+ * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
16694
+ * the decoded pixels live in. One more member of the one-of
16695
+ * frame/frameHandle/image/imageBase64/referenceImage group.
16696
+ */
16697
+ frameHandle: FrameHandleSchema.optional(),
16698
+ imageBase64: string().optional(),
16699
+ /**
16700
+ * Binary JPEG bytes — preferred over `imageBase64` on internal
16701
+ * hops (hub → forked worker via Moleculer MsgPack) because it
16702
+ * skips the 33% base64 overhead + the per-call base64 decode on
16703
+ * the detection-pipeline worker. Callers can pass either; exactly
16704
+ * one of `frame`/`image`/`imageBase64`/`referenceImage` is required.
16705
+ */
16706
+ image: _instanceof(Uint8Array).optional(),
16707
+ referenceImage: string().optional(),
16708
+ deviceId: number().optional(),
16709
+ sessionId: string().optional(),
16710
+ /**
16711
+ * Execution plane. 'full' (default) runs the whole tree — benchmark,
16712
+ * reference-image, and detail-subtree calls. 'frame' is the live
16713
+ * per-frame dispatch: ONLY root-plane steps run; crop children
16714
+ * (inputClasses ≠ null) are skipped and served per-track via
16715
+ * pipelineRunner.runDetailSubtree (two-plane design).
16716
+ */
16717
+ plane: _enum(["full", "frame"]).optional(),
16718
+ /**
16719
+ * Inference-device selector (Phase 2 multi-device). Format
16720
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
16721
+ * Omitted ⇒ the runner's default device (current single-engine
16722
+ * behaviour). Selects WHICH device pool of the node runs the call.
16723
+ */
16724
+ deviceKey: string().optional(),
16725
+ /**
16726
+ * Two-plane NATIVE child-crop reference. Set by `runDetailSubtree` ONLY
16727
+ * when the parent crop was resolved from the frame's retained NATIVE
16728
+ * surface (a frameHandle HIT). Lets the executor re-cut a LEAF crop
16729
+ * child's ROI (plate-ocr, face-embedding, leaf classifiers) at native
16730
+ * resolution from that surface — the SAME quality path faces already
16731
+ * had — instead of the downscaled parent tile. `handle` keys the native
16732
+ * surface (node-pinned to its owner); `cropFrameSpace` is the parent
16733
+ * crop's padded/clamped rectangle in FRAME-space pixels, used to compose
16734
+ * the executor's crop-normalized child ROI back into frame-normalized
16735
+ * coordinates. Auxiliary to the image source (`image`/`frame`/…), NOT one
16736
+ * of the mutually-exclusive image inputs. Absent ⇒ tile-crop children
16737
+ * (today's behaviour on the fallback path).
16738
+ */
16739
+ nativeCropRef: NativeCropRefSchema.optional()
16740
+ }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
16741
+ engine: PipelineEngineChoiceSchema.optional(),
16742
+ steps: array(PipelineStepInputSchema).min(1),
16743
+ frames: array(FrameInputSchema).min(1).max(255),
16744
+ deviceId: number().optional(),
16745
+ sessionId: string().optional(),
16746
+ /**
16747
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
16748
+ * the batch to the Python pool's bench preprocess cache
16749
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
16750
+ * preprocessed ONCE and every later inference is a pure-inference cache
16751
+ * hit — the sustained-throughput run measures inference, not
16752
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
16753
+ * full preprocess every call, correct). Fresh per sustained run;
16754
+ * released via `uncacheFrame`.
16755
+ */
16756
+ frameId: number().int().nonnegative().optional(),
16757
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
16758
+ deviceKey: string().optional()
16759
+ }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
16760
+ data: _instanceof(Uint8Array),
16761
+ width: number().int().positive(),
16762
+ height: number().int().positive(),
16763
+ format: _enum([
16764
+ "rgb",
16765
+ "bgr",
16766
+ "gray"
16767
+ ])
16768
+ }), object({
16769
+ frameId: number(),
16770
+ width: number(),
16771
+ height: number()
16772
+ }), { kind: "mutation" }), method(object({
16773
+ stepId: string(),
16774
+ frameId: number().int()
16775
+ }), record(string(), unknown()), { kind: "mutation" }), method(object({ frameId: number().int() }), _void(), { kind: "mutation" }), method(_void(), object({
16776
+ batchMode: string(),
16777
+ windowMs: number(),
16778
+ maxBatchSize: number(),
16779
+ concurrency: number()
16780
+ })), method(_void(), array(object({
16781
+ engineKey: string(),
16782
+ engine: PipelineEngineChoiceSchema,
16783
+ modelsLoaded: array(string()).readonly(),
16784
+ inUseByCameras: array(number()).readonly(),
16785
+ /**
16786
+ * Origin of this resident factory.
16787
+ * - `runtime` — main camera-serving engine (no idle TTL).
16788
+ * - `warm-override` — benchmark/test override held in the warm
16789
+ * cache; auto-disposed after the idle TTL.
16790
+ * - `device-pool` — a concurrent per-device pool (Phase 2
16791
+ * multi-device, keyed by `deviceKey`) resolved
16792
+ * via `resolveDeviceFactory`. Runs alongside the
16793
+ * `runtime` engine on a DIFFERENT accelerator
16794
+ * (NPU / iGPU / Coral) — this is how the
16795
+ * Engines tab shows all pools running at once.
16796
+ */
16797
+ kind: _enum([
16798
+ "runtime",
16799
+ "warm-override",
16800
+ "device-pool"
16801
+ ]),
16802
+ /** Native pid of the underlying Python pool (null when no pool). */
16803
+ poolPid: number().nullable(),
16804
+ /** ms since this factory was last used (null when not warm-tracked). */
16805
+ idleMs: number().nullable(),
16806
+ /** Idle TTL after which `warm-override` factories self-evict (null when not applicable). */
16807
+ idleTtlMs: number().nullable()
16808
+ })).readonly()), method(object({ engine: PipelineEngineChoiceSchema }), object({ success: literal(true) }), {
16809
+ kind: "mutation",
16810
+ auth: "admin"
16811
+ }), method(object({
16812
+ engine: PipelineEngineChoiceSchema,
16813
+ force: boolean().optional()
16814
+ }), object({
16815
+ success: boolean(),
16816
+ reason: string().optional()
16817
+ }), {
16818
+ kind: "mutation",
16819
+ auth: "admin"
16820
+ }), 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({
16821
+ addonId: string(),
16822
+ modelId: string(),
16823
+ filename: string().optional(),
16824
+ settings: record(string(), unknown()).optional()
16825
+ }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
16826
+ /**
16827
+ * Per-stage gating mode applied to the zones a rule references.
16828
+ *
16829
+ * - `include`: the rule contributes to a **whitelist** for its stage.
16830
+ * When at least one `include` rule fires for a stage, only entities
16831
+ * inside one of those zones pass that stage.
16832
+ * - `exclude`: the rule contributes to a **blacklist** for its stage.
16833
+ * Entities inside one of those zones are dropped at that stage.
16834
+ *
16835
+ * `monitor`-style observation (count without filtering) is not a rule
16836
+ * mode — zones without any matching rule are observed naturally by
16837
+ * `zone-analytics` (live snapshot + history), so an "I just want to
16838
+ * count, not filter" use case needs no rule at all.
16839
+ */
16840
+ var ZoneRuleModeEnum = _enum(["include", "exclude"]);
16841
+ /**
16842
+ * Per-consumer rule that references existing zones (geometry) and
16843
+ * defines how a specific pipeline stage should treat them. Each
16844
+ * consumer addon owns its own `ZoneRule[]` array in its per-device
16845
+ * settings:
16846
+ *
16847
+ * - `addon-motion-wasm` → `motionZoneRules: ZoneRule[]` (motion stage)
16848
+ * - `addon-detection-pipeline` → `detectionZoneRules: ZoneRule[]` (detection stage)
16849
+ * - future: notification rules, audio gating, etc.
16850
+ *
16851
+ * One rule applies to N zones (`zoneIds[]`) so the operator can
16852
+ * express "ignore motion in ALL of {garden, street}" with a single
16853
+ * rule. `classFilter` narrows the rule to specific object classes —
16854
+ * "drop person detections in the street, but keep cars" is one
16855
+ * `exclude` rule with `classFilter: ['person']`.
16856
+ *
16857
+ * `enabled` is a soft toggle — the operator can keep the rule
16858
+ * configured but inert without deleting it.
16859
+ */
16860
+ var ZoneRuleSchema = object({
16861
+ /** Stable rule id — survives edits, used by the UI for diffing. */
16862
+ id: string(),
16863
+ /** Optional human-readable label rendered in the rule editor. */
16864
+ name: string().optional(),
16865
+ /** Zones this rule targets. The rule's `mode` applies to ALL
16866
+ * listed zones (OR-set: a detection in any one of them counts).
16867
+ * At least one zone id required — a rule with no targets is a
16868
+ * configuration mistake and the form validator rejects it. */
16869
+ zoneIds: array(string()).min(1).readonly(),
16870
+ mode: ZoneRuleModeEnum,
16871
+ /**
16872
+ * Class names this rule applies to. Empty / undefined ⇒ rule
16873
+ * applies to every class. Class strings match the `macroClass`
16874
+ * field on detections (e.g. `person`, `car`, `dog`).
16875
+ */
16876
+ classFilter: array(string()).readonly().optional(),
16877
+ /**
16878
+ * Minimum bbox/mask overlap (0–1) with any of the rule's zones
16879
+ * required to consider an entity "in the zone". Defaults to the
16880
+ * consumer's stage default when omitted. Kept for back-compat with
16881
+ * existing per-rule overrides; new operators pick the value via
16882
+ * `bboxInclusionPct` (operator-friendly 0–100). Whichever field is
16883
+ * set, the lower-level engine reads it as a 0–1 fraction.
16884
+ */
16885
+ overlapThreshold: number().min(0).max(1).optional(),
16886
+ /**
16887
+ * Operator-friendly version of `overlapThreshold` — the percentage
16888
+ * of the detection's bbox that must lie inside the zone for the
16889
+ * rule to match. Documented default is 85%; the engine substitutes
16890
+ * that when the field is omitted (kept optional so existing rules
16891
+ * stored without it stay valid).
16892
+ *
16893
+ * When BOTH `overlapThreshold` and `bboxInclusionPct` are set on a
16894
+ * rule, the engine prefers `bboxInclusionPct` because it's the
16895
+ * field exposed in the UI. Internally both feed the same gate.
16896
+ */
16897
+ bboxInclusionPct: number().min(0).max(100).optional(),
16898
+ /**
16899
+ * When `true` and a detection has a segmentation mask, use the
16900
+ * mask for overlap instead of the bbox. Detection-stage only;
16901
+ * motion rules ignore this field.
16902
+ */
16903
+ preferMask: boolean().optional(),
16904
+ /**
16905
+ * Soft-toggle: `false` disables the rule without deleting it.
16906
+ * Defaults to `true` so operators creating a rule via the UI
16907
+ * see it active immediately.
16908
+ */
16909
+ enabled: boolean().default(true)
16910
+ });
16911
+ array(ZoneRuleSchema).readonly();
16912
+ /**
16913
+ * Zone — pure geometry + identity. NO filtering behaviour.
16914
+ *
16915
+ * Zones describe **where** in the frame the operator wants to flag
16916
+ * something; consumer-owned {@link ZoneRule} arrays describe **how**
16917
+ * each pipeline stage uses them. Splitting the two means a single
16918
+ * polygon "Driveway" can simultaneously back a motion-exclude rule,
16919
+ * a detection-include rule on `['car']`, and an occupancy aggregate
16920
+ * — without three duplicated polygons.
16921
+ *
16922
+ * Owned by the orchestrator addon (provider) and mirrored into the
16923
+ * `zones` device-state slice on every mutation. Consumers
16924
+ * (motion-wasm, pipeline-executor, analytics, admin UI) read either
16925
+ * via `api.zones.listZones` (one-shot) or via `dev.state.zones` (live
16926
+ * mirror with `onChanged`).
16927
+ *
16928
+ * Coordinates are normalised fractions of the frame (0–1) so zones
16929
+ * survive resolution changes and stream profile switches.
16930
+ *
16931
+ * `kind` discriminates between full polygons (closed regions used
16932
+ * for intrusion / occupancy filters) and tripwires (open 2-point
16933
+ * line segments used for cross events). Onboard / firmware-reported
16934
+ * zones (Reolink, ONVIF) are out of scope for now — see the deferred
16935
+ * task list.
16936
+ */
16937
+ var ZoneKindEnum = _enum(["polygon", "tripwire"]);
16938
+ /** Polygon vertex in fraction-of-frame coordinates (0–1). */
16939
+ var PolygonPointSchema = object({
16940
+ x: number(),
16941
+ y: number()
16942
+ });
16943
+ /** A camera detection zone — pure geometry/identity. */
16944
+ var ZoneSchema = object({
16945
+ id: string(),
16946
+ name: string(),
16947
+ kind: ZoneKindEnum.default("polygon"),
16948
+ /** Polygon vertices, fraction of frame (0–1). */
16949
+ polygon: array(PolygonPointSchema).readonly(),
16950
+ /** Visual color for UI rendering. */
16951
+ color: string().default("#3b82f6")
16952
+ });
16953
+ /**
16954
+ * Zones capability — per-camera CRUD over polygon detection zones.
16955
+ *
16956
+ * Provider lives in `addon-pipeline-orchestrator` (hub-only). Persists
16957
+ * to per-device settings and mirrors into the `zones` device-state
16958
+ * slice on every mutation, so downstream consumers can subscribe via
16959
+ * `dev.state.zones.onChanged`.
16960
+ *
16961
+ * The cap surface only handles geometry + identity; filtering
16962
+ * behaviour (per-class, include/exclude, threshold) lives in the
16963
+ * consumer addons' rule arrays — see `ZoneRuleSchema` exported from
16964
+ * `capabilities/schemas/zone-rule.js`.
16965
+ */
16966
+ var zonesCapability = {
16967
+ name: "zones",
16968
+ scope: "device",
16969
+ mode: "singleton",
16970
+ deviceTypes: [DeviceType.Camera],
16971
+ methods: {
16972
+ listZones: method(object({ deviceId: number() }), array(ZoneSchema).readonly()),
16973
+ addZone: method(object({
16974
+ deviceId: number(),
16975
+ zone: ZoneSchema
16976
+ }), _void(), {
16977
+ kind: "mutation",
16978
+ auth: "admin"
16979
+ }),
16980
+ removeZone: method(object({
16981
+ deviceId: number(),
16982
+ zoneId: string()
16983
+ }), _void(), {
16984
+ kind: "mutation",
16985
+ auth: "admin"
16986
+ }),
16987
+ updateZone: method(object({
16988
+ deviceId: number(),
16989
+ zone: ZoneSchema
16990
+ }), _void(), {
16991
+ kind: "mutation",
16992
+ auth: "admin"
16993
+ })
16994
+ },
16995
+ /**
16996
+ * Runtime-state slice — the live zone catalogue mirrored by the
16997
+ * orchestrator on every CRUD mutation. Consumers read via
16998
+ * `device.state.zones.value` / `.watch(...)` without round-tripping
16999
+ * the cap, and the codegen DeviceProxy auto-wires the reactive
17000
+ * handle. Slice shape is `{ zones: Zone[] }` so future extensions
17001
+ * (e.g. zone groupings) can sit alongside the polygon list.
17002
+ */
17003
+ runtimeState: object({ zones: array(ZoneSchema).readonly() }),
17004
+ /**
17005
+ * 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.
17006
+ *
17007
+ * See `RuntimeStateDurability`. Enforced by
17008
+ * `scripts/check-runtime-state-durability.ts`.
17009
+ */
17010
+ durability: "restored"
17011
+ };
16325
17012
  /**
16326
17013
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16327
17014
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17411,6 +18098,24 @@ var RebuildStatusSchema = object({
17411
18098
  /** Present when the pass ended by throwing. */
17412
18099
  error: string().nullable()
17413
18100
  });
18101
+ var ReplayFrameInputSchema = object({
18102
+ timestamp: number(),
18103
+ frame: PipelineRunResultBridge
18104
+ });
18105
+ var RunReplayFrameProcessorResultSchema = object({ tracks: array(object({
18106
+ className: string(),
18107
+ firstSeenMs: number(),
18108
+ lastSeenMs: number(),
18109
+ /** Bbox of the track's FIRST matched detection, pixel-space in the clip's
18110
+ * frame — a representative box for the diff's `(className, window, IoU)`
18111
+ * pairing (`replay-diff.ts`). A replay does not need the full per-frame
18112
+ * trajectory production's `Track.positions` keeps. */
18113
+ bbox: BoundingBoxSchema,
18114
+ /** How many of the input frames this track matched a real detection on
18115
+ * (never a coasted/extrapolated frame) — the replay's own signal for "how
18116
+ * solid is this track", cheaper than re-deriving it from a trajectory. */
18117
+ framesMatched: number().int()
18118
+ })).readonly() });
17414
18119
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
17415
18120
  deviceId: number(),
17416
18121
  trackId: string()
@@ -17516,6 +18221,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17516
18221
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17517
18222
  kind: "mutation",
17518
18223
  auth: "admin"
18224
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18225
+ kind: "mutation",
18226
+ auth: "admin"
18227
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
18228
+ kind: "query",
18229
+ auth: "admin"
18230
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
18231
+ kind: "mutation",
18232
+ auth: "admin"
17519
18233
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17520
18234
  kind: "query",
17521
18235
  auth: "admin"
@@ -17572,6 +18286,16 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17572
18286
  }), RetrainAssistResultSchema, {
17573
18287
  kind: "mutation",
17574
18288
  auth: "admin"
18289
+ }), method(object({
18290
+ deviceId: number(),
18291
+ source: DetectionSourceSchema,
18292
+ zones: array(ZoneSchema).readonly().optional(),
18293
+ detectionRules: array(ZoneRuleSchema).readonly().optional(),
18294
+ zoneMembershipMinOverlap: number().min(0).max(1).optional(),
18295
+ frames: array(ReplayFrameInputSchema).min(1)
18296
+ }), RunReplayFrameProcessorResultSchema, {
18297
+ kind: "mutation",
18298
+ auth: "admin"
17575
18299
  }), method(object({ trackId: string() }), array(RetrainAnnotationSchema).readonly(), {
17576
18300
  kind: "query",
17577
18301
  auth: "admin"
@@ -17636,433 +18360,6 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17636
18360
  eventId: string(),
17637
18361
  timestamp: number()
17638
18362
  });
17639
- /**
17640
- * Reference to the frame's retained NATIVE surface + the parent crop's placement
17641
- * within the frame, so the executor can re-cut a leaf child ROI at native
17642
- * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
17643
- */
17644
- var NativeCropRefSchema = object({
17645
- /** Handle keying the retained native surface (node-pinned to its owner). */
17646
- handle: FrameHandleSchema,
17647
- /** The parent crop's padded/clamped rectangle in FRAME-space pixels. */
17648
- cropFrameSpace: object({
17649
- x: number(),
17650
- y: number(),
17651
- w: number(),
17652
- h: number()
17653
- })
17654
- });
17655
- object({
17656
- crop: object({
17657
- left: number(),
17658
- top: number(),
17659
- width: number().positive(),
17660
- height: number().positive()
17661
- }).optional(),
17662
- content: object({
17663
- width: number().int().positive(),
17664
- height: number().int().positive()
17665
- }),
17666
- fit: _enum(["stretch", "contain"]),
17667
- format: _enum([
17668
- "rgb",
17669
- "gray",
17670
- "jpeg"
17671
- ])
17672
- });
17673
- var FrameRefSchema = object({
17674
- registryId: string().min(1),
17675
- id: string().min(1),
17676
- width: number().int().positive(),
17677
- height: number().int().positive(),
17678
- format: _enum(["rgb", "gray"]),
17679
- timestamp: number(),
17680
- capturedAt: number().optional()
17681
- });
17682
- var ModelFormatSchema$1 = _enum([
17683
- "onnx",
17684
- "coreml",
17685
- "openvino",
17686
- "tflite",
17687
- "pt",
17688
- "gguf"
17689
- ]);
17690
- var PipelineSlotSchema = _enum([
17691
- "detector",
17692
- "cropper",
17693
- "classifier",
17694
- "refiner",
17695
- "audio-classifier"
17696
- ]);
17697
- var PipelineEngineChoiceSchema = object({
17698
- runtime: _enum(["node", "python"]),
17699
- backend: string(),
17700
- format: ModelFormatSchema$1,
17701
- device: string().optional()
17702
- });
17703
- var AvailableEngineSchema = object({
17704
- engine: PipelineEngineChoiceSchema,
17705
- devices: array(object({
17706
- id: string(),
17707
- label: string(),
17708
- description: string().optional()
17709
- })).readonly(),
17710
- defaultDevice: string()
17711
- });
17712
- var PipelineDefaultStepSchema = lazy(() => object({
17713
- addonId: string(),
17714
- addonName: string(),
17715
- slot: PipelineSlotSchema,
17716
- inputClasses: array(string()).readonly(),
17717
- outputClasses: array(string()).readonly(),
17718
- enabled: boolean(),
17719
- modelId: string(),
17720
- children: array(PipelineDefaultStepSchema).readonly(),
17721
- group: string().optional(),
17722
- settings: record(string(), unknown()).optional()
17723
- }));
17724
- var PipelineTemplateStepSchema = lazy(() => object({
17725
- addonId: string(),
17726
- enabled: boolean(),
17727
- modelId: string(),
17728
- children: array(PipelineTemplateStepSchema).readonly(),
17729
- settings: record(string(), unknown()).optional()
17730
- }));
17731
- var PipelineTemplateSchema$1 = object({
17732
- id: string(),
17733
- name: string(),
17734
- createdAt: string(),
17735
- updatedAt: string(),
17736
- engine: PipelineEngineChoiceSchema,
17737
- steps: array(PipelineTemplateStepSchema).readonly()
17738
- });
17739
- var PipelineModelOptionSchema = object({
17740
- id: string(),
17741
- name: string(),
17742
- formats: record(string(), object({
17743
- downloaded: boolean(),
17744
- sizeMB: number()
17745
- })),
17746
- group: ModelVariantGroupSchema.optional(),
17747
- legacy: boolean().optional(),
17748
- provider: ModelProviderIdSchema.optional()
17749
- });
17750
- var ConfigFieldBridge = custom();
17751
- var PipelineAddonSchemaSchema = object({
17752
- id: string(),
17753
- name: string(),
17754
- slot: PipelineSlotSchema,
17755
- inputClasses: array(string()).readonly(),
17756
- outputClasses: array(string()).readonly(),
17757
- childSlots: array(PipelineSlotSchema).readonly(),
17758
- models: array(PipelineModelOptionSchema).readonly(),
17759
- defaultModelId: string(),
17760
- defaultModelIdByFormat: record(string(), string()).optional(),
17761
- enabledByDefault: boolean().optional(),
17762
- backfillIntoExistingOverrides: boolean().optional(),
17763
- defaultConfidence: number(),
17764
- group: string().optional(),
17765
- configSchema: array(ConfigFieldBridge).readonly().optional()
17766
- });
17767
- var PipelineSlotSchemaSchema = object({
17768
- id: PipelineSlotSchema,
17769
- label: string(),
17770
- priority: number(),
17771
- parentSlot: PipelineSlotSchema.nullable(),
17772
- addons: array(PipelineAddonSchemaSchema).readonly()
17773
- });
17774
- var PipelineSchemaSchema = object({
17775
- availableEngines: array(AvailableEngineSchema).readonly(),
17776
- selectedEngine: PipelineEngineChoiceSchema,
17777
- slots: array(PipelineSlotSchemaSchema).readonly()
17778
- });
17779
- var EngineProvisioningSchema = object({
17780
- runtimeId: _enum([
17781
- "onnx",
17782
- "openvino",
17783
- "coreml",
17784
- "edgetpu"
17785
- ]).nullable(),
17786
- device: string().nullable(),
17787
- state: _enum([
17788
- "idle",
17789
- "installing",
17790
- "verifying",
17791
- "ready",
17792
- "failed"
17793
- ]),
17794
- progress: number().optional(),
17795
- error: string().optional(),
17796
- nextRetryAt: number().optional(),
17797
- /**
17798
- * Gate A (config-correctness gate at engine change): human-readable
17799
- * config issues surfaced EAGERLY when the node's engine changes — model
17800
- * substitutions ("chose X, running Y") and zero-build steps ("no model
17801
- * has a <format> build"). Additive/optional: informational only, never
17802
- * enforced here — `assertEngineReady` (readiness) still gates inference.
17803
- * Absent/empty when the node-default tree resolves cleanly.
17804
- */
17805
- configIssues: array(string()).optional()
17806
- });
17807
- var PipelineStepInputSchema = lazy(() => object({
17808
- addonId: string(),
17809
- modelId: string().optional(),
17810
- enabled: boolean().default(true),
17811
- children: array(PipelineStepInputSchema).optional(),
17812
- settings: record(string(), unknown()).optional(),
17813
- jumpDeviceKey: string().optional()
17814
- }));
17815
- var ModelSubstitutionSchema = object({
17816
- addonId: string(),
17817
- chosen: string(),
17818
- running: string(),
17819
- format: string()
17820
- });
17821
- var PipelineValidationIssueSchema = object({
17822
- addonId: string(),
17823
- kind: _enum(["unknown-addon", "no-format-build"]),
17824
- detail: string()
17825
- });
17826
- var PipelineValidationResultSchema = object({
17827
- ok: boolean(),
17828
- issues: array(PipelineValidationIssueSchema).readonly(),
17829
- substitutions: array(ModelSubstitutionSchema).readonly(),
17830
- /** The node's `currentEngine.format` this validation ran against. */
17831
- format: string()
17832
- });
17833
- var ReferenceImageEntrySchema = object({
17834
- filename: string(),
17835
- stepIds: array(string()).readonly().optional()
17836
- });
17837
- var ReferenceImageBodySchema = object({
17838
- base64: string(),
17839
- filename: string()
17840
- });
17841
- var ReferenceAudioEntrySchema = object({
17842
- filename: string(),
17843
- sizeKb: number()
17844
- });
17845
- var ReferenceAudioBodySchema = object({ base64: string() });
17846
- var AudioBackendSchema = object({
17847
- id: string(),
17848
- name: string(),
17849
- description: string(),
17850
- available: boolean(),
17851
- /**
17852
- * Raw classifier labels this backend can emit (e.g. YAMNet's
17853
- * 521-class set or Apple SoundAnalysis's 303-class set). Used by
17854
- * the benchmark UI to populate the `enabledMicroClasses` filter
17855
- * specific to the selected backend without a separate fetch.
17856
- */
17857
- rawLabels: array(string()).readonly().optional()
17858
- });
17859
- var AudioCapabilitiesSchema = object({
17860
- activeBackend: string(),
17861
- availableBackends: array(AudioBackendSchema).readonly(),
17862
- sampleRate: number(),
17863
- chunkDurationMs: number()
17864
- });
17865
- var DownloadModelResultSchema = object({
17866
- filePath: string(),
17867
- sizeMB: number(),
17868
- durationMs: number()
17869
- });
17870
- /**
17871
- * Wrapper carrying a single test run's result. Replaces the legacy
17872
- * ad-hoc `{labels: [{className, originalClass, score}]}` shape with the
17873
- * canonical `AudioResult` from the Phase 6 output rework: one
17874
- * `AudioDetection` per class above `minScore`, top-N candidates in
17875
- * `debug.alternateLabels['audio-classifier']`, per-source timings in
17876
- * `debug.stepTimings`. The outer `success`/`error` fields stay so the
17877
- * benchmark UI can still report a clean failure when the classifier
17878
- * cap isn't available.
17879
- */
17880
- var AudioTestResultSchema = object({
17881
- success: boolean(),
17882
- error: string().optional(),
17883
- frame: custom().optional()
17884
- });
17885
- var PipelineConfigBridge = custom();
17886
- var ConfigUISchemaBridge = custom();
17887
- var ConfigUISchemaNullableBridge = custom();
17888
- var InferenceCapabilitiesBridge = custom();
17889
- var ModelAvailabilityListBridge = custom();
17890
- var PipelineRunResultBridge = custom();
17891
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
17892
- modelId: string(),
17893
- settings: record(string(), unknown()).readonly()
17894
- }))), method(object({ steps: record(string(), object({
17895
- modelId: string(),
17896
- settings: record(string(), unknown()).readonly()
17897
- })) }), object({ success: literal(true) }), {
17898
- kind: "mutation",
17899
- auth: "admin"
17900
- }), method(object({ nodeId: string() }), object({
17901
- success: literal(true),
17902
- clearedDevices: number()
17903
- }), {
17904
- kind: "mutation",
17905
- auth: "admin"
17906
- }), 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({
17907
- name: string(),
17908
- steps: array(PipelineTemplateStepSchema).readonly(),
17909
- engine: PipelineEngineChoiceSchema
17910
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
17911
- id: string(),
17912
- name: string().optional(),
17913
- steps: array(PipelineTemplateStepSchema).readonly().optional()
17914
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
17915
- addonId: string(),
17916
- modelId: string(),
17917
- format: ModelFormatSchema$1
17918
- }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
17919
- addonId: string(),
17920
- modelId: string(),
17921
- format: ModelFormatSchema$1
17922
- }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
17923
- engine: PipelineEngineChoiceSchema.optional(),
17924
- steps: array(PipelineStepInputSchema).min(1),
17925
- frame: FrameInputSchema.optional(),
17926
- /**
17927
- * Process-local lazy frame. Valid only when caller and provider resolve
17928
- * in the same execution-group process; split/cross-node callers use
17929
- * `frame`/`image` inline compatibility instead.
17930
- */
17931
- frameRef: FrameRefSchema.optional(),
17932
- /**
17933
- * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17934
- * the decoded pixels live in. One more member of the one-of
17935
- * frame/frameHandle/image/imageBase64/referenceImage group.
17936
- */
17937
- frameHandle: FrameHandleSchema.optional(),
17938
- imageBase64: string().optional(),
17939
- /**
17940
- * Binary JPEG bytes — preferred over `imageBase64` on internal
17941
- * hops (hub → forked worker via Moleculer MsgPack) because it
17942
- * skips the 33% base64 overhead + the per-call base64 decode on
17943
- * the detection-pipeline worker. Callers can pass either; exactly
17944
- * one of `frame`/`image`/`imageBase64`/`referenceImage` is required.
17945
- */
17946
- image: _instanceof(Uint8Array).optional(),
17947
- referenceImage: string().optional(),
17948
- deviceId: number().optional(),
17949
- sessionId: string().optional(),
17950
- /**
17951
- * Execution plane. 'full' (default) runs the whole tree — benchmark,
17952
- * reference-image, and detail-subtree calls. 'frame' is the live
17953
- * per-frame dispatch: ONLY root-plane steps run; crop children
17954
- * (inputClasses ≠ null) are skipped and served per-track via
17955
- * pipelineRunner.runDetailSubtree (two-plane design).
17956
- */
17957
- plane: _enum(["full", "frame"]).optional(),
17958
- /**
17959
- * Inference-device selector (Phase 2 multi-device). Format
17960
- * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
17961
- * Omitted ⇒ the runner's default device (current single-engine
17962
- * behaviour). Selects WHICH device pool of the node runs the call.
17963
- */
17964
- deviceKey: string().optional(),
17965
- /**
17966
- * Two-plane NATIVE child-crop reference. Set by `runDetailSubtree` ONLY
17967
- * when the parent crop was resolved from the frame's retained NATIVE
17968
- * surface (a frameHandle HIT). Lets the executor re-cut a LEAF crop
17969
- * child's ROI (plate-ocr, face-embedding, leaf classifiers) at native
17970
- * resolution from that surface — the SAME quality path faces already
17971
- * had — instead of the downscaled parent tile. `handle` keys the native
17972
- * surface (node-pinned to its owner); `cropFrameSpace` is the parent
17973
- * crop's padded/clamped rectangle in FRAME-space pixels, used to compose
17974
- * the executor's crop-normalized child ROI back into frame-normalized
17975
- * coordinates. Auxiliary to the image source (`image`/`frame`/…), NOT one
17976
- * of the mutually-exclusive image inputs. Absent ⇒ tile-crop children
17977
- * (today's behaviour on the fallback path).
17978
- */
17979
- nativeCropRef: NativeCropRefSchema.optional()
17980
- }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
17981
- engine: PipelineEngineChoiceSchema.optional(),
17982
- steps: array(PipelineStepInputSchema).min(1),
17983
- frames: array(FrameInputSchema).min(1).max(255),
17984
- deviceId: number().optional(),
17985
- sessionId: string().optional(),
17986
- /**
17987
- * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
17988
- * the batch to the Python pool's bench preprocess cache
17989
- * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
17990
- * preprocessed ONCE and every later inference is a pure-inference cache
17991
- * hit — the sustained-throughput run measures inference, not
17992
- * decode+preprocess+infer. Omitted/0 for live frames (all different →
17993
- * full preprocess every call, correct). Fresh per sustained run;
17994
- * released via `uncacheFrame`.
17995
- */
17996
- frameId: number().int().nonnegative().optional(),
17997
- /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
17998
- deviceKey: string().optional()
17999
- }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
18000
- data: _instanceof(Uint8Array),
18001
- width: number().int().positive(),
18002
- height: number().int().positive(),
18003
- format: _enum([
18004
- "rgb",
18005
- "bgr",
18006
- "gray"
18007
- ])
18008
- }), object({
18009
- frameId: number(),
18010
- width: number(),
18011
- height: number()
18012
- }), { kind: "mutation" }), method(object({
18013
- stepId: string(),
18014
- frameId: number().int()
18015
- }), record(string(), unknown()), { kind: "mutation" }), method(object({ frameId: number().int() }), _void(), { kind: "mutation" }), method(_void(), object({
18016
- batchMode: string(),
18017
- windowMs: number(),
18018
- maxBatchSize: number(),
18019
- concurrency: number()
18020
- })), method(_void(), array(object({
18021
- engineKey: string(),
18022
- engine: PipelineEngineChoiceSchema,
18023
- modelsLoaded: array(string()).readonly(),
18024
- inUseByCameras: array(number()).readonly(),
18025
- /**
18026
- * Origin of this resident factory.
18027
- * - `runtime` — main camera-serving engine (no idle TTL).
18028
- * - `warm-override` — benchmark/test override held in the warm
18029
- * cache; auto-disposed after the idle TTL.
18030
- * - `device-pool` — a concurrent per-device pool (Phase 2
18031
- * multi-device, keyed by `deviceKey`) resolved
18032
- * via `resolveDeviceFactory`. Runs alongside the
18033
- * `runtime` engine on a DIFFERENT accelerator
18034
- * (NPU / iGPU / Coral) — this is how the
18035
- * Engines tab shows all pools running at once.
18036
- */
18037
- kind: _enum([
18038
- "runtime",
18039
- "warm-override",
18040
- "device-pool"
18041
- ]),
18042
- /** Native pid of the underlying Python pool (null when no pool). */
18043
- poolPid: number().nullable(),
18044
- /** ms since this factory was last used (null when not warm-tracked). */
18045
- idleMs: number().nullable(),
18046
- /** Idle TTL after which `warm-override` factories self-evict (null when not applicable). */
18047
- idleTtlMs: number().nullable()
18048
- })).readonly()), method(object({ engine: PipelineEngineChoiceSchema }), object({ success: literal(true) }), {
18049
- kind: "mutation",
18050
- auth: "admin"
18051
- }), method(object({
18052
- engine: PipelineEngineChoiceSchema,
18053
- force: boolean().optional()
18054
- }), object({
18055
- success: boolean(),
18056
- reason: string().optional()
18057
- }), {
18058
- kind: "mutation",
18059
- auth: "admin"
18060
- }), 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({
18061
- addonId: string(),
18062
- modelId: string(),
18063
- filename: string().optional(),
18064
- settings: record(string(), unknown()).optional()
18065
- }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
18066
18363
  object({
18067
18364
  activeCameras: number(),
18068
18365
  throttledCameras: number(),
@@ -18088,106 +18385,6 @@ var CameraMetricsSchema = object({
18088
18385
  });
18089
18386
  var CameraMetricsWithDeviceIdSchema = CameraMetricsSchema.extend({ deviceId: number() });
18090
18387
  /**
18091
- * Zone — pure geometry + identity. NO filtering behaviour.
18092
- *
18093
- * Zones describe **where** in the frame the operator wants to flag
18094
- * something; consumer-owned {@link ZoneRule} arrays describe **how**
18095
- * each pipeline stage uses them. Splitting the two means a single
18096
- * polygon "Driveway" can simultaneously back a motion-exclude rule,
18097
- * a detection-include rule on `['car']`, and an occupancy aggregate
18098
- * — without three duplicated polygons.
18099
- *
18100
- * Owned by the orchestrator addon (provider) and mirrored into the
18101
- * `zones` device-state slice on every mutation. Consumers
18102
- * (motion-wasm, pipeline-executor, analytics, admin UI) read either
18103
- * via `api.zones.listZones` (one-shot) or via `dev.state.zones` (live
18104
- * mirror with `onChanged`).
18105
- *
18106
- * Coordinates are normalised fractions of the frame (0–1) so zones
18107
- * survive resolution changes and stream profile switches.
18108
- *
18109
- * `kind` discriminates between full polygons (closed regions used
18110
- * for intrusion / occupancy filters) and tripwires (open 2-point
18111
- * line segments used for cross events). Onboard / firmware-reported
18112
- * zones (Reolink, ONVIF) are out of scope for now — see the deferred
18113
- * task list.
18114
- */
18115
- var ZoneKindEnum = _enum(["polygon", "tripwire"]);
18116
- /** Polygon vertex in fraction-of-frame coordinates (0–1). */
18117
- var PolygonPointSchema = object({
18118
- x: number(),
18119
- y: number()
18120
- });
18121
- /** A camera detection zone — pure geometry/identity. */
18122
- var ZoneSchema = object({
18123
- id: string(),
18124
- name: string(),
18125
- kind: ZoneKindEnum.default("polygon"),
18126
- /** Polygon vertices, fraction of frame (0–1). */
18127
- polygon: array(PolygonPointSchema).readonly(),
18128
- /** Visual color for UI rendering. */
18129
- color: string().default("#3b82f6")
18130
- });
18131
- /**
18132
- * Zones capability — per-camera CRUD over polygon detection zones.
18133
- *
18134
- * Provider lives in `addon-pipeline-orchestrator` (hub-only). Persists
18135
- * to per-device settings and mirrors into the `zones` device-state
18136
- * slice on every mutation, so downstream consumers can subscribe via
18137
- * `dev.state.zones.onChanged`.
18138
- *
18139
- * The cap surface only handles geometry + identity; filtering
18140
- * behaviour (per-class, include/exclude, threshold) lives in the
18141
- * consumer addons' rule arrays — see `ZoneRuleSchema` exported from
18142
- * `capabilities/schemas/zone-rule.js`.
18143
- */
18144
- var zonesCapability = {
18145
- name: "zones",
18146
- scope: "device",
18147
- mode: "singleton",
18148
- deviceTypes: [DeviceType.Camera],
18149
- methods: {
18150
- listZones: method(object({ deviceId: number() }), array(ZoneSchema).readonly()),
18151
- addZone: method(object({
18152
- deviceId: number(),
18153
- zone: ZoneSchema
18154
- }), _void(), {
18155
- kind: "mutation",
18156
- auth: "admin"
18157
- }),
18158
- removeZone: method(object({
18159
- deviceId: number(),
18160
- zoneId: string()
18161
- }), _void(), {
18162
- kind: "mutation",
18163
- auth: "admin"
18164
- }),
18165
- updateZone: method(object({
18166
- deviceId: number(),
18167
- zone: ZoneSchema
18168
- }), _void(), {
18169
- kind: "mutation",
18170
- auth: "admin"
18171
- })
18172
- },
18173
- /**
18174
- * Runtime-state slice — the live zone catalogue mirrored by the
18175
- * orchestrator on every CRUD mutation. Consumers read via
18176
- * `device.state.zones.value` / `.watch(...)` without round-tripping
18177
- * the cap, and the codegen DeviceProxy auto-wires the reactive
18178
- * handle. Slice shape is `{ zones: Zone[] }` so future extensions
18179
- * (e.g. zone groupings) can sit alongside the polygon list.
18180
- */
18181
- runtimeState: object({ zones: array(ZoneSchema).readonly() }),
18182
- /**
18183
- * 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.
18184
- *
18185
- * See `RuntimeStateDurability`. Enforced by
18186
- * `scripts/check-runtime-state-durability.ts`.
18187
- */
18188
- durability: "restored"
18189
- };
18190
- /**
18191
18388
  * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
18192
18389
  * decode worker resolves it against the RETAINED native frame's real pixel dims,
18193
18390
  * so the caller supplies only the detection-res bbox divided by the detection
@@ -19979,7 +20176,7 @@ method(object({
19979
20176
  * linking rather than produce an eternal token.
19980
20177
  */
19981
20178
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19982
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
20179
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19983
20180
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19984
20181
  providerId: string().min(1),
19985
20182
  displayName: string().min(1),
@@ -20074,10 +20271,13 @@ var EvictResultSchema = object({
20074
20271
  /** True when the provider has nothing left it is willing to drop on this location. */
20075
20272
  exhausted: boolean()
20076
20273
  });
20077
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20274
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
20078
20275
  locationId: string(),
20079
20276
  targetBytes: number().int().positive()
20080
- }), EvictResultSchema, { kind: "mutation" });
20277
+ }), EvictResultSchema, {
20278
+ kind: "mutation",
20279
+ auth: "admin"
20280
+ });
20081
20281
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
20082
20282
  kind: "mutation",
20083
20283
  auth: "admin"
@@ -20137,26 +20337,50 @@ var ReadChunkInputSchema = object({
20137
20337
  length: number()
20138
20338
  });
20139
20339
  var EndDownloadInputSchema = object({ downloadId: string() });
20140
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20340
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20141
20341
  location: StorageLocationSchema,
20142
20342
  relativePath: string()
20143
- }), string()), method(object({
20343
+ }), string(), { auth: "admin" }), method(object({
20144
20344
  location: StorageLocationSchema,
20145
20345
  relativePath: string(),
20146
20346
  data: _instanceof(Uint8Array)
20147
- }), _void(), { kind: "mutation" }), method(object({
20347
+ }), _void(), {
20348
+ kind: "mutation",
20349
+ auth: "admin"
20350
+ }), method(object({
20148
20351
  location: StorageLocationSchema,
20149
20352
  relativePath: string()
20150
- }), _instanceof(Uint8Array)), method(object({
20353
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
20151
20354
  location: StorageLocationSchema,
20152
20355
  relativePath: string()
20153
- }), boolean()), method(object({
20356
+ }), boolean(), { auth: "admin" }), method(object({
20154
20357
  location: StorageLocationSchema,
20155
20358
  prefix: string().optional()
20156
- }), array(string()).readonly()), method(object({
20359
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
20157
20360
  location: StorageLocationSchema,
20158
20361
  relativePath: string()
20159
- }), _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" });
20362
+ }), _void(), {
20363
+ kind: "mutation",
20364
+ auth: "admin"
20365
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20366
+ kind: "mutation",
20367
+ auth: "admin"
20368
+ }), method(WriteChunkInputSchema, _void(), {
20369
+ kind: "mutation",
20370
+ auth: "admin"
20371
+ }), method(FinalizeUploadInputSchema, _void(), {
20372
+ kind: "mutation",
20373
+ auth: "admin"
20374
+ }), method(AbortUploadInputSchema, _void(), {
20375
+ kind: "mutation",
20376
+ auth: "admin"
20377
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20378
+ kind: "mutation",
20379
+ auth: "admin"
20380
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20381
+ kind: "mutation",
20382
+ auth: "admin"
20383
+ });
20160
20384
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20161
20385
  var ProfileSettingsSchemaBridge = unknown().nullable();
20162
20386
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20458,7 +20682,8 @@ method(object({
20458
20682
  access: "create"
20459
20683
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20460
20684
  kind: "mutation",
20461
- access: "view"
20685
+ access: "view",
20686
+ auth: "admin"
20462
20687
  }), method(object({
20463
20688
  /** Required — the user the assertion belongs to (verified). */
20464
20689
  userId: string(),
@@ -20466,10 +20691,12 @@ method(object({
20466
20691
  response: record(string(), unknown())
20467
20692
  }), object({ verified: boolean() }), {
20468
20693
  kind: "mutation",
20469
- access: "view"
20694
+ access: "view",
20695
+ auth: "admin"
20470
20696
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20471
20697
  kind: "mutation",
20472
- access: "view"
20698
+ access: "view",
20699
+ auth: "admin"
20473
20700
  }), method(object({
20474
20701
  /** AuthenticationResponseJSON from the browser. */
20475
20702
  response: record(string(), unknown()) }), object({
@@ -20477,7 +20704,8 @@ response: record(string(), unknown()) }), object({
20477
20704
  userId: string().nullable()
20478
20705
  }), {
20479
20706
  kind: "mutation",
20480
- access: "view"
20707
+ access: "view",
20708
+ auth: "admin"
20481
20709
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20482
20710
  userId: string(),
20483
20711
  credentialId: string()
@@ -20649,7 +20877,19 @@ var VectorStatsResultSchema = object({
20649
20877
  /** False when the backend ranks approximately. */
20650
20878
  exact: boolean()
20651
20879
  });
20652
- 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);
20880
+ method(VectorDeclareIndexInputSchema, _void(), {
20881
+ kind: "mutation",
20882
+ auth: "admin"
20883
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20884
+ kind: "mutation",
20885
+ auth: "admin"
20886
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20887
+ kind: "mutation",
20888
+ auth: "admin"
20889
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20890
+ kind: "mutation",
20891
+ auth: "admin"
20892
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20653
20893
  var ClipSchema = object({
20654
20894
  /** Opaque, provider-namespaced id. The default provider encodes the time
20655
20895
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -23102,7 +23342,27 @@ var MediaFileLiteSchema$1 = object({
23102
23342
  sizeBytes: number(),
23103
23343
  timestamp: number()
23104
23344
  });
23105
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23345
+ method(object({
23346
+ /**
23347
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23348
+ *
23349
+ * Default `false`, the same inversion `listRecentFaces` and
23350
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23351
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23352
+ * on the live hub the same day: four identities cost 40,979 B with the
23353
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23354
+ * four times and the viewer holds at `staleTime: 30_000`.
23355
+ *
23356
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23357
+ * the `event-media` plane serves that key `immutable` with an ETag.
23358
+ *
23359
+ * **This is an INPUT field, so it does not reach the addon until the
23360
+ * next train** — the hub router validates cap inputs against its own
23361
+ * compiled Zod and strips a key it does not know. Until then the
23362
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23363
+ * is what ships, and the opt-in becomes reachable when the train lands.
23364
+ */
23365
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23106
23366
  kind: "mutation",
23107
23367
  auth: "admin"
23108
23368
  }), method(object({
@@ -25992,8 +26252,10 @@ var PlateInfoSchema = object({
25992
26252
  keyFrameMediaKey: string().optional(),
25993
26253
  base64: string().optional(),
25994
26254
  /**
25995
- * Same crop as a data-plane URL. `getPlateByTrack` returns this and
25996
- * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26255
+ * Same crop as a data-plane URL, always present when the plate has a stored
26256
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26257
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26258
+ * left at its `true` default.
25997
26259
  */
25998
26260
  cropUrl: string().optional()
25999
26261
  });
@@ -26013,14 +26275,34 @@ var PlateClusterSchema = object({
26013
26275
  });
26014
26276
  method(object({
26015
26277
  deviceId: number().int().optional(),
26016
- limit: number().int().positive().optional()
26278
+ limit: number().int().positive().optional(),
26279
+ /**
26280
+ * Inline the base64 crop on every row. Default `true` — the existing
26281
+ * behaviour, kept so no caller breaks.
26282
+ *
26283
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26284
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26285
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26286
+ * metadata without them — and the browser then caches the images.
26287
+ *
26288
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26289
+ * plates were the one gallery list left without it.
26290
+ *
26291
+ * **This is an INPUT field, so it does not reach the addon until the
26292
+ * next train.** The hub router validates cap inputs against its own
26293
+ * compiled Zod and strips a key it does not know. Until the train
26294
+ * ships, sending `false` is harmless and keeps the crops inline.
26295
+ */
26296
+ includeCrops: boolean().optional()
26017
26297
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
26018
26298
  deviceId: number().int(),
26019
26299
  trackId: string()
26020
26300
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
26021
26301
  text: string().min(1),
26022
26302
  maxDistance: number().int().min(0).optional(),
26023
- limit: number().int().positive().optional()
26303
+ limit: number().int().positive().optional(),
26304
+ /** See `listPlates.includeCrops`. Default `true`. */
26305
+ includeCrops: boolean().optional()
26024
26306
  }), array(PlateInfoSchema).readonly()), method(object({
26025
26307
  maxDistance: number().int().min(0).optional(),
26026
26308
  minClusterSize: number().int().min(2).optional(),
@@ -26034,7 +26316,13 @@ method(object({
26034
26316
  }), method(object({ plateId: string() }), _void(), {
26035
26317
  kind: "mutation",
26036
26318
  auth: "admin"
26037
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26319
+ }), method(object({
26320
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26321
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26322
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26323
+ * INPUT field: stripped by the hub router until the train ships, which
26324
+ * resolves to `false` and is exactly the intended default. */
26325
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26038
26326
  kind: "mutation",
26039
26327
  auth: "admin"
26040
26328
  }), method(object({
@@ -27555,92 +27843,6 @@ var sceneMonitorCapability = {
27555
27843
  durability: "session"
27556
27844
  };
27557
27845
  /**
27558
- * Per-stage gating mode applied to the zones a rule references.
27559
- *
27560
- * - `include`: the rule contributes to a **whitelist** for its stage.
27561
- * When at least one `include` rule fires for a stage, only entities
27562
- * inside one of those zones pass that stage.
27563
- * - `exclude`: the rule contributes to a **blacklist** for its stage.
27564
- * Entities inside one of those zones are dropped at that stage.
27565
- *
27566
- * `monitor`-style observation (count without filtering) is not a rule
27567
- * mode — zones without any matching rule are observed naturally by
27568
- * `zone-analytics` (live snapshot + history), so an "I just want to
27569
- * count, not filter" use case needs no rule at all.
27570
- */
27571
- var ZoneRuleModeEnum = _enum(["include", "exclude"]);
27572
- /**
27573
- * Per-consumer rule that references existing zones (geometry) and
27574
- * defines how a specific pipeline stage should treat them. Each
27575
- * consumer addon owns its own `ZoneRule[]` array in its per-device
27576
- * settings:
27577
- *
27578
- * - `addon-motion-wasm` → `motionZoneRules: ZoneRule[]` (motion stage)
27579
- * - `addon-detection-pipeline` → `detectionZoneRules: ZoneRule[]` (detection stage)
27580
- * - future: notification rules, audio gating, etc.
27581
- *
27582
- * One rule applies to N zones (`zoneIds[]`) so the operator can
27583
- * express "ignore motion in ALL of {garden, street}" with a single
27584
- * rule. `classFilter` narrows the rule to specific object classes —
27585
- * "drop person detections in the street, but keep cars" is one
27586
- * `exclude` rule with `classFilter: ['person']`.
27587
- *
27588
- * `enabled` is a soft toggle — the operator can keep the rule
27589
- * configured but inert without deleting it.
27590
- */
27591
- var ZoneRuleSchema = object({
27592
- /** Stable rule id — survives edits, used by the UI for diffing. */
27593
- id: string(),
27594
- /** Optional human-readable label rendered in the rule editor. */
27595
- name: string().optional(),
27596
- /** Zones this rule targets. The rule's `mode` applies to ALL
27597
- * listed zones (OR-set: a detection in any one of them counts).
27598
- * At least one zone id required — a rule with no targets is a
27599
- * configuration mistake and the form validator rejects it. */
27600
- zoneIds: array(string()).min(1).readonly(),
27601
- mode: ZoneRuleModeEnum,
27602
- /**
27603
- * Class names this rule applies to. Empty / undefined ⇒ rule
27604
- * applies to every class. Class strings match the `macroClass`
27605
- * field on detections (e.g. `person`, `car`, `dog`).
27606
- */
27607
- classFilter: array(string()).readonly().optional(),
27608
- /**
27609
- * Minimum bbox/mask overlap (0–1) with any of the rule's zones
27610
- * required to consider an entity "in the zone". Defaults to the
27611
- * consumer's stage default when omitted. Kept for back-compat with
27612
- * existing per-rule overrides; new operators pick the value via
27613
- * `bboxInclusionPct` (operator-friendly 0–100). Whichever field is
27614
- * set, the lower-level engine reads it as a 0–1 fraction.
27615
- */
27616
- overlapThreshold: number().min(0).max(1).optional(),
27617
- /**
27618
- * Operator-friendly version of `overlapThreshold` — the percentage
27619
- * of the detection's bbox that must lie inside the zone for the
27620
- * rule to match. Documented default is 85%; the engine substitutes
27621
- * that when the field is omitted (kept optional so existing rules
27622
- * stored without it stay valid).
27623
- *
27624
- * When BOTH `overlapThreshold` and `bboxInclusionPct` are set on a
27625
- * rule, the engine prefers `bboxInclusionPct` because it's the
27626
- * field exposed in the UI. Internally both feed the same gate.
27627
- */
27628
- bboxInclusionPct: number().min(0).max(100).optional(),
27629
- /**
27630
- * When `true` and a detection has a segmentation mask, use the
27631
- * mask for overlap instead of the bbox. Detection-stage only;
27632
- * motion rules ignore this field.
27633
- */
27634
- preferMask: boolean().optional(),
27635
- /**
27636
- * Soft-toggle: `false` disables the rule without deleting it.
27637
- * Defaults to `true` so operators creating a rule via the UI
27638
- * see it active immediately.
27639
- */
27640
- enabled: boolean().default(true)
27641
- });
27642
- array(ZoneRuleSchema).readonly();
27643
- /**
27644
27846
  * Script-runner cap. Models HA `script.*` entities on
27645
27847
  * `DeviceType.Script`. A Script is a pre-recorded action sequence
27646
27848
  * that can be invoked imperatively — optionally with a variables
@@ -33293,6 +33495,12 @@ Object.freeze({
33293
33495
  addonId: null,
33294
33496
  access: "create"
33295
33497
  },
33498
+ "pipelineAnalytics.cancelRelocateMedia": {
33499
+ capName: "pipeline-analytics",
33500
+ capScope: "device",
33501
+ addonId: null,
33502
+ access: "create"
33503
+ },
33296
33504
  "pipelineAnalytics.cancelStorageMigrationMove": {
33297
33505
  capName: "pipeline-analytics",
33298
33506
  capScope: "device",
@@ -33467,6 +33675,12 @@ Object.freeze({
33467
33675
  addonId: null,
33468
33676
  access: "view"
33469
33677
  },
33678
+ "pipelineAnalytics.listRelocateMediaJobs": {
33679
+ capName: "pipeline-analytics",
33680
+ capScope: "device",
33681
+ addonId: null,
33682
+ access: "view"
33683
+ },
33470
33684
  "pipelineAnalytics.listRetrainAnnotations": {
33471
33685
  capName: "pipeline-analytics",
33472
33686
  capScope: "device",
@@ -33545,6 +33759,12 @@ Object.freeze({
33545
33759
  addonId: null,
33546
33760
  access: "create"
33547
33761
  },
33762
+ "pipelineAnalytics.relocateMedia": {
33763
+ capName: "pipeline-analytics",
33764
+ capScope: "device",
33765
+ addonId: null,
33766
+ access: "create"
33767
+ },
33548
33768
  "pipelineAnalytics.restageRetrainTrack": {
33549
33769
  capName: "pipeline-analytics",
33550
33770
  capScope: "device",
@@ -33557,6 +33777,12 @@ Object.freeze({
33557
33777
  addonId: null,
33558
33778
  access: "create"
33559
33779
  },
33780
+ "pipelineAnalytics.runReplayFrameProcessor": {
33781
+ capName: "pipeline-analytics",
33782
+ capScope: "device",
33783
+ addonId: null,
33784
+ access: "create"
33785
+ },
33560
33786
  "pipelineAnalytics.saveRetrainAnnotations": {
33561
33787
  capName: "pipeline-analytics",
33562
33788
  capScope: "device",
@@ -33689,6 +33915,12 @@ Object.freeze({
33689
33915
  addonId: null,
33690
33916
  access: "view"
33691
33917
  },
33918
+ "pipelineExecutor.getInferenceDeviceHealth": {
33919
+ capName: "pipeline-executor",
33920
+ capScope: "system",
33921
+ addonId: null,
33922
+ access: "view"
33923
+ },
33692
33924
  "pipelineExecutor.getOrchestratorConfigSchema": {
33693
33925
  capName: "pipeline-executor",
33694
33926
  capScope: "system",
@@ -33761,6 +33993,12 @@ Object.freeze({
33761
33993
  addonId: null,
33762
33994
  access: "view"
33763
33995
  },
33996
+ "pipelineExecutor.rearmInferenceDevice": {
33997
+ capName: "pipeline-executor",
33998
+ capScope: "system",
33999
+ addonId: null,
34000
+ access: "create"
34001
+ },
33764
34002
  "pipelineExecutor.runAudioTest": {
33765
34003
  capName: "pipeline-executor",
33766
34004
  capScope: "system",
@@ -37009,6 +37247,11 @@ Object.freeze({
37009
37247
  form: "single",
37010
37248
  optional: false
37011
37249
  }],
37250
+ "pipelineAnalytics.runReplayFrameProcessor": [{
37251
+ name: "deviceId",
37252
+ form: "single",
37253
+ optional: false
37254
+ }],
37012
37255
  "pipelineAnalytics.saveRetrainAnnotations": [{
37013
37256
  name: "deviceId",
37014
37257
  form: "single",
@@ -44408,7 +44651,10 @@ function sanitizeProfileSettings(profileId, raw) {
44408
44651
  showContainers: true,
44409
44652
  showSensors: true
44410
44653
  };
44411
- for (const plugin of GLANCES_PLUGINS) if (typeof bag[plugin.key] === "boolean") out[plugin.key] = bag[plugin.key];
44654
+ for (const plugin of GLANCES_PLUGINS) {
44655
+ const value = bag[plugin.key];
44656
+ if (typeof value === "boolean") out[plugin.key] = value;
44657
+ }
44412
44658
  return out;
44413
44659
  }
44414
44660
  function profileSettingsToArgs(profileId, settings) {