@camstack/addon-provider-dreo 0.2.27 → 0.2.29

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 +431 -111
  2. package/dist/addon.mjs +431 -111
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5837,6 +5837,13 @@ var BaseAddon = class {
5837
5837
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5838
5838
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5839
5839
  _registeredCapNames = [];
5840
+ /**
5841
+ * True only after `readAddonStore` actually answered. Constructor
5842
+ * defaults look like stored config when the store is down — a forked
5843
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5844
+ * mode, 2026-08-25) is not "the operator chose this".
5845
+ */
5846
+ settingsStoreReady = false;
5840
5847
  /** Default config values. Provided via constructor. */
5841
5848
  defaults;
5842
5849
  constructor(defaults) {
@@ -6237,7 +6244,9 @@ var BaseAddon = class {
6237
6244
  ];
6238
6245
  let lastErr;
6239
6246
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6240
- return await settings.readAddonStore() ?? {};
6247
+ const stored = await settings.readAddonStore() ?? {};
6248
+ this.settingsStoreReady = true;
6249
+ return stored;
6241
6250
  } catch (err) {
6242
6251
  lastErr = err;
6243
6252
  const msg = err instanceof Error ? err.message : String(err);
@@ -6245,6 +6254,7 @@ var BaseAddon = class {
6245
6254
  if (attempt === delaysMs.length) break;
6246
6255
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6247
6256
  }
6257
+ this.settingsStoreReady = false;
6248
6258
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6249
6259
  return {};
6250
6260
  }
@@ -6656,7 +6666,7 @@ function method(input, output, options) {
6656
6666
  input,
6657
6667
  output,
6658
6668
  kind: options?.kind ?? "query",
6659
- auth: options?.auth ?? "protected",
6669
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6660
6670
  ...options?.access !== void 0 ? { access: options.access } : {},
6661
6671
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6662
6672
  timeoutMs: options?.timeoutMs
@@ -6680,7 +6690,7 @@ function event(data) {
6680
6690
  }
6681
6691
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6682
6692
  var VersionOutputSchema$1 = object({ version: string() });
6683
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6693
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6684
6694
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6685
6695
  DeviceType["Camera"] = "camera";
6686
6696
  DeviceType["Hub"] = "hub";
@@ -7001,7 +7011,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7001
7011
  }({});
7002
7012
  var StaticDirOutputSchema = object({ staticDir: string() });
7003
7013
  var VersionOutputSchema = object({ version: string() });
7004
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7014
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7005
7015
  /**
7006
7016
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7007
7017
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7627,24 +7637,6 @@ var RecordingRetentionSchema = object({
7627
7637
  maxSizeGb: number().min(0).optional()
7628
7638
  });
7629
7639
  /**
7630
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7631
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7632
- * previews at. Five graduated steps; absent on a config = `standard` (the
7633
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7634
- *
7635
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7636
- * Each window's index sidecar carries its own tile dims, so a camera whose
7637
- * preset changed over time renders every historical window at the dims it was
7638
- * written with.
7639
- */
7640
- var ScrubThumbnailPresetSchema = _enum([
7641
- "minimal",
7642
- "low",
7643
- "standard",
7644
- "high",
7645
- "max"
7646
- ]);
7647
- /**
7648
7640
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7649
7641
  *
7650
7642
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7652,7 +7644,11 @@ var ScrubThumbnailPresetSchema = _enum([
7652
7644
  * other field is a storage knob (profiles, segment length, retention, scrub).
7653
7645
  *
7654
7646
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7655
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7647
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7648
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7649
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7650
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7651
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7656
7652
  * A stale caller must fail loudly — silently stripping its legacy intent would
7657
7653
  * persist a band-less config, i.e. silently stop recording the camera.
7658
7654
  */
@@ -7675,14 +7671,7 @@ var RecordingConfigSchema = object({
7675
7671
  * "off" is the absence of a covering band, never a band value.
7676
7672
  */
7677
7673
  bands: array(RecordingBandSchema).default([]),
7678
- retention: RecordingRetentionSchema.optional(),
7679
- /**
7680
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7681
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7682
- * windows only — existing sheets are immutable, and each window's index
7683
- * carries its own tile dims so mixed-preset history renders correctly.
7684
- */
7685
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7674
+ retention: RecordingRetentionSchema.optional()
7686
7675
  }).strict();
7687
7676
  /**
7688
7677
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7758,10 +7747,11 @@ var RelocateFootageInputSchema = object({
7758
7747
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7759
7748
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7760
7749
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7761
- var StorageMigrationMediaMoveInputSchema = object({
7750
+ var RelocateMediaInputSchema = object({
7762
7751
  toLocationId: string(),
7763
7752
  throttleMbps: number().min(1).max(1e3).optional()
7764
- }).extend({ leaseId: string().min(1) });
7753
+ });
7754
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7765
7755
  /** The independently selectable logical storage classes. `recordings`
7766
7756
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7767
7757
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8056,7 +8046,26 @@ var LabelDefinitionSchema = object({
8056
8046
  description: string().optional(),
8057
8047
  icon: string().optional()
8058
8048
  });
8059
- var ClassMapDefinitionSchema = object({
8049
+ /**
8050
+ * Wire schema for a per-model CATALOG classMap override
8051
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8052
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8053
+ * detection pipeline executor actually routes.
8054
+ *
8055
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8056
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8057
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8058
+ * enum) — the two used to share the name `ClassMapDefinition`/
8059
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8060
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8061
+ * are not: it is two different concepts colliding on a name. Keep this type
8062
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8063
+ * would either narrow every `ClassMapDefinition` consumer to the four
8064
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8065
+ * schema exists for (see the "rejects a classMap whose target is not a
8066
+ * detection macro" test in `model-catalog-schema.test.ts`).
8067
+ */
8068
+ var DetectionCatalogClassMapSchema = object({
8060
8069
  mapping: record(string(), _enum([
8061
8070
  "person",
8062
8071
  "vehicle",
@@ -8148,6 +8157,12 @@ var ModelVariantGroupSchema = object({
8148
8157
  */
8149
8158
  resolution: number().int().positive().optional()
8150
8159
  });
8160
+ var ModelProviderIdSchema = _enum([
8161
+ "camstack",
8162
+ "frigate",
8163
+ "scrypted",
8164
+ "custom"
8165
+ ]);
8151
8166
  var ModelCatalogEntrySchema = object({
8152
8167
  id: string(),
8153
8168
  name: string(),
@@ -8245,11 +8260,17 @@ var ModelCatalogEntrySchema = object({
8245
8260
  */
8246
8261
  group: ModelVariantGroupSchema.optional(),
8247
8262
  /**
8263
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8264
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8265
+ * persisted before this field existed (`inferModelProvider` fills those).
8266
+ */
8267
+ provider: ModelProviderIdSchema.optional(),
8268
+ /**
8248
8269
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8249
8270
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8250
8271
  * labels already ARE the CamStack macros (Scrypted identity map).
8251
8272
  */
8252
- classMap: ClassMapDefinitionSchema.optional()
8273
+ classMap: DetectionCatalogClassMapSchema.optional()
8253
8274
  });
8254
8275
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8255
8276
  format: literal("openvino"),
@@ -8279,7 +8300,7 @@ var ModelConvertMetadataSchema = object({
8279
8300
  "segmentation"
8280
8301
  ]),
8281
8302
  faceAlignment: boolean().optional(),
8282
- classMap: ClassMapDefinitionSchema.optional()
8303
+ classMap: DetectionCatalogClassMapSchema.optional()
8283
8304
  });
8284
8305
  var ConvertResultSchema = object({
8285
8306
  entry: ModelCatalogEntrySchema,
@@ -9142,7 +9163,7 @@ var AddonPageDeclarationSchema = object({
9142
9163
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9143
9164
  sectionLabel: string().optional()
9144
9165
  });
9145
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9166
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9146
9167
  var AddonHttpRouteSchema = object({
9147
9168
  method: _enum([
9148
9169
  "GET",
@@ -9377,7 +9398,7 @@ var WidgetMetadataSchema = object({
9377
9398
  defaultColumns: number().int().min(1).max(12).default(6),
9378
9399
  defaultRows: number().int().min(1).max(12).default(1)
9379
9400
  });
9380
- method(_void(), array(WidgetMetadataSchema).readonly());
9401
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9381
9402
  /**
9382
9403
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9383
9404
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11001,7 +11022,7 @@ var CustomModelDescriptorSchema = object({
11001
11022
  stepId: string(),
11002
11023
  entry: ModelCatalogEntrySchema
11003
11024
  });
11004
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11025
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11005
11026
  /**
11006
11027
  * Query filter for settings-store collections.
11007
11028
  */
@@ -11088,7 +11109,8 @@ method(object({
11088
11109
  }), _void(), { kind: "mutation" }), method(object({
11089
11110
  namespace: string().optional(),
11090
11111
  collection: string(),
11091
- filter: QueryFilterSchema.optional()
11112
+ filter: QueryFilterSchema.optional(),
11113
+ columns: array(string()).readonly().optional()
11092
11114
  }), array(SettingsRecordSchema).readonly()), method(object({
11093
11115
  namespace: string().optional(),
11094
11116
  collection: string(),
@@ -11151,46 +11173,87 @@ var EngineInfoSchema = object({
11151
11173
  kind: _enum(["relational", "vector"]),
11152
11174
  displayName: string()
11153
11175
  });
11154
- method(_void(), EngineInfoSchema), method(object({
11176
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11155
11177
  namespace: string().optional(),
11156
11178
  collection: string(),
11157
11179
  key: string()
11158
- }), unknown()), method(object({
11180
+ }), unknown(), { auth: "admin" }), method(object({
11159
11181
  namespace: string().optional(),
11160
11182
  collection: string(),
11161
11183
  key: string(),
11162
11184
  value: unknown()
11163
- }), _void(), { kind: "mutation" }), method(object({
11185
+ }), _void(), {
11186
+ kind: "mutation",
11187
+ auth: "admin"
11188
+ }), method(object({
11164
11189
  namespace: string().optional(),
11165
11190
  collection: string(),
11166
- filter: QueryFilterSchema.optional()
11167
- }), array(SettingsRecordSchema).readonly()), method(object({
11191
+ filter: QueryFilterSchema.optional(),
11192
+ /**
11193
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11194
+ *
11195
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11196
+ * was wrong — corrected 2026-08-26 after the hop map
11197
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11198
+ * There is **no Zod parse at all** between the door and the engine: the
11199
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11200
+ * field declared here reaches `SqliteSettingsBackend` either way.
11201
+ *
11202
+ * What actually lost `columns` was the THIRD declaration of this shape:
11203
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11204
+ * interface the engine destructures from. The field existed on both
11205
+ * schemas and the engine still never read it, because nothing checks a
11206
+ * registered provider against `InferProvider<cap>` —
11207
+ * `ProviderRegistration.provider` is typed `object`.
11208
+ *
11209
+ * It is declared here anyway, and must stay in step with
11210
+ * `settings-store.query`: a caller reading only the cap definitions has
11211
+ * to be able to see that this call carries a projection.
11212
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11213
+ */
11214
+ columns: array(string()).readonly().optional()
11215
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11168
11216
  namespace: string().optional(),
11169
11217
  collection: string(),
11170
11218
  record: SettingsRecordSchema
11171
- }), _void(), { kind: "mutation" }), method(object({
11219
+ }), _void(), {
11220
+ kind: "mutation",
11221
+ auth: "admin"
11222
+ }), method(object({
11172
11223
  namespace: string().optional(),
11173
11224
  collection: string(),
11174
11225
  id: string(),
11175
11226
  data: record(string(), unknown())
11176
- }), _void(), { kind: "mutation" }), method(object({
11227
+ }), _void(), {
11228
+ kind: "mutation",
11229
+ auth: "admin"
11230
+ }), method(object({
11177
11231
  namespace: string().optional(),
11178
11232
  collection: string(),
11179
11233
  key: string()
11180
- }), _void(), { kind: "mutation" }), method(object({
11234
+ }), _void(), {
11235
+ kind: "mutation",
11236
+ auth: "admin"
11237
+ }), method(object({
11181
11238
  namespace: string().optional(),
11182
11239
  collection: string(),
11183
11240
  filter: MutationFilterSchema
11184
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11241
+ }), object({ deleted: number().int() }), {
11242
+ kind: "mutation",
11243
+ auth: "admin"
11244
+ }), method(object({
11185
11245
  namespace: string().optional(),
11186
11246
  collection: string(),
11187
11247
  filter: MutationFilterSchema,
11188
11248
  data: record(string(), unknown())
11189
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11249
+ }), object({ updated: number().int() }), {
11250
+ kind: "mutation",
11251
+ auth: "admin"
11252
+ }), method(object({
11190
11253
  namespace: string().optional(),
11191
11254
  collection: string(),
11192
11255
  filter: QueryFilterSchema.optional()
11193
- }), number()), method(object({
11256
+ }), number(), { auth: "admin" }), method(object({
11194
11257
  namespace: string().optional(),
11195
11258
  collection: string(),
11196
11259
  field: string(),
@@ -11200,15 +11263,18 @@ method(_void(), EngineInfoSchema), method(object({
11200
11263
  }), array(object({
11201
11264
  bucket: number().int(),
11202
11265
  count: number().int()
11203
- })).readonly()), method(object({
11266
+ })).readonly(), { auth: "admin" }), method(object({
11204
11267
  namespace: string().optional(),
11205
11268
  collection: string()
11206
- }), boolean()), method(object({
11269
+ }), boolean(), { auth: "admin" }), method(object({
11207
11270
  namespace: string().optional(),
11208
11271
  collection: string(),
11209
11272
  columns: array(CollectionColumnSchema).readonly(),
11210
11273
  indexes: array(CollectionIndexSchema).readonly().optional()
11211
- }), _void(), { kind: "mutation" });
11274
+ }), _void(), {
11275
+ kind: "mutation",
11276
+ auth: "admin"
11277
+ });
11212
11278
  /**
11213
11279
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11214
11280
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -12053,6 +12119,27 @@ var LinkedDeviceSchema = object({
12053
12119
  features: array(string()),
12054
12120
  producesTrackedEvents: boolean().optional()
12055
12121
  });
12122
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12123
+ * The batch answer needs the tag; the single-device answer already has it
12124
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12125
+ var LinkedDevicesForDeviceSchema = object({
12126
+ deviceId: number(),
12127
+ mode: LinkedDevicesModeSchema,
12128
+ devices: array(LinkedDeviceSchema)
12129
+ });
12130
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12131
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12132
+ * object literal is exactly how the three drift apart. */
12133
+ var DeviceBindingsForDeviceSchema = object({
12134
+ deviceId: number(),
12135
+ entries: array(object({
12136
+ capName: string(),
12137
+ kind: _enum(["native", "wrapped"]),
12138
+ providerAddonId: string(),
12139
+ providerNodeId: string(),
12140
+ nativeAddonId: string()
12141
+ }))
12142
+ });
12056
12143
  var SavedDeviceRowSchema = object({
12057
12144
  /** Numeric id reserved at allocateDeviceId time. */
12058
12145
  id: number(),
@@ -12278,11 +12365,25 @@ method(object({
12278
12365
  projection: _enum(["full", "slim"]).optional(),
12279
12366
  /** Return only camera devices. Filtering server-side instead of
12280
12367
  * shipping 293 rows to find 12. */
12281
- isCamera: boolean().optional()
12368
+ isCamera: boolean().optional(),
12369
+ /**
12370
+ * Return only these device ids. For the caller that already KNOWS the
12371
+ * handful it wants and needs a field the id-bearing answer does not
12372
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12373
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12374
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12375
+ * refetches on the reconcile interval, on a phone.
12376
+ *
12377
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12378
+ * keys rather than rejecting them (verified against the live hub
12379
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12380
+ * it answers today and the caller filters as it already does.
12381
+ */
12382
+ deviceIds: array(number()).optional()
12282
12383
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12283
12384
  mode: LinkedDevicesModeSchema,
12284
12385
  devices: array(LinkedDeviceSchema)
12285
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12386
+ })), method(object({ deviceIds: array(number()) }), array(LinkedDevicesForDeviceSchema)), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12286
12387
  deviceId: number(),
12287
12388
  values: record(string(), unknown())
12288
12389
  }), object({ success: literal(true) }), {
@@ -12309,25 +12410,7 @@ method(object({
12309
12410
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12310
12411
  kind: "mutation",
12311
12412
  auth: "admin"
12312
- }), method(object({ deviceId: number() }), object({
12313
- deviceId: number(),
12314
- entries: array(object({
12315
- capName: string(),
12316
- kind: _enum(["native", "wrapped"]),
12317
- providerAddonId: string(),
12318
- providerNodeId: string(),
12319
- nativeAddonId: string()
12320
- }))
12321
- })), method(object({}), array(object({
12322
- deviceId: number(),
12323
- entries: array(object({
12324
- capName: string(),
12325
- kind: _enum(["native", "wrapped"]),
12326
- providerAddonId: string(),
12327
- providerNodeId: string(),
12328
- nativeAddonId: string()
12329
- }))
12330
- }))), method(object({
12413
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12331
12414
  deviceId: number(),
12332
12415
  capName: string(),
12333
12416
  wrapperAddonId: string(),
@@ -12498,7 +12581,7 @@ method(object({
12498
12581
  crop: _instanceof(Uint8Array),
12499
12582
  width: number(),
12500
12583
  height: number()
12501
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12584
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12502
12585
  /**
12503
12586
  * filesystem-browse — per-node capability for browsing the node's local
12504
12587
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12791,19 +12874,22 @@ method(LlmGenerateBaseInputSchema.extend({
12791
12874
  runtime: ManagedRuntimeConfigSchema,
12792
12875
  /** The managed profile's timeout, threaded by the hub provider. */
12793
12876
  timeoutMs: number().int().positive().optional()
12794
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12877
+ }), LlmGenerateResultSchema, {
12878
+ kind: "mutation",
12879
+ auth: "admin"
12880
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12795
12881
  kind: "mutation",
12796
12882
  auth: "admin"
12797
12883
  }), method(object({}), _void(), {
12798
12884
  kind: "mutation",
12799
12885
  auth: "admin"
12800
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12886
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12801
12887
  kind: "mutation",
12802
12888
  auth: "admin"
12803
12889
  }), method(object({ file: string() }), _void(), {
12804
12890
  kind: "mutation",
12805
12891
  auth: "admin"
12806
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12892
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12807
12893
  /**
12808
12894
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12809
12895
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14737,12 +14823,15 @@ var NcOccupancyConditionSchema = object({
14737
14823
  * there is no second switch that can disagree with the first and every rule
14738
14824
  * authored before the decision migrates for free (`audioModeOf`):
14739
14825
  *
14740
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14741
- * classifier labels with one of them. No window, no percentage:
14742
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14743
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14744
- * the analyzer's (`classificationMinScore`, per device) — a label only
14745
- * reaches this condition if the classifier was already confident enough.
14826
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14827
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14828
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14829
+ * frames is the wrong question for a classifier that labels 1–3 frames
14830
+ * per episode. The count window is the brake that drops a single-frame
14831
+ * false positive; the rule's own `throttle` cooldown is the other. The
14832
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14833
+ * per device) — a label only reaches this condition if the classifier was
14834
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14746
14835
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14747
14836
  * the condition: at least `hitPercent`% of the samples over
14748
14837
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14769,14 +14858,22 @@ var NcOccupancyConditionSchema = object({
14769
14858
  * an operator who typed `dog` mean the same thing.
14770
14859
  */
14771
14860
  var NcAudioConditionSchema = object({
14772
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14861
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14773
14862
  labels: array(string().min(1)).min(1).optional(),
14774
14863
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14775
14864
  dbThreshold: number().min(-96).max(0).optional(),
14776
14865
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14777
14866
  hitPercent: number().int().min(1).max(100).default(60),
14778
14867
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14779
- samplingSeconds: number().int().min(1).max(300).default(10)
14868
+ samplingSeconds: number().int().min(1).max(300).default(10),
14869
+ /**
14870
+ * LABEL MODE: how many labelled frames must land inside
14871
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14872
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14873
+ */
14874
+ confirmHits: number().int().min(1).max(20).optional(),
14875
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14876
+ confirmWindowSec: number().int().min(1).max(60).optional()
14780
14877
  });
14781
14878
  /**
14782
14879
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16303,7 +16400,7 @@ var OauthIntegrationDescriptorSchema = object({
16303
16400
  */
16304
16401
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16305
16402
  });
16306
- method(_void(), OauthIntegrationDescriptorSchema);
16403
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16307
16404
  /**
16308
16405
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16309
16406
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17150,6 +17247,46 @@ var RecentTracksPageSchema = object({
17150
17247
  /** Cursor for the next page, or null when this page is the last. */
17151
17248
  nextCursor: string().nullable()
17152
17249
  });
17250
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17251
+ var LIST_GROUPS_MAX_LIMIT = 100;
17252
+ var AnalyticsGroupRecordSchema = object({
17253
+ id: string(),
17254
+ deviceId: number().int(),
17255
+ openedAt: number().int(),
17256
+ closedAt: number().int(),
17257
+ timestamp: number().int(),
17258
+ memberCount: number().int(),
17259
+ memberTrackIds: array(string()).readonly(),
17260
+ className: string(),
17261
+ classes: array(string()).readonly(),
17262
+ /** Relative event-media path, or null when the group has no picture yet. */
17263
+ mediaUrl: string().nullable(),
17264
+ singleton: boolean()
17265
+ });
17266
+ var AnalyticsGroupMemberSchema = object({
17267
+ trackId: string(),
17268
+ deviceId: number().int(),
17269
+ className: string(),
17270
+ firstSeen: number().int(),
17271
+ lastSeen: number().int(),
17272
+ mediaUrl: string().nullable()
17273
+ });
17274
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17275
+ var ListGroupsQueryInput = object({
17276
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17277
+ deviceIds: array(number()),
17278
+ /** Window lower bound on `closedAt` (inclusive). */
17279
+ since: number().optional(),
17280
+ /** Window upper bound on `openedAt` (inclusive). */
17281
+ until: number().optional(),
17282
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17283
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17284
+ cursor: string().optional()
17285
+ });
17286
+ var ListGroupsPageSchema = object({
17287
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17288
+ nextCursor: string().nullable()
17289
+ });
17153
17290
  var KeyEventQueryInput = object({
17154
17291
  deviceId: number(),
17155
17292
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17225,7 +17362,9 @@ var TrackCascadeCountsSchema = object({
17225
17362
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17226
17363
  plates: number().int(),
17227
17364
  /** Per-track CLIP search vectors removed (best-effort). */
17228
- embeddings: number().int()
17365
+ embeddings: number().int(),
17366
+ /** Group membership + group rows removed with their last member (best-effort). */
17367
+ groups: number().int()
17229
17368
  });
17230
17369
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17231
17370
  var DiskReconcileCountsSchema = object({
@@ -17371,7 +17510,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17371
17510
  * stationary registry). Default false: the timeline lists passages,
17372
17511
  * not parking records (operator decision, 2026-08-15). */
17373
17512
  includeStationary: boolean().optional()
17374
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17513
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17514
+ deviceId: number(),
17515
+ groupId: string().min(1)
17516
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17375
17517
  kind: "mutation",
17376
17518
  auth: "admin"
17377
17519
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -17453,6 +17595,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17453
17595
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17454
17596
  kind: "mutation",
17455
17597
  auth: "admin"
17598
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17599
+ kind: "mutation",
17600
+ auth: "admin"
17601
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17602
+ kind: "query",
17603
+ auth: "admin"
17604
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17605
+ kind: "mutation",
17606
+ auth: "admin"
17456
17607
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17457
17608
  kind: "query",
17458
17609
  auth: "admin"
@@ -17607,6 +17758,11 @@ object({
17607
17758
  "jpeg"
17608
17759
  ])
17609
17760
  });
17761
+ /**
17762
+ * Process-local frame identity. It is serializable so it can ride an in-process
17763
+ * capability call, but `registryId` deliberately prevents resolution in any
17764
+ * other process or execution group.
17765
+ */
17610
17766
  var FrameRefSchema = object({
17611
17767
  registryId: string().min(1),
17612
17768
  id: string().min(1),
@@ -17681,7 +17837,8 @@ var PipelineModelOptionSchema = object({
17681
17837
  sizeMB: number()
17682
17838
  })),
17683
17839
  group: ModelVariantGroupSchema.optional(),
17684
- legacy: boolean().optional()
17840
+ legacy: boolean().optional(),
17841
+ provider: ModelProviderIdSchema.optional()
17685
17842
  });
17686
17843
  var ConfigFieldBridge = custom();
17687
17844
  var PipelineAddonSchemaSchema = object({
@@ -19811,7 +19968,7 @@ method(object({
19811
19968
  * linking rather than produce an eternal token.
19812
19969
  */
19813
19970
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19814
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19971
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19815
19972
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19816
19973
  providerId: string().min(1),
19817
19974
  displayName: string().min(1),
@@ -19906,10 +20063,13 @@ var EvictResultSchema = object({
19906
20063
  /** True when the provider has nothing left it is willing to drop on this location. */
19907
20064
  exhausted: boolean()
19908
20065
  });
19909
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20066
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19910
20067
  locationId: string(),
19911
20068
  targetBytes: number().int().positive()
19912
- }), EvictResultSchema, { kind: "mutation" });
20069
+ }), EvictResultSchema, {
20070
+ kind: "mutation",
20071
+ auth: "admin"
20072
+ });
19913
20073
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19914
20074
  kind: "mutation",
19915
20075
  auth: "admin"
@@ -19969,26 +20129,50 @@ var ReadChunkInputSchema = object({
19969
20129
  length: number()
19970
20130
  });
19971
20131
  var EndDownloadInputSchema = object({ downloadId: string() });
19972
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20132
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19973
20133
  location: StorageLocationSchema,
19974
20134
  relativePath: string()
19975
- }), string()), method(object({
20135
+ }), string(), { auth: "admin" }), method(object({
19976
20136
  location: StorageLocationSchema,
19977
20137
  relativePath: string(),
19978
20138
  data: _instanceof(Uint8Array)
19979
- }), _void(), { kind: "mutation" }), method(object({
20139
+ }), _void(), {
20140
+ kind: "mutation",
20141
+ auth: "admin"
20142
+ }), method(object({
19980
20143
  location: StorageLocationSchema,
19981
20144
  relativePath: string()
19982
- }), _instanceof(Uint8Array)), method(object({
20145
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19983
20146
  location: StorageLocationSchema,
19984
20147
  relativePath: string()
19985
- }), boolean()), method(object({
20148
+ }), boolean(), { auth: "admin" }), method(object({
19986
20149
  location: StorageLocationSchema,
19987
20150
  prefix: string().optional()
19988
- }), array(string()).readonly()), method(object({
20151
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19989
20152
  location: StorageLocationSchema,
19990
20153
  relativePath: string()
19991
- }), _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" });
20154
+ }), _void(), {
20155
+ kind: "mutation",
20156
+ auth: "admin"
20157
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20158
+ kind: "mutation",
20159
+ auth: "admin"
20160
+ }), method(WriteChunkInputSchema, _void(), {
20161
+ kind: "mutation",
20162
+ auth: "admin"
20163
+ }), method(FinalizeUploadInputSchema, _void(), {
20164
+ kind: "mutation",
20165
+ auth: "admin"
20166
+ }), method(AbortUploadInputSchema, _void(), {
20167
+ kind: "mutation",
20168
+ auth: "admin"
20169
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20170
+ kind: "mutation",
20171
+ auth: "admin"
20172
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20173
+ kind: "mutation",
20174
+ auth: "admin"
20175
+ });
19992
20176
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19993
20177
  var ProfileSettingsSchemaBridge = unknown().nullable();
19994
20178
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20246,7 +20430,8 @@ method(object({
20246
20430
  access: "create"
20247
20431
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20248
20432
  kind: "mutation",
20249
- access: "view"
20433
+ access: "view",
20434
+ auth: "admin"
20250
20435
  }), method(object({
20251
20436
  /** Required — the user the assertion belongs to (verified). */
20252
20437
  userId: string(),
@@ -20254,10 +20439,12 @@ method(object({
20254
20439
  response: record(string(), unknown())
20255
20440
  }), object({ verified: boolean() }), {
20256
20441
  kind: "mutation",
20257
- access: "view"
20442
+ access: "view",
20443
+ auth: "admin"
20258
20444
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20259
20445
  kind: "mutation",
20260
- access: "view"
20446
+ access: "view",
20447
+ auth: "admin"
20261
20448
  }), method(object({
20262
20449
  /** AuthenticationResponseJSON from the browser. */
20263
20450
  response: record(string(), unknown()) }), object({
@@ -20265,7 +20452,8 @@ response: record(string(), unknown()) }), object({
20265
20452
  userId: string().nullable()
20266
20453
  }), {
20267
20454
  kind: "mutation",
20268
- access: "view"
20455
+ access: "view",
20456
+ auth: "admin"
20269
20457
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20270
20458
  userId: string(),
20271
20459
  credentialId: string()
@@ -20437,7 +20625,19 @@ var VectorStatsResultSchema = object({
20437
20625
  /** False when the backend ranks approximately. */
20438
20626
  exact: boolean()
20439
20627
  });
20440
- 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);
20628
+ method(VectorDeclareIndexInputSchema, _void(), {
20629
+ kind: "mutation",
20630
+ auth: "admin"
20631
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20632
+ kind: "mutation",
20633
+ auth: "admin"
20634
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20635
+ kind: "mutation",
20636
+ auth: "admin"
20637
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20638
+ kind: "mutation",
20639
+ auth: "admin"
20640
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20441
20641
  var ClipSchema = object({
20442
20642
  /** Opaque, provider-namespaced id. The default provider encodes the time
20443
20643
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -22898,7 +23098,27 @@ var MediaFileLiteSchema$1 = object({
22898
23098
  sizeBytes: number(),
22899
23099
  timestamp: number()
22900
23100
  });
22901
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23101
+ method(object({
23102
+ /**
23103
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23104
+ *
23105
+ * Default `false`, the same inversion `listRecentFaces` and
23106
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23107
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23108
+ * on the live hub the same day: four identities cost 40,979 B with the
23109
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23110
+ * four times and the viewer holds at `staleTime: 30_000`.
23111
+ *
23112
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23113
+ * the `event-media` plane serves that key `immutable` with an ETag.
23114
+ *
23115
+ * **This is an INPUT field, so it does not reach the addon until the
23116
+ * next train** — the hub router validates cap inputs against its own
23117
+ * compiled Zod and strips a key it does not know. Until then the
23118
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23119
+ * is what ships, and the opt-in becomes reachable when the train lands.
23120
+ */
23121
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22902
23122
  kind: "mutation",
22903
23123
  auth: "admin"
22904
23124
  }), method(object({
@@ -25786,7 +26006,14 @@ var PlateInfoSchema = object({
25786
26006
  plateBbox: BoundingBoxSchema.optional(),
25787
26007
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25788
26008
  keyFrameMediaKey: string().optional(),
25789
- base64: string().optional()
26009
+ base64: string().optional(),
26010
+ /**
26011
+ * Same crop as a data-plane URL, always present when the plate has a stored
26012
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26013
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26014
+ * left at its `true` default.
26015
+ */
26016
+ cropUrl: string().optional()
25790
26017
  });
25791
26018
  var MediaFileLiteSchema = object({
25792
26019
  key: string(),
@@ -25804,14 +26031,34 @@ var PlateClusterSchema = object({
25804
26031
  });
25805
26032
  method(object({
25806
26033
  deviceId: number().int().optional(),
25807
- limit: number().int().positive().optional()
26034
+ limit: number().int().positive().optional(),
26035
+ /**
26036
+ * Inline the base64 crop on every row. Default `true` — the existing
26037
+ * behaviour, kept so no caller breaks.
26038
+ *
26039
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26040
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26041
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26042
+ * metadata without them — and the browser then caches the images.
26043
+ *
26044
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26045
+ * plates were the one gallery list left without it.
26046
+ *
26047
+ * **This is an INPUT field, so it does not reach the addon until the
26048
+ * next train.** The hub router validates cap inputs against its own
26049
+ * compiled Zod and strips a key it does not know. Until the train
26050
+ * ships, sending `false` is harmless and keeps the crops inline.
26051
+ */
26052
+ includeCrops: boolean().optional()
25808
26053
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
25809
26054
  deviceId: number().int(),
25810
26055
  trackId: string()
25811
26056
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
25812
26057
  text: string().min(1),
25813
26058
  maxDistance: number().int().min(0).optional(),
25814
- limit: number().int().positive().optional()
26059
+ limit: number().int().positive().optional(),
26060
+ /** See `listPlates.includeCrops`. Default `true`. */
26061
+ includeCrops: boolean().optional()
25815
26062
  }), array(PlateInfoSchema).readonly()), method(object({
25816
26063
  maxDistance: number().int().min(0).optional(),
25817
26064
  minClusterSize: number().int().min(2).optional(),
@@ -25825,7 +26072,13 @@ method(object({
25825
26072
  }), method(object({ plateId: string() }), _void(), {
25826
26073
  kind: "mutation",
25827
26074
  auth: "admin"
25828
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26075
+ }), method(object({
26076
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26077
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26078
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26079
+ * INPUT field: stripped by the hub router until the train ships, which
26080
+ * resolves to `false` and is exactly the intended default. */
26081
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
25829
26082
  kind: "mutation",
25830
26083
  auth: "admin"
25831
26084
  }), method(object({
@@ -31310,6 +31563,12 @@ Object.freeze({
31310
31563
  addonId: null,
31311
31564
  access: "view"
31312
31565
  },
31566
+ "deviceManager.getBindingsBatch": {
31567
+ capName: "device-manager",
31568
+ capScope: "system",
31569
+ addonId: null,
31570
+ access: "view"
31571
+ },
31313
31572
  "deviceManager.getChildren": {
31314
31573
  capName: "device-manager",
31315
31574
  capScope: "system",
@@ -31370,6 +31629,12 @@ Object.freeze({
31370
31629
  addonId: null,
31371
31630
  access: "view"
31372
31631
  },
31632
+ "deviceManager.getLinkedDevicesBatch": {
31633
+ capName: "device-manager",
31634
+ capScope: "system",
31635
+ addonId: null,
31636
+ access: "view"
31637
+ },
31373
31638
  "deviceManager.getRoleDisplayDefaults": {
31374
31639
  capName: "device-manager",
31375
31640
  capScope: "system",
@@ -33074,6 +33339,12 @@ Object.freeze({
33074
33339
  addonId: null,
33075
33340
  access: "create"
33076
33341
  },
33342
+ "pipelineAnalytics.cancelRelocateMedia": {
33343
+ capName: "pipeline-analytics",
33344
+ capScope: "device",
33345
+ addonId: null,
33346
+ access: "create"
33347
+ },
33077
33348
  "pipelineAnalytics.cancelStorageMigrationMove": {
33078
33349
  capName: "pipeline-analytics",
33079
33350
  capScope: "device",
@@ -33140,6 +33411,12 @@ Object.freeze({
33140
33411
  addonId: null,
33141
33412
  access: "view"
33142
33413
  },
33414
+ "pipelineAnalytics.getGroup": {
33415
+ capName: "pipeline-analytics",
33416
+ capScope: "device",
33417
+ addonId: null,
33418
+ access: "view"
33419
+ },
33143
33420
  "pipelineAnalytics.getKeyEvents": {
33144
33421
  capName: "pipeline-analytics",
33145
33422
  capScope: "device",
@@ -33224,6 +33501,12 @@ Object.freeze({
33224
33501
  addonId: null,
33225
33502
  access: "view"
33226
33503
  },
33504
+ "pipelineAnalytics.listGroups": {
33505
+ capName: "pipeline-analytics",
33506
+ capScope: "device",
33507
+ addonId: null,
33508
+ access: "view"
33509
+ },
33227
33510
  "pipelineAnalytics.listOpsLog": {
33228
33511
  capName: "pipeline-analytics",
33229
33512
  capScope: "device",
@@ -33236,6 +33519,12 @@ Object.freeze({
33236
33519
  addonId: null,
33237
33520
  access: "view"
33238
33521
  },
33522
+ "pipelineAnalytics.listRelocateMediaJobs": {
33523
+ capName: "pipeline-analytics",
33524
+ capScope: "device",
33525
+ addonId: null,
33526
+ access: "view"
33527
+ },
33239
33528
  "pipelineAnalytics.listRetrainAnnotations": {
33240
33529
  capName: "pipeline-analytics",
33241
33530
  capScope: "device",
@@ -33314,6 +33603,12 @@ Object.freeze({
33314
33603
  addonId: null,
33315
33604
  access: "create"
33316
33605
  },
33606
+ "pipelineAnalytics.relocateMedia": {
33607
+ capName: "pipeline-analytics",
33608
+ capScope: "device",
33609
+ addonId: null,
33610
+ access: "create"
33611
+ },
33317
33612
  "pipelineAnalytics.restageRetrainTrack": {
33318
33613
  capName: "pipeline-analytics",
33319
33614
  capScope: "device",
@@ -36005,6 +36300,11 @@ Object.freeze({
36005
36300
  form: "single",
36006
36301
  optional: false
36007
36302
  }],
36303
+ "deviceManager.getBindingsBatch": [{
36304
+ name: "deviceIds",
36305
+ form: "array",
36306
+ optional: false
36307
+ }],
36008
36308
  "deviceManager.getChildren": [{
36009
36309
  name: "parentDeviceId",
36010
36310
  form: "single",
@@ -36050,6 +36350,11 @@ Object.freeze({
36050
36350
  form: "single",
36051
36351
  optional: false
36052
36352
  }],
36353
+ "deviceManager.getLinkedDevicesBatch": [{
36354
+ name: "deviceIds",
36355
+ form: "array",
36356
+ optional: false
36357
+ }],
36053
36358
  "deviceManager.getSettingsSchema": [{
36054
36359
  name: "deviceId",
36055
36360
  form: "single",
@@ -36070,6 +36375,11 @@ Object.freeze({
36070
36375
  form: "single",
36071
36376
  optional: false
36072
36377
  }],
36378
+ "deviceManager.listAll": [{
36379
+ name: "deviceIds",
36380
+ form: "array",
36381
+ optional: true
36382
+ }],
36073
36383
  "deviceManager.loadConfig": [{
36074
36384
  name: "deviceId",
36075
36385
  form: "single",
@@ -36643,6 +36953,11 @@ Object.freeze({
36643
36953
  form: "single",
36644
36954
  optional: false
36645
36955
  }],
36956
+ "pipelineAnalytics.getGroup": [{
36957
+ name: "deviceId",
36958
+ form: "single",
36959
+ optional: false
36960
+ }],
36646
36961
  "pipelineAnalytics.getKeyEvents": [{
36647
36962
  name: "deviceId",
36648
36963
  form: "single",
@@ -36698,6 +37013,11 @@ Object.freeze({
36698
37013
  form: "array",
36699
37014
  optional: false
36700
37015
  }],
37016
+ "pipelineAnalytics.listGroups": [{
37017
+ name: "deviceIds",
37018
+ form: "array",
37019
+ optional: false
37020
+ }],
36701
37021
  "pipelineAnalytics.listOpsLog": [{
36702
37022
  name: "deviceId",
36703
37023
  form: "single",