@camstack/addon-provider-wyze 0.2.31 → 0.2.33

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
@@ -5833,6 +5833,13 @@ var BaseAddon = class {
5833
5833
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5834
5834
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5835
5835
  _registeredCapNames = [];
5836
+ /**
5837
+ * True only after `readAddonStore` actually answered. Constructor
5838
+ * defaults look like stored config when the store is down — a forked
5839
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5840
+ * mode, 2026-08-25) is not "the operator chose this".
5841
+ */
5842
+ settingsStoreReady = false;
5836
5843
  /** Default config values. Provided via constructor. */
5837
5844
  defaults;
5838
5845
  constructor(defaults) {
@@ -6233,7 +6240,9 @@ var BaseAddon = class {
6233
6240
  ];
6234
6241
  let lastErr;
6235
6242
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6236
- return await settings.readAddonStore() ?? {};
6243
+ const stored = await settings.readAddonStore() ?? {};
6244
+ this.settingsStoreReady = true;
6245
+ return stored;
6237
6246
  } catch (err) {
6238
6247
  lastErr = err;
6239
6248
  const msg = err instanceof Error ? err.message : String(err);
@@ -6241,6 +6250,7 @@ var BaseAddon = class {
6241
6250
  if (attempt === delaysMs.length) break;
6242
6251
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6243
6252
  }
6253
+ this.settingsStoreReady = false;
6244
6254
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6245
6255
  return {};
6246
6256
  }
@@ -6652,7 +6662,7 @@ function method(input, output, options) {
6652
6662
  input,
6653
6663
  output,
6654
6664
  kind: options?.kind ?? "query",
6655
- auth: options?.auth ?? "protected",
6665
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6656
6666
  ...options?.access !== void 0 ? { access: options.access } : {},
6657
6667
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6658
6668
  timeoutMs: options?.timeoutMs
@@ -6676,7 +6686,7 @@ function event(data) {
6676
6686
  }
6677
6687
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6678
6688
  var VersionOutputSchema$1 = object({ version: string() });
6679
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6689
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6680
6690
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6681
6691
  DeviceType["Camera"] = "camera";
6682
6692
  DeviceType["Hub"] = "hub";
@@ -6997,7 +7007,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6997
7007
  }({});
6998
7008
  var StaticDirOutputSchema = object({ staticDir: string() });
6999
7009
  var VersionOutputSchema = object({ version: string() });
7000
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7010
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7001
7011
  /**
7002
7012
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7003
7013
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7623,24 +7633,6 @@ var RecordingRetentionSchema = object({
7623
7633
  maxSizeGb: number().min(0).optional()
7624
7634
  });
7625
7635
  /**
7626
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7627
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7628
- * previews at. Five graduated steps; absent on a config = `standard` (the
7629
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7630
- *
7631
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7632
- * Each window's index sidecar carries its own tile dims, so a camera whose
7633
- * preset changed over time renders every historical window at the dims it was
7634
- * written with.
7635
- */
7636
- var ScrubThumbnailPresetSchema = _enum([
7637
- "minimal",
7638
- "low",
7639
- "standard",
7640
- "high",
7641
- "max"
7642
- ]);
7643
- /**
7644
7636
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7645
7637
  *
7646
7638
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7648,7 +7640,11 @@ var ScrubThumbnailPresetSchema = _enum([
7648
7640
  * other field is a storage knob (profiles, segment length, retention, scrub).
7649
7641
  *
7650
7642
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7651
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7643
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7644
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7645
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7646
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7647
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7652
7648
  * A stale caller must fail loudly — silently stripping its legacy intent would
7653
7649
  * persist a band-less config, i.e. silently stop recording the camera.
7654
7650
  */
@@ -7671,14 +7667,7 @@ var RecordingConfigSchema = object({
7671
7667
  * "off" is the absence of a covering band, never a band value.
7672
7668
  */
7673
7669
  bands: array(RecordingBandSchema).default([]),
7674
- retention: RecordingRetentionSchema.optional(),
7675
- /**
7676
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7677
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7678
- * windows only — existing sheets are immutable, and each window's index
7679
- * carries its own tile dims so mixed-preset history renders correctly.
7680
- */
7681
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7670
+ retention: RecordingRetentionSchema.optional()
7682
7671
  }).strict();
7683
7672
  /**
7684
7673
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7754,10 +7743,11 @@ var RelocateFootageInputSchema = object({
7754
7743
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7755
7744
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7756
7745
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7757
- var StorageMigrationMediaMoveInputSchema = object({
7746
+ var RelocateMediaInputSchema = object({
7758
7747
  toLocationId: string(),
7759
7748
  throttleMbps: number().min(1).max(1e3).optional()
7760
- }).extend({ leaseId: string().min(1) });
7749
+ });
7750
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7761
7751
  /** The independently selectable logical storage classes. `recordings`
7762
7752
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7763
7753
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8052,7 +8042,26 @@ var LabelDefinitionSchema = object({
8052
8042
  description: string().optional(),
8053
8043
  icon: string().optional()
8054
8044
  });
8055
- var ClassMapDefinitionSchema = object({
8045
+ /**
8046
+ * Wire schema for a per-model CATALOG classMap override
8047
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8048
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8049
+ * detection pipeline executor actually routes.
8050
+ *
8051
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8052
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8053
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8054
+ * enum) — the two used to share the name `ClassMapDefinition`/
8055
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8056
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8057
+ * are not: it is two different concepts colliding on a name. Keep this type
8058
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8059
+ * would either narrow every `ClassMapDefinition` consumer to the four
8060
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8061
+ * schema exists for (see the "rejects a classMap whose target is not a
8062
+ * detection macro" test in `model-catalog-schema.test.ts`).
8063
+ */
8064
+ var DetectionCatalogClassMapSchema = object({
8056
8065
  mapping: record(string(), _enum([
8057
8066
  "person",
8058
8067
  "vehicle",
@@ -8144,6 +8153,12 @@ var ModelVariantGroupSchema = object({
8144
8153
  */
8145
8154
  resolution: number().int().positive().optional()
8146
8155
  });
8156
+ var ModelProviderIdSchema = _enum([
8157
+ "camstack",
8158
+ "frigate",
8159
+ "scrypted",
8160
+ "custom"
8161
+ ]);
8147
8162
  var ModelCatalogEntrySchema = object({
8148
8163
  id: string(),
8149
8164
  name: string(),
@@ -8241,11 +8256,17 @@ var ModelCatalogEntrySchema = object({
8241
8256
  */
8242
8257
  group: ModelVariantGroupSchema.optional(),
8243
8258
  /**
8259
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8260
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8261
+ * persisted before this field existed (`inferModelProvider` fills those).
8262
+ */
8263
+ provider: ModelProviderIdSchema.optional(),
8264
+ /**
8244
8265
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8245
8266
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8246
8267
  * labels already ARE the CamStack macros (Scrypted identity map).
8247
8268
  */
8248
- classMap: ClassMapDefinitionSchema.optional()
8269
+ classMap: DetectionCatalogClassMapSchema.optional()
8249
8270
  });
8250
8271
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8251
8272
  format: literal("openvino"),
@@ -8275,7 +8296,7 @@ var ModelConvertMetadataSchema = object({
8275
8296
  "segmentation"
8276
8297
  ]),
8277
8298
  faceAlignment: boolean().optional(),
8278
- classMap: ClassMapDefinitionSchema.optional()
8299
+ classMap: DetectionCatalogClassMapSchema.optional()
8279
8300
  });
8280
8301
  var ConvertResultSchema = object({
8281
8302
  entry: ModelCatalogEntrySchema,
@@ -9138,7 +9159,7 @@ var AddonPageDeclarationSchema = object({
9138
9159
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9139
9160
  sectionLabel: string().optional()
9140
9161
  });
9141
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9162
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9142
9163
  var AddonHttpRouteSchema = object({
9143
9164
  method: _enum([
9144
9165
  "GET",
@@ -9373,7 +9394,7 @@ var WidgetMetadataSchema = object({
9373
9394
  defaultColumns: number().int().min(1).max(12).default(6),
9374
9395
  defaultRows: number().int().min(1).max(12).default(1)
9375
9396
  });
9376
- method(_void(), array(WidgetMetadataSchema).readonly());
9397
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9377
9398
  /**
9378
9399
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9379
9400
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -10997,7 +11018,7 @@ var CustomModelDescriptorSchema = object({
10997
11018
  stepId: string(),
10998
11019
  entry: ModelCatalogEntrySchema
10999
11020
  });
11000
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11021
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11001
11022
  /**
11002
11023
  * Query filter for settings-store collections.
11003
11024
  */
@@ -11084,7 +11105,8 @@ method(object({
11084
11105
  }), _void(), { kind: "mutation" }), method(object({
11085
11106
  namespace: string().optional(),
11086
11107
  collection: string(),
11087
- filter: QueryFilterSchema.optional()
11108
+ filter: QueryFilterSchema.optional(),
11109
+ columns: array(string()).readonly().optional()
11088
11110
  }), array(SettingsRecordSchema).readonly()), method(object({
11089
11111
  namespace: string().optional(),
11090
11112
  collection: string(),
@@ -11147,46 +11169,87 @@ var EngineInfoSchema = object({
11147
11169
  kind: _enum(["relational", "vector"]),
11148
11170
  displayName: string()
11149
11171
  });
11150
- method(_void(), EngineInfoSchema), method(object({
11172
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11151
11173
  namespace: string().optional(),
11152
11174
  collection: string(),
11153
11175
  key: string()
11154
- }), unknown()), method(object({
11176
+ }), unknown(), { auth: "admin" }), method(object({
11155
11177
  namespace: string().optional(),
11156
11178
  collection: string(),
11157
11179
  key: string(),
11158
11180
  value: unknown()
11159
- }), _void(), { kind: "mutation" }), method(object({
11181
+ }), _void(), {
11182
+ kind: "mutation",
11183
+ auth: "admin"
11184
+ }), method(object({
11160
11185
  namespace: string().optional(),
11161
11186
  collection: string(),
11162
- filter: QueryFilterSchema.optional()
11163
- }), array(SettingsRecordSchema).readonly()), method(object({
11187
+ filter: QueryFilterSchema.optional(),
11188
+ /**
11189
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11190
+ *
11191
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11192
+ * was wrong — corrected 2026-08-26 after the hop map
11193
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11194
+ * There is **no Zod parse at all** between the door and the engine: the
11195
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11196
+ * field declared here reaches `SqliteSettingsBackend` either way.
11197
+ *
11198
+ * What actually lost `columns` was the THIRD declaration of this shape:
11199
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11200
+ * interface the engine destructures from. The field existed on both
11201
+ * schemas and the engine still never read it, because nothing checks a
11202
+ * registered provider against `InferProvider<cap>` —
11203
+ * `ProviderRegistration.provider` is typed `object`.
11204
+ *
11205
+ * It is declared here anyway, and must stay in step with
11206
+ * `settings-store.query`: a caller reading only the cap definitions has
11207
+ * to be able to see that this call carries a projection.
11208
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11209
+ */
11210
+ columns: array(string()).readonly().optional()
11211
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11164
11212
  namespace: string().optional(),
11165
11213
  collection: string(),
11166
11214
  record: SettingsRecordSchema
11167
- }), _void(), { kind: "mutation" }), method(object({
11215
+ }), _void(), {
11216
+ kind: "mutation",
11217
+ auth: "admin"
11218
+ }), method(object({
11168
11219
  namespace: string().optional(),
11169
11220
  collection: string(),
11170
11221
  id: string(),
11171
11222
  data: record(string(), unknown())
11172
- }), _void(), { kind: "mutation" }), method(object({
11223
+ }), _void(), {
11224
+ kind: "mutation",
11225
+ auth: "admin"
11226
+ }), method(object({
11173
11227
  namespace: string().optional(),
11174
11228
  collection: string(),
11175
11229
  key: string()
11176
- }), _void(), { kind: "mutation" }), method(object({
11230
+ }), _void(), {
11231
+ kind: "mutation",
11232
+ auth: "admin"
11233
+ }), method(object({
11177
11234
  namespace: string().optional(),
11178
11235
  collection: string(),
11179
11236
  filter: MutationFilterSchema
11180
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11237
+ }), object({ deleted: number().int() }), {
11238
+ kind: "mutation",
11239
+ auth: "admin"
11240
+ }), method(object({
11181
11241
  namespace: string().optional(),
11182
11242
  collection: string(),
11183
11243
  filter: MutationFilterSchema,
11184
11244
  data: record(string(), unknown())
11185
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11245
+ }), object({ updated: number().int() }), {
11246
+ kind: "mutation",
11247
+ auth: "admin"
11248
+ }), method(object({
11186
11249
  namespace: string().optional(),
11187
11250
  collection: string(),
11188
11251
  filter: QueryFilterSchema.optional()
11189
- }), number()), method(object({
11252
+ }), number(), { auth: "admin" }), method(object({
11190
11253
  namespace: string().optional(),
11191
11254
  collection: string(),
11192
11255
  field: string(),
@@ -11196,15 +11259,18 @@ method(_void(), EngineInfoSchema), method(object({
11196
11259
  }), array(object({
11197
11260
  bucket: number().int(),
11198
11261
  count: number().int()
11199
- })).readonly()), method(object({
11262
+ })).readonly(), { auth: "admin" }), method(object({
11200
11263
  namespace: string().optional(),
11201
11264
  collection: string()
11202
- }), boolean()), method(object({
11265
+ }), boolean(), { auth: "admin" }), method(object({
11203
11266
  namespace: string().optional(),
11204
11267
  collection: string(),
11205
11268
  columns: array(CollectionColumnSchema).readonly(),
11206
11269
  indexes: array(CollectionIndexSchema).readonly().optional()
11207
- }), _void(), { kind: "mutation" });
11270
+ }), _void(), {
11271
+ kind: "mutation",
11272
+ auth: "admin"
11273
+ });
11208
11274
  /**
11209
11275
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11210
11276
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -12049,6 +12115,27 @@ var LinkedDeviceSchema = object({
12049
12115
  features: array(string()),
12050
12116
  producesTrackedEvents: boolean().optional()
12051
12117
  });
12118
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12119
+ * The batch answer needs the tag; the single-device answer already has it
12120
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12121
+ var LinkedDevicesForDeviceSchema = object({
12122
+ deviceId: number(),
12123
+ mode: LinkedDevicesModeSchema,
12124
+ devices: array(LinkedDeviceSchema)
12125
+ });
12126
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12127
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12128
+ * object literal is exactly how the three drift apart. */
12129
+ var DeviceBindingsForDeviceSchema = object({
12130
+ deviceId: number(),
12131
+ entries: array(object({
12132
+ capName: string(),
12133
+ kind: _enum(["native", "wrapped"]),
12134
+ providerAddonId: string(),
12135
+ providerNodeId: string(),
12136
+ nativeAddonId: string()
12137
+ }))
12138
+ });
12052
12139
  var SavedDeviceRowSchema = object({
12053
12140
  /** Numeric id reserved at allocateDeviceId time. */
12054
12141
  id: number(),
@@ -12274,11 +12361,25 @@ method(object({
12274
12361
  projection: _enum(["full", "slim"]).optional(),
12275
12362
  /** Return only camera devices. Filtering server-side instead of
12276
12363
  * shipping 293 rows to find 12. */
12277
- isCamera: boolean().optional()
12364
+ isCamera: boolean().optional(),
12365
+ /**
12366
+ * Return only these device ids. For the caller that already KNOWS the
12367
+ * handful it wants and needs a field the id-bearing answer does not
12368
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12369
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12370
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12371
+ * refetches on the reconcile interval, on a phone.
12372
+ *
12373
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12374
+ * keys rather than rejecting them (verified against the live hub
12375
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12376
+ * it answers today and the caller filters as it already does.
12377
+ */
12378
+ deviceIds: array(number()).optional()
12278
12379
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12279
12380
  mode: LinkedDevicesModeSchema,
12280
12381
  devices: array(LinkedDeviceSchema)
12281
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12382
+ })), 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({
12282
12383
  deviceId: number(),
12283
12384
  values: record(string(), unknown())
12284
12385
  }), object({ success: literal(true) }), {
@@ -12305,25 +12406,7 @@ method(object({
12305
12406
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12306
12407
  kind: "mutation",
12307
12408
  auth: "admin"
12308
- }), method(object({ deviceId: number() }), object({
12309
- deviceId: number(),
12310
- entries: array(object({
12311
- capName: string(),
12312
- kind: _enum(["native", "wrapped"]),
12313
- providerAddonId: string(),
12314
- providerNodeId: string(),
12315
- nativeAddonId: string()
12316
- }))
12317
- })), method(object({}), array(object({
12318
- deviceId: number(),
12319
- entries: array(object({
12320
- capName: string(),
12321
- kind: _enum(["native", "wrapped"]),
12322
- providerAddonId: string(),
12323
- providerNodeId: string(),
12324
- nativeAddonId: string()
12325
- }))
12326
- }))), method(object({
12409
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12327
12410
  deviceId: number(),
12328
12411
  capName: string(),
12329
12412
  wrapperAddonId: string(),
@@ -12494,7 +12577,7 @@ method(object({
12494
12577
  crop: _instanceof(Uint8Array),
12495
12578
  width: number(),
12496
12579
  height: number()
12497
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12580
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12498
12581
  /**
12499
12582
  * filesystem-browse — per-node capability for browsing the node's local
12500
12583
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12787,19 +12870,22 @@ method(LlmGenerateBaseInputSchema.extend({
12787
12870
  runtime: ManagedRuntimeConfigSchema,
12788
12871
  /** The managed profile's timeout, threaded by the hub provider. */
12789
12872
  timeoutMs: number().int().positive().optional()
12790
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12873
+ }), LlmGenerateResultSchema, {
12874
+ kind: "mutation",
12875
+ auth: "admin"
12876
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12791
12877
  kind: "mutation",
12792
12878
  auth: "admin"
12793
12879
  }), method(object({}), _void(), {
12794
12880
  kind: "mutation",
12795
12881
  auth: "admin"
12796
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12882
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12797
12883
  kind: "mutation",
12798
12884
  auth: "admin"
12799
12885
  }), method(object({ file: string() }), _void(), {
12800
12886
  kind: "mutation",
12801
12887
  auth: "admin"
12802
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12888
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12803
12889
  /**
12804
12890
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12805
12891
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14733,12 +14819,15 @@ var NcOccupancyConditionSchema = object({
14733
14819
  * there is no second switch that can disagree with the first and every rule
14734
14820
  * authored before the decision migrates for free (`audioModeOf`):
14735
14821
  *
14736
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14737
- * classifier labels with one of them. No window, no percentage:
14738
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14739
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14740
- * the analyzer's (`classificationMinScore`, per device) — a label only
14741
- * reaches this condition if the classifier was already confident enough.
14822
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14823
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14824
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14825
+ * frames is the wrong question for a classifier that labels 1–3 frames
14826
+ * per episode. The count window is the brake that drops a single-frame
14827
+ * false positive; the rule's own `throttle` cooldown is the other. The
14828
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14829
+ * per device) — a label only reaches this condition if the classifier was
14830
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14742
14831
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14743
14832
  * the condition: at least `hitPercent`% of the samples over
14744
14833
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14765,14 +14854,22 @@ var NcOccupancyConditionSchema = object({
14765
14854
  * an operator who typed `dog` mean the same thing.
14766
14855
  */
14767
14856
  var NcAudioConditionSchema = object({
14768
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14857
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14769
14858
  labels: array(string().min(1)).min(1).optional(),
14770
14859
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14771
14860
  dbThreshold: number().min(-96).max(0).optional(),
14772
14861
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14773
14862
  hitPercent: number().int().min(1).max(100).default(60),
14774
14863
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14775
- samplingSeconds: number().int().min(1).max(300).default(10)
14864
+ samplingSeconds: number().int().min(1).max(300).default(10),
14865
+ /**
14866
+ * LABEL MODE: how many labelled frames must land inside
14867
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14868
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14869
+ */
14870
+ confirmHits: number().int().min(1).max(20).optional(),
14871
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14872
+ confirmWindowSec: number().int().min(1).max(60).optional()
14776
14873
  });
14777
14874
  /**
14778
14875
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16299,7 +16396,7 @@ var OauthIntegrationDescriptorSchema = object({
16299
16396
  */
16300
16397
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16301
16398
  });
16302
- method(_void(), OauthIntegrationDescriptorSchema);
16399
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16303
16400
  /**
16304
16401
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16305
16402
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17146,6 +17243,46 @@ var RecentTracksPageSchema = object({
17146
17243
  /** Cursor for the next page, or null when this page is the last. */
17147
17244
  nextCursor: string().nullable()
17148
17245
  });
17246
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17247
+ var LIST_GROUPS_MAX_LIMIT = 100;
17248
+ var AnalyticsGroupRecordSchema = object({
17249
+ id: string(),
17250
+ deviceId: number().int(),
17251
+ openedAt: number().int(),
17252
+ closedAt: number().int(),
17253
+ timestamp: number().int(),
17254
+ memberCount: number().int(),
17255
+ memberTrackIds: array(string()).readonly(),
17256
+ className: string(),
17257
+ classes: array(string()).readonly(),
17258
+ /** Relative event-media path, or null when the group has no picture yet. */
17259
+ mediaUrl: string().nullable(),
17260
+ singleton: boolean()
17261
+ });
17262
+ var AnalyticsGroupMemberSchema = object({
17263
+ trackId: string(),
17264
+ deviceId: number().int(),
17265
+ className: string(),
17266
+ firstSeen: number().int(),
17267
+ lastSeen: number().int(),
17268
+ mediaUrl: string().nullable()
17269
+ });
17270
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17271
+ var ListGroupsQueryInput = object({
17272
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17273
+ deviceIds: array(number()),
17274
+ /** Window lower bound on `closedAt` (inclusive). */
17275
+ since: number().optional(),
17276
+ /** Window upper bound on `openedAt` (inclusive). */
17277
+ until: number().optional(),
17278
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17279
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17280
+ cursor: string().optional()
17281
+ });
17282
+ var ListGroupsPageSchema = object({
17283
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17284
+ nextCursor: string().nullable()
17285
+ });
17149
17286
  var KeyEventQueryInput = object({
17150
17287
  deviceId: number(),
17151
17288
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17221,7 +17358,9 @@ var TrackCascadeCountsSchema = object({
17221
17358
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17222
17359
  plates: number().int(),
17223
17360
  /** Per-track CLIP search vectors removed (best-effort). */
17224
- embeddings: number().int()
17361
+ embeddings: number().int(),
17362
+ /** Group membership + group rows removed with their last member (best-effort). */
17363
+ groups: number().int()
17225
17364
  });
17226
17365
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17227
17366
  var DiskReconcileCountsSchema = object({
@@ -17367,7 +17506,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17367
17506
  * stationary registry). Default false: the timeline lists passages,
17368
17507
  * not parking records (operator decision, 2026-08-15). */
17369
17508
  includeStationary: boolean().optional()
17370
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17509
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17510
+ deviceId: number(),
17511
+ groupId: string().min(1)
17512
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17371
17513
  kind: "mutation",
17372
17514
  auth: "admin"
17373
17515
  }), 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({
@@ -17449,6 +17591,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17449
17591
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17450
17592
  kind: "mutation",
17451
17593
  auth: "admin"
17594
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17595
+ kind: "mutation",
17596
+ auth: "admin"
17597
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17598
+ kind: "query",
17599
+ auth: "admin"
17600
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17601
+ kind: "mutation",
17602
+ auth: "admin"
17452
17603
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17453
17604
  kind: "query",
17454
17605
  auth: "admin"
@@ -17603,6 +17754,11 @@ object({
17603
17754
  "jpeg"
17604
17755
  ])
17605
17756
  });
17757
+ /**
17758
+ * Process-local frame identity. It is serializable so it can ride an in-process
17759
+ * capability call, but `registryId` deliberately prevents resolution in any
17760
+ * other process or execution group.
17761
+ */
17606
17762
  var FrameRefSchema = object({
17607
17763
  registryId: string().min(1),
17608
17764
  id: string().min(1),
@@ -17677,7 +17833,8 @@ var PipelineModelOptionSchema = object({
17677
17833
  sizeMB: number()
17678
17834
  })),
17679
17835
  group: ModelVariantGroupSchema.optional(),
17680
- legacy: boolean().optional()
17836
+ legacy: boolean().optional(),
17837
+ provider: ModelProviderIdSchema.optional()
17681
17838
  });
17682
17839
  var ConfigFieldBridge = custom();
17683
17840
  var PipelineAddonSchemaSchema = object({
@@ -19911,7 +20068,7 @@ method(object({
19911
20068
  * linking rather than produce an eternal token.
19912
20069
  */
19913
20070
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19914
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
20071
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19915
20072
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19916
20073
  providerId: string().min(1),
19917
20074
  displayName: string().min(1),
@@ -20006,10 +20163,13 @@ var EvictResultSchema = object({
20006
20163
  /** True when the provider has nothing left it is willing to drop on this location. */
20007
20164
  exhausted: boolean()
20008
20165
  });
20009
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20166
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
20010
20167
  locationId: string(),
20011
20168
  targetBytes: number().int().positive()
20012
- }), EvictResultSchema, { kind: "mutation" });
20169
+ }), EvictResultSchema, {
20170
+ kind: "mutation",
20171
+ auth: "admin"
20172
+ });
20013
20173
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
20014
20174
  kind: "mutation",
20015
20175
  auth: "admin"
@@ -20069,26 +20229,50 @@ var ReadChunkInputSchema = object({
20069
20229
  length: number()
20070
20230
  });
20071
20231
  var EndDownloadInputSchema = object({ downloadId: string() });
20072
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20232
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20073
20233
  location: StorageLocationSchema,
20074
20234
  relativePath: string()
20075
- }), string()), method(object({
20235
+ }), string(), { auth: "admin" }), method(object({
20076
20236
  location: StorageLocationSchema,
20077
20237
  relativePath: string(),
20078
20238
  data: _instanceof(Uint8Array)
20079
- }), _void(), { kind: "mutation" }), method(object({
20239
+ }), _void(), {
20240
+ kind: "mutation",
20241
+ auth: "admin"
20242
+ }), method(object({
20080
20243
  location: StorageLocationSchema,
20081
20244
  relativePath: string()
20082
- }), _instanceof(Uint8Array)), method(object({
20245
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
20083
20246
  location: StorageLocationSchema,
20084
20247
  relativePath: string()
20085
- }), boolean()), method(object({
20248
+ }), boolean(), { auth: "admin" }), method(object({
20086
20249
  location: StorageLocationSchema,
20087
20250
  prefix: string().optional()
20088
- }), array(string()).readonly()), method(object({
20251
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
20089
20252
  location: StorageLocationSchema,
20090
20253
  relativePath: string()
20091
- }), _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" });
20254
+ }), _void(), {
20255
+ kind: "mutation",
20256
+ auth: "admin"
20257
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20258
+ kind: "mutation",
20259
+ auth: "admin"
20260
+ }), method(WriteChunkInputSchema, _void(), {
20261
+ kind: "mutation",
20262
+ auth: "admin"
20263
+ }), method(FinalizeUploadInputSchema, _void(), {
20264
+ kind: "mutation",
20265
+ auth: "admin"
20266
+ }), method(AbortUploadInputSchema, _void(), {
20267
+ kind: "mutation",
20268
+ auth: "admin"
20269
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20270
+ kind: "mutation",
20271
+ auth: "admin"
20272
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20273
+ kind: "mutation",
20274
+ auth: "admin"
20275
+ });
20092
20276
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20093
20277
  var ProfileSettingsSchemaBridge = unknown().nullable();
20094
20278
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20346,7 +20530,8 @@ method(object({
20346
20530
  access: "create"
20347
20531
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20348
20532
  kind: "mutation",
20349
- access: "view"
20533
+ access: "view",
20534
+ auth: "admin"
20350
20535
  }), method(object({
20351
20536
  /** Required — the user the assertion belongs to (verified). */
20352
20537
  userId: string(),
@@ -20354,10 +20539,12 @@ method(object({
20354
20539
  response: record(string(), unknown())
20355
20540
  }), object({ verified: boolean() }), {
20356
20541
  kind: "mutation",
20357
- access: "view"
20542
+ access: "view",
20543
+ auth: "admin"
20358
20544
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20359
20545
  kind: "mutation",
20360
- access: "view"
20546
+ access: "view",
20547
+ auth: "admin"
20361
20548
  }), method(object({
20362
20549
  /** AuthenticationResponseJSON from the browser. */
20363
20550
  response: record(string(), unknown()) }), object({
@@ -20365,7 +20552,8 @@ response: record(string(), unknown()) }), object({
20365
20552
  userId: string().nullable()
20366
20553
  }), {
20367
20554
  kind: "mutation",
20368
- access: "view"
20555
+ access: "view",
20556
+ auth: "admin"
20369
20557
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20370
20558
  userId: string(),
20371
20559
  credentialId: string()
@@ -20537,7 +20725,19 @@ var VectorStatsResultSchema = object({
20537
20725
  /** False when the backend ranks approximately. */
20538
20726
  exact: boolean()
20539
20727
  });
20540
- 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);
20728
+ method(VectorDeclareIndexInputSchema, _void(), {
20729
+ kind: "mutation",
20730
+ auth: "admin"
20731
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20732
+ kind: "mutation",
20733
+ auth: "admin"
20734
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20735
+ kind: "mutation",
20736
+ auth: "admin"
20737
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20738
+ kind: "mutation",
20739
+ auth: "admin"
20740
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20541
20741
  var ClipSchema = object({
20542
20742
  /** Opaque, provider-namespaced id. The default provider encodes the time
20543
20743
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -22998,7 +23198,27 @@ var MediaFileLiteSchema$1 = object({
22998
23198
  sizeBytes: number(),
22999
23199
  timestamp: number()
23000
23200
  });
23001
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23201
+ method(object({
23202
+ /**
23203
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23204
+ *
23205
+ * Default `false`, the same inversion `listRecentFaces` and
23206
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23207
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23208
+ * on the live hub the same day: four identities cost 40,979 B with the
23209
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23210
+ * four times and the viewer holds at `staleTime: 30_000`.
23211
+ *
23212
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23213
+ * the `event-media` plane serves that key `immutable` with an ETag.
23214
+ *
23215
+ * **This is an INPUT field, so it does not reach the addon until the
23216
+ * next train** — the hub router validates cap inputs against its own
23217
+ * compiled Zod and strips a key it does not know. Until then the
23218
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23219
+ * is what ships, and the opt-in becomes reachable when the train lands.
23220
+ */
23221
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23002
23222
  kind: "mutation",
23003
23223
  auth: "admin"
23004
23224
  }), method(object({
@@ -25886,7 +26106,14 @@ var PlateInfoSchema = object({
25886
26106
  plateBbox: BoundingBoxSchema.optional(),
25887
26107
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25888
26108
  keyFrameMediaKey: string().optional(),
25889
- base64: string().optional()
26109
+ base64: string().optional(),
26110
+ /**
26111
+ * Same crop as a data-plane URL, always present when the plate has a stored
26112
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26113
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26114
+ * left at its `true` default.
26115
+ */
26116
+ cropUrl: string().optional()
25890
26117
  });
25891
26118
  var MediaFileLiteSchema = object({
25892
26119
  key: string(),
@@ -25904,14 +26131,34 @@ var PlateClusterSchema = object({
25904
26131
  });
25905
26132
  method(object({
25906
26133
  deviceId: number().int().optional(),
25907
- limit: number().int().positive().optional()
26134
+ limit: number().int().positive().optional(),
26135
+ /**
26136
+ * Inline the base64 crop on every row. Default `true` — the existing
26137
+ * behaviour, kept so no caller breaks.
26138
+ *
26139
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26140
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26141
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26142
+ * metadata without them — and the browser then caches the images.
26143
+ *
26144
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26145
+ * plates were the one gallery list left without it.
26146
+ *
26147
+ * **This is an INPUT field, so it does not reach the addon until the
26148
+ * next train.** The hub router validates cap inputs against its own
26149
+ * compiled Zod and strips a key it does not know. Until the train
26150
+ * ships, sending `false` is harmless and keeps the crops inline.
26151
+ */
26152
+ includeCrops: boolean().optional()
25908
26153
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
25909
26154
  deviceId: number().int(),
25910
26155
  trackId: string()
25911
26156
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
25912
26157
  text: string().min(1),
25913
26158
  maxDistance: number().int().min(0).optional(),
25914
- limit: number().int().positive().optional()
26159
+ limit: number().int().positive().optional(),
26160
+ /** See `listPlates.includeCrops`. Default `true`. */
26161
+ includeCrops: boolean().optional()
25915
26162
  }), array(PlateInfoSchema).readonly()), method(object({
25916
26163
  maxDistance: number().int().min(0).optional(),
25917
26164
  minClusterSize: number().int().min(2).optional(),
@@ -25925,7 +26172,13 @@ method(object({
25925
26172
  }), method(object({ plateId: string() }), _void(), {
25926
26173
  kind: "mutation",
25927
26174
  auth: "admin"
25928
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26175
+ }), method(object({
26176
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26177
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26178
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26179
+ * INPUT field: stripped by the hub router until the train ships, which
26180
+ * resolves to `false` and is exactly the intended default. */
26181
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
25929
26182
  kind: "mutation",
25930
26183
  auth: "admin"
25931
26184
  }), method(object({
@@ -31410,6 +31663,12 @@ Object.freeze({
31410
31663
  addonId: null,
31411
31664
  access: "view"
31412
31665
  },
31666
+ "deviceManager.getBindingsBatch": {
31667
+ capName: "device-manager",
31668
+ capScope: "system",
31669
+ addonId: null,
31670
+ access: "view"
31671
+ },
31413
31672
  "deviceManager.getChildren": {
31414
31673
  capName: "device-manager",
31415
31674
  capScope: "system",
@@ -31470,6 +31729,12 @@ Object.freeze({
31470
31729
  addonId: null,
31471
31730
  access: "view"
31472
31731
  },
31732
+ "deviceManager.getLinkedDevicesBatch": {
31733
+ capName: "device-manager",
31734
+ capScope: "system",
31735
+ addonId: null,
31736
+ access: "view"
31737
+ },
31473
31738
  "deviceManager.getRoleDisplayDefaults": {
31474
31739
  capName: "device-manager",
31475
31740
  capScope: "system",
@@ -33174,6 +33439,12 @@ Object.freeze({
33174
33439
  addonId: null,
33175
33440
  access: "create"
33176
33441
  },
33442
+ "pipelineAnalytics.cancelRelocateMedia": {
33443
+ capName: "pipeline-analytics",
33444
+ capScope: "device",
33445
+ addonId: null,
33446
+ access: "create"
33447
+ },
33177
33448
  "pipelineAnalytics.cancelStorageMigrationMove": {
33178
33449
  capName: "pipeline-analytics",
33179
33450
  capScope: "device",
@@ -33240,6 +33511,12 @@ Object.freeze({
33240
33511
  addonId: null,
33241
33512
  access: "view"
33242
33513
  },
33514
+ "pipelineAnalytics.getGroup": {
33515
+ capName: "pipeline-analytics",
33516
+ capScope: "device",
33517
+ addonId: null,
33518
+ access: "view"
33519
+ },
33243
33520
  "pipelineAnalytics.getKeyEvents": {
33244
33521
  capName: "pipeline-analytics",
33245
33522
  capScope: "device",
@@ -33324,6 +33601,12 @@ Object.freeze({
33324
33601
  addonId: null,
33325
33602
  access: "view"
33326
33603
  },
33604
+ "pipelineAnalytics.listGroups": {
33605
+ capName: "pipeline-analytics",
33606
+ capScope: "device",
33607
+ addonId: null,
33608
+ access: "view"
33609
+ },
33327
33610
  "pipelineAnalytics.listOpsLog": {
33328
33611
  capName: "pipeline-analytics",
33329
33612
  capScope: "device",
@@ -33336,6 +33619,12 @@ Object.freeze({
33336
33619
  addonId: null,
33337
33620
  access: "view"
33338
33621
  },
33622
+ "pipelineAnalytics.listRelocateMediaJobs": {
33623
+ capName: "pipeline-analytics",
33624
+ capScope: "device",
33625
+ addonId: null,
33626
+ access: "view"
33627
+ },
33339
33628
  "pipelineAnalytics.listRetrainAnnotations": {
33340
33629
  capName: "pipeline-analytics",
33341
33630
  capScope: "device",
@@ -33414,6 +33703,12 @@ Object.freeze({
33414
33703
  addonId: null,
33415
33704
  access: "create"
33416
33705
  },
33706
+ "pipelineAnalytics.relocateMedia": {
33707
+ capName: "pipeline-analytics",
33708
+ capScope: "device",
33709
+ addonId: null,
33710
+ access: "create"
33711
+ },
33417
33712
  "pipelineAnalytics.restageRetrainTrack": {
33418
33713
  capName: "pipeline-analytics",
33419
33714
  capScope: "device",
@@ -36105,6 +36400,11 @@ Object.freeze({
36105
36400
  form: "single",
36106
36401
  optional: false
36107
36402
  }],
36403
+ "deviceManager.getBindingsBatch": [{
36404
+ name: "deviceIds",
36405
+ form: "array",
36406
+ optional: false
36407
+ }],
36108
36408
  "deviceManager.getChildren": [{
36109
36409
  name: "parentDeviceId",
36110
36410
  form: "single",
@@ -36150,6 +36450,11 @@ Object.freeze({
36150
36450
  form: "single",
36151
36451
  optional: false
36152
36452
  }],
36453
+ "deviceManager.getLinkedDevicesBatch": [{
36454
+ name: "deviceIds",
36455
+ form: "array",
36456
+ optional: false
36457
+ }],
36153
36458
  "deviceManager.getSettingsSchema": [{
36154
36459
  name: "deviceId",
36155
36460
  form: "single",
@@ -36170,6 +36475,11 @@ Object.freeze({
36170
36475
  form: "single",
36171
36476
  optional: false
36172
36477
  }],
36478
+ "deviceManager.listAll": [{
36479
+ name: "deviceIds",
36480
+ form: "array",
36481
+ optional: true
36482
+ }],
36173
36483
  "deviceManager.loadConfig": [{
36174
36484
  name: "deviceId",
36175
36485
  form: "single",
@@ -36743,6 +37053,11 @@ Object.freeze({
36743
37053
  form: "single",
36744
37054
  optional: false
36745
37055
  }],
37056
+ "pipelineAnalytics.getGroup": [{
37057
+ name: "deviceId",
37058
+ form: "single",
37059
+ optional: false
37060
+ }],
36746
37061
  "pipelineAnalytics.getKeyEvents": [{
36747
37062
  name: "deviceId",
36748
37063
  form: "single",
@@ -36798,6 +37113,11 @@ Object.freeze({
36798
37113
  form: "array",
36799
37114
  optional: false
36800
37115
  }],
37116
+ "pipelineAnalytics.listGroups": [{
37117
+ name: "deviceIds",
37118
+ form: "array",
37119
+ optional: false
37120
+ }],
36801
37121
  "pipelineAnalytics.listOpsLog": [{
36802
37122
  name: "deviceId",
36803
37123
  form: "single",