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