@camstack/addon-provider-rtsp 1.2.27 → 1.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
@@ -5801,6 +5801,13 @@ var BaseAddon = class {
5801
5801
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5802
5802
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5803
5803
  _registeredCapNames = [];
5804
+ /**
5805
+ * True only after `readAddonStore` actually answered. Constructor
5806
+ * defaults look like stored config when the store is down — a forked
5807
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5808
+ * mode, 2026-08-25) is not "the operator chose this".
5809
+ */
5810
+ settingsStoreReady = false;
5804
5811
  /** Default config values. Provided via constructor. */
5805
5812
  defaults;
5806
5813
  constructor(defaults) {
@@ -6201,7 +6208,9 @@ var BaseAddon = class {
6201
6208
  ];
6202
6209
  let lastErr;
6203
6210
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6204
- return await settings.readAddonStore() ?? {};
6211
+ const stored = await settings.readAddonStore() ?? {};
6212
+ this.settingsStoreReady = true;
6213
+ return stored;
6205
6214
  } catch (err) {
6206
6215
  lastErr = err;
6207
6216
  const msg = err instanceof Error ? err.message : String(err);
@@ -6209,6 +6218,7 @@ var BaseAddon = class {
6209
6218
  if (attempt === delaysMs.length) break;
6210
6219
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6211
6220
  }
6221
+ this.settingsStoreReady = false;
6212
6222
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6213
6223
  return {};
6214
6224
  }
@@ -6620,7 +6630,7 @@ function method(input, output, options) {
6620
6630
  input,
6621
6631
  output,
6622
6632
  kind: options?.kind ?? "query",
6623
- auth: options?.auth ?? "protected",
6633
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6624
6634
  ...options?.access !== void 0 ? { access: options.access } : {},
6625
6635
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6626
6636
  timeoutMs: options?.timeoutMs
@@ -6644,7 +6654,7 @@ function event(data) {
6644
6654
  }
6645
6655
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6646
6656
  var VersionOutputSchema$1 = object({ version: string() });
6647
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6657
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6648
6658
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6649
6659
  DeviceType["Camera"] = "camera";
6650
6660
  DeviceType["Hub"] = "hub";
@@ -6965,7 +6975,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6965
6975
  }({});
6966
6976
  var StaticDirOutputSchema = object({ staticDir: string() });
6967
6977
  var VersionOutputSchema = object({ version: string() });
6968
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
6978
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
6969
6979
  /**
6970
6980
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6971
6981
  * 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
@@ -12032,6 +12098,27 @@ var LinkedDeviceSchema = object({
12032
12098
  features: array(string()),
12033
12099
  producesTrackedEvents: boolean().optional()
12034
12100
  });
12101
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12102
+ * The batch answer needs the tag; the single-device answer already has it
12103
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12104
+ var LinkedDevicesForDeviceSchema = object({
12105
+ deviceId: number(),
12106
+ mode: LinkedDevicesModeSchema,
12107
+ devices: array(LinkedDeviceSchema)
12108
+ });
12109
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12110
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12111
+ * object literal is exactly how the three drift apart. */
12112
+ var DeviceBindingsForDeviceSchema = object({
12113
+ deviceId: number(),
12114
+ entries: array(object({
12115
+ capName: string(),
12116
+ kind: _enum(["native", "wrapped"]),
12117
+ providerAddonId: string(),
12118
+ providerNodeId: string(),
12119
+ nativeAddonId: string()
12120
+ }))
12121
+ });
12035
12122
  var SavedDeviceRowSchema = object({
12036
12123
  /** Numeric id reserved at allocateDeviceId time. */
12037
12124
  id: number(),
@@ -12257,11 +12344,25 @@ method(object({
12257
12344
  projection: _enum(["full", "slim"]).optional(),
12258
12345
  /** Return only camera devices. Filtering server-side instead of
12259
12346
  * shipping 293 rows to find 12. */
12260
- isCamera: boolean().optional()
12347
+ isCamera: boolean().optional(),
12348
+ /**
12349
+ * Return only these device ids. For the caller that already KNOWS the
12350
+ * handful it wants and needs a field the id-bearing answer does not
12351
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12352
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12353
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12354
+ * refetches on the reconcile interval, on a phone.
12355
+ *
12356
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12357
+ * keys rather than rejecting them (verified against the live hub
12358
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12359
+ * it answers today and the caller filters as it already does.
12360
+ */
12361
+ deviceIds: array(number()).optional()
12261
12362
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12262
12363
  mode: LinkedDevicesModeSchema,
12263
12364
  devices: array(LinkedDeviceSchema)
12264
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12365
+ })), 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({
12265
12366
  deviceId: number(),
12266
12367
  values: record(string(), unknown())
12267
12368
  }), object({ success: literal(true) }), {
@@ -12288,25 +12389,7 @@ method(object({
12288
12389
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12289
12390
  kind: "mutation",
12290
12391
  auth: "admin"
12291
- }), method(object({ deviceId: number() }), object({
12292
- deviceId: number(),
12293
- entries: array(object({
12294
- capName: string(),
12295
- kind: _enum(["native", "wrapped"]),
12296
- providerAddonId: string(),
12297
- providerNodeId: string(),
12298
- nativeAddonId: string()
12299
- }))
12300
- })), method(object({}), array(object({
12301
- deviceId: number(),
12302
- entries: array(object({
12303
- capName: string(),
12304
- kind: _enum(["native", "wrapped"]),
12305
- providerAddonId: string(),
12306
- providerNodeId: string(),
12307
- nativeAddonId: string()
12308
- }))
12309
- }))), method(object({
12392
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12310
12393
  deviceId: number(),
12311
12394
  capName: string(),
12312
12395
  wrapperAddonId: string(),
@@ -12477,7 +12560,7 @@ method(object({
12477
12560
  crop: _instanceof(Uint8Array),
12478
12561
  width: number(),
12479
12562
  height: number()
12480
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12563
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12481
12564
  /**
12482
12565
  * filesystem-browse — per-node capability for browsing the node's local
12483
12566
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12770,19 +12853,22 @@ method(LlmGenerateBaseInputSchema.extend({
12770
12853
  runtime: ManagedRuntimeConfigSchema,
12771
12854
  /** The managed profile's timeout, threaded by the hub provider. */
12772
12855
  timeoutMs: number().int().positive().optional()
12773
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12856
+ }), LlmGenerateResultSchema, {
12857
+ kind: "mutation",
12858
+ auth: "admin"
12859
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12774
12860
  kind: "mutation",
12775
12861
  auth: "admin"
12776
12862
  }), method(object({}), _void(), {
12777
12863
  kind: "mutation",
12778
12864
  auth: "admin"
12779
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12865
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12780
12866
  kind: "mutation",
12781
12867
  auth: "admin"
12782
12868
  }), method(object({ file: string() }), _void(), {
12783
12869
  kind: "mutation",
12784
12870
  auth: "admin"
12785
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12871
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12786
12872
  /**
12787
12873
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12788
12874
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14716,12 +14802,15 @@ var NcOccupancyConditionSchema = object({
14716
14802
  * there is no second switch that can disagree with the first and every rule
14717
14803
  * authored before the decision migrates for free (`audioModeOf`):
14718
14804
  *
14719
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14720
- * classifier labels with one of them. No window, no percentage:
14721
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14722
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14723
- * the analyzer's (`classificationMinScore`, per device) a label only
14724
- * reaches this condition if the classifier was already confident enough.
14805
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14806
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14807
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14808
+ * frames is the wrong question for a classifier that labels 1–3 frames
14809
+ * per episode. The count window is the brake that drops a single-frame
14810
+ * false positive; the rule's own `throttle` cooldown is the other. The
14811
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14812
+ * per device) — a label only reaches this condition if the classifier was
14813
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14725
14814
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14726
14815
  * the condition: at least `hitPercent`% of the samples over
14727
14816
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14748,14 +14837,22 @@ var NcOccupancyConditionSchema = object({
14748
14837
  * an operator who typed `dog` mean the same thing.
14749
14838
  */
14750
14839
  var NcAudioConditionSchema = object({
14751
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14840
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14752
14841
  labels: array(string().min(1)).min(1).optional(),
14753
14842
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14754
14843
  dbThreshold: number().min(-96).max(0).optional(),
14755
14844
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14756
14845
  hitPercent: number().int().min(1).max(100).default(60),
14757
14846
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14758
- samplingSeconds: number().int().min(1).max(300).default(10)
14847
+ samplingSeconds: number().int().min(1).max(300).default(10),
14848
+ /**
14849
+ * LABEL MODE: how many labelled frames must land inside
14850
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14851
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14852
+ */
14853
+ confirmHits: number().int().min(1).max(20).optional(),
14854
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14855
+ confirmWindowSec: number().int().min(1).max(60).optional()
14759
14856
  });
14760
14857
  /**
14761
14858
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16282,7 +16379,7 @@ var OauthIntegrationDescriptorSchema = object({
16282
16379
  */
16283
16380
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16284
16381
  });
16285
- method(_void(), OauthIntegrationDescriptorSchema);
16382
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16286
16383
  /**
16287
16384
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16288
16385
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17129,6 +17226,46 @@ var RecentTracksPageSchema = object({
17129
17226
  /** Cursor for the next page, or null when this page is the last. */
17130
17227
  nextCursor: string().nullable()
17131
17228
  });
17229
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17230
+ var LIST_GROUPS_MAX_LIMIT = 100;
17231
+ var AnalyticsGroupRecordSchema = object({
17232
+ id: string(),
17233
+ deviceId: number().int(),
17234
+ openedAt: number().int(),
17235
+ closedAt: number().int(),
17236
+ timestamp: number().int(),
17237
+ memberCount: number().int(),
17238
+ memberTrackIds: array(string()).readonly(),
17239
+ className: string(),
17240
+ classes: array(string()).readonly(),
17241
+ /** Relative event-media path, or null when the group has no picture yet. */
17242
+ mediaUrl: string().nullable(),
17243
+ singleton: boolean()
17244
+ });
17245
+ var AnalyticsGroupMemberSchema = object({
17246
+ trackId: string(),
17247
+ deviceId: number().int(),
17248
+ className: string(),
17249
+ firstSeen: number().int(),
17250
+ lastSeen: number().int(),
17251
+ mediaUrl: string().nullable()
17252
+ });
17253
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17254
+ var ListGroupsQueryInput = object({
17255
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17256
+ deviceIds: array(number()),
17257
+ /** Window lower bound on `closedAt` (inclusive). */
17258
+ since: number().optional(),
17259
+ /** Window upper bound on `openedAt` (inclusive). */
17260
+ until: number().optional(),
17261
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17262
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17263
+ cursor: string().optional()
17264
+ });
17265
+ var ListGroupsPageSchema = object({
17266
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17267
+ nextCursor: string().nullable()
17268
+ });
17132
17269
  var KeyEventQueryInput = object({
17133
17270
  deviceId: number(),
17134
17271
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17204,7 +17341,9 @@ var TrackCascadeCountsSchema = object({
17204
17341
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17205
17342
  plates: number().int(),
17206
17343
  /** Per-track CLIP search vectors removed (best-effort). */
17207
- embeddings: number().int()
17344
+ embeddings: number().int(),
17345
+ /** Group membership + group rows removed with their last member (best-effort). */
17346
+ groups: number().int()
17208
17347
  });
17209
17348
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17210
17349
  var DiskReconcileCountsSchema = object({
@@ -17350,7 +17489,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17350
17489
  * stationary registry). Default false: the timeline lists passages,
17351
17490
  * not parking records (operator decision, 2026-08-15). */
17352
17491
  includeStationary: boolean().optional()
17353
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17492
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17493
+ deviceId: number(),
17494
+ groupId: string().min(1)
17495
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17354
17496
  kind: "mutation",
17355
17497
  auth: "admin"
17356
17498
  }), 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({
@@ -17432,6 +17574,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17432
17574
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17433
17575
  kind: "mutation",
17434
17576
  auth: "admin"
17577
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17578
+ kind: "mutation",
17579
+ auth: "admin"
17580
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17581
+ kind: "query",
17582
+ auth: "admin"
17583
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17584
+ kind: "mutation",
17585
+ auth: "admin"
17435
17586
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17436
17587
  kind: "query",
17437
17588
  auth: "admin"
@@ -17586,6 +17737,11 @@ object({
17586
17737
  "jpeg"
17587
17738
  ])
17588
17739
  });
17740
+ /**
17741
+ * Process-local frame identity. It is serializable so it can ride an in-process
17742
+ * capability call, but `registryId` deliberately prevents resolution in any
17743
+ * other process or execution group.
17744
+ */
17589
17745
  var FrameRefSchema = object({
17590
17746
  registryId: string().min(1),
17591
17747
  id: string().min(1),
@@ -17660,7 +17816,8 @@ var PipelineModelOptionSchema = object({
17660
17816
  sizeMB: number()
17661
17817
  })),
17662
17818
  group: ModelVariantGroupSchema.optional(),
17663
- legacy: boolean().optional()
17819
+ legacy: boolean().optional(),
17820
+ provider: ModelProviderIdSchema.optional()
17664
17821
  });
17665
17822
  var ConfigFieldBridge = custom();
17666
17823
  var PipelineAddonSchemaSchema = object({
@@ -19894,7 +20051,7 @@ method(object({
19894
20051
  * linking rather than produce an eternal token.
19895
20052
  */
19896
20053
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19897
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
20054
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19898
20055
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19899
20056
  providerId: string().min(1),
19900
20057
  displayName: string().min(1),
@@ -19989,10 +20146,13 @@ var EvictResultSchema = object({
19989
20146
  /** True when the provider has nothing left it is willing to drop on this location. */
19990
20147
  exhausted: boolean()
19991
20148
  });
19992
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20149
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19993
20150
  locationId: string(),
19994
20151
  targetBytes: number().int().positive()
19995
- }), EvictResultSchema, { kind: "mutation" });
20152
+ }), EvictResultSchema, {
20153
+ kind: "mutation",
20154
+ auth: "admin"
20155
+ });
19996
20156
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19997
20157
  kind: "mutation",
19998
20158
  auth: "admin"
@@ -20052,26 +20212,50 @@ var ReadChunkInputSchema = object({
20052
20212
  length: number()
20053
20213
  });
20054
20214
  var EndDownloadInputSchema = object({ downloadId: string() });
20055
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20215
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20056
20216
  location: StorageLocationSchema,
20057
20217
  relativePath: string()
20058
- }), string()), method(object({
20218
+ }), string(), { auth: "admin" }), method(object({
20059
20219
  location: StorageLocationSchema,
20060
20220
  relativePath: string(),
20061
20221
  data: _instanceof(Uint8Array)
20062
- }), _void(), { kind: "mutation" }), method(object({
20222
+ }), _void(), {
20223
+ kind: "mutation",
20224
+ auth: "admin"
20225
+ }), method(object({
20063
20226
  location: StorageLocationSchema,
20064
20227
  relativePath: string()
20065
- }), _instanceof(Uint8Array)), method(object({
20228
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
20066
20229
  location: StorageLocationSchema,
20067
20230
  relativePath: string()
20068
- }), boolean()), method(object({
20231
+ }), boolean(), { auth: "admin" }), method(object({
20069
20232
  location: StorageLocationSchema,
20070
20233
  prefix: string().optional()
20071
- }), array(string()).readonly()), method(object({
20234
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
20072
20235
  location: StorageLocationSchema,
20073
20236
  relativePath: string()
20074
- }), _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" });
20237
+ }), _void(), {
20238
+ kind: "mutation",
20239
+ auth: "admin"
20240
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20241
+ kind: "mutation",
20242
+ auth: "admin"
20243
+ }), method(WriteChunkInputSchema, _void(), {
20244
+ kind: "mutation",
20245
+ auth: "admin"
20246
+ }), method(FinalizeUploadInputSchema, _void(), {
20247
+ kind: "mutation",
20248
+ auth: "admin"
20249
+ }), method(AbortUploadInputSchema, _void(), {
20250
+ kind: "mutation",
20251
+ auth: "admin"
20252
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20253
+ kind: "mutation",
20254
+ auth: "admin"
20255
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20256
+ kind: "mutation",
20257
+ auth: "admin"
20258
+ });
20075
20259
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20076
20260
  var ProfileSettingsSchemaBridge = unknown().nullable();
20077
20261
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20329,7 +20513,8 @@ method(object({
20329
20513
  access: "create"
20330
20514
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20331
20515
  kind: "mutation",
20332
- access: "view"
20516
+ access: "view",
20517
+ auth: "admin"
20333
20518
  }), method(object({
20334
20519
  /** Required — the user the assertion belongs to (verified). */
20335
20520
  userId: string(),
@@ -20337,10 +20522,12 @@ method(object({
20337
20522
  response: record(string(), unknown())
20338
20523
  }), object({ verified: boolean() }), {
20339
20524
  kind: "mutation",
20340
- access: "view"
20525
+ access: "view",
20526
+ auth: "admin"
20341
20527
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20342
20528
  kind: "mutation",
20343
- access: "view"
20529
+ access: "view",
20530
+ auth: "admin"
20344
20531
  }), method(object({
20345
20532
  /** AuthenticationResponseJSON from the browser. */
20346
20533
  response: record(string(), unknown()) }), object({
@@ -20348,7 +20535,8 @@ response: record(string(), unknown()) }), object({
20348
20535
  userId: string().nullable()
20349
20536
  }), {
20350
20537
  kind: "mutation",
20351
- access: "view"
20538
+ access: "view",
20539
+ auth: "admin"
20352
20540
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20353
20541
  userId: string(),
20354
20542
  credentialId: string()
@@ -20520,7 +20708,19 @@ var VectorStatsResultSchema = object({
20520
20708
  /** False when the backend ranks approximately. */
20521
20709
  exact: boolean()
20522
20710
  });
20523
- 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);
20711
+ method(VectorDeclareIndexInputSchema, _void(), {
20712
+ kind: "mutation",
20713
+ auth: "admin"
20714
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20715
+ kind: "mutation",
20716
+ auth: "admin"
20717
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20718
+ kind: "mutation",
20719
+ auth: "admin"
20720
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20721
+ kind: "mutation",
20722
+ auth: "admin"
20723
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20524
20724
  var ClipSchema = object({
20525
20725
  /** Opaque, provider-namespaced id. The default provider encodes the time
20526
20726
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -22981,7 +23181,27 @@ var MediaFileLiteSchema$1 = object({
22981
23181
  sizeBytes: number(),
22982
23182
  timestamp: number()
22983
23183
  });
22984
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23184
+ method(object({
23185
+ /**
23186
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23187
+ *
23188
+ * Default `false`, the same inversion `listRecentFaces` and
23189
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23190
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23191
+ * on the live hub the same day: four identities cost 40,979 B with the
23192
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23193
+ * four times and the viewer holds at `staleTime: 30_000`.
23194
+ *
23195
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23196
+ * the `event-media` plane serves that key `immutable` with an ETag.
23197
+ *
23198
+ * **This is an INPUT field, so it does not reach the addon until the
23199
+ * next train** — the hub router validates cap inputs against its own
23200
+ * compiled Zod and strips a key it does not know. Until then the
23201
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23202
+ * is what ships, and the opt-in becomes reachable when the train lands.
23203
+ */
23204
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22985
23205
  kind: "mutation",
22986
23206
  auth: "admin"
22987
23207
  }), method(object({
@@ -25869,7 +26089,14 @@ var PlateInfoSchema = object({
25869
26089
  plateBbox: BoundingBoxSchema.optional(),
25870
26090
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25871
26091
  keyFrameMediaKey: string().optional(),
25872
- base64: string().optional()
26092
+ base64: string().optional(),
26093
+ /**
26094
+ * Same crop as a data-plane URL, always present when the plate has a stored
26095
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26096
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26097
+ * left at its `true` default.
26098
+ */
26099
+ cropUrl: string().optional()
25873
26100
  });
25874
26101
  var MediaFileLiteSchema = object({
25875
26102
  key: string(),
@@ -25887,14 +26114,34 @@ var PlateClusterSchema = object({
25887
26114
  });
25888
26115
  method(object({
25889
26116
  deviceId: number().int().optional(),
25890
- limit: number().int().positive().optional()
26117
+ limit: number().int().positive().optional(),
26118
+ /**
26119
+ * Inline the base64 crop on every row. Default `true` — the existing
26120
+ * behaviour, kept so no caller breaks.
26121
+ *
26122
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26123
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26124
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26125
+ * metadata without them — and the browser then caches the images.
26126
+ *
26127
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26128
+ * plates were the one gallery list left without it.
26129
+ *
26130
+ * **This is an INPUT field, so it does not reach the addon until the
26131
+ * next train.** The hub router validates cap inputs against its own
26132
+ * compiled Zod and strips a key it does not know. Until the train
26133
+ * ships, sending `false` is harmless and keeps the crops inline.
26134
+ */
26135
+ includeCrops: boolean().optional()
25891
26136
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
25892
26137
  deviceId: number().int(),
25893
26138
  trackId: string()
25894
26139
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
25895
26140
  text: string().min(1),
25896
26141
  maxDistance: number().int().min(0).optional(),
25897
- limit: number().int().positive().optional()
26142
+ limit: number().int().positive().optional(),
26143
+ /** See `listPlates.includeCrops`. Default `true`. */
26144
+ includeCrops: boolean().optional()
25898
26145
  }), array(PlateInfoSchema).readonly()), method(object({
25899
26146
  maxDistance: number().int().min(0).optional(),
25900
26147
  minClusterSize: number().int().min(2).optional(),
@@ -25908,7 +26155,13 @@ method(object({
25908
26155
  }), method(object({ plateId: string() }), _void(), {
25909
26156
  kind: "mutation",
25910
26157
  auth: "admin"
25911
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26158
+ }), method(object({
26159
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26160
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26161
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26162
+ * INPUT field: stripped by the hub router until the train ships, which
26163
+ * resolves to `false` and is exactly the intended default. */
26164
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
25912
26165
  kind: "mutation",
25913
26166
  auth: "admin"
25914
26167
  }), method(object({
@@ -31459,6 +31712,12 @@ Object.freeze({
31459
31712
  addonId: null,
31460
31713
  access: "view"
31461
31714
  },
31715
+ "deviceManager.getBindingsBatch": {
31716
+ capName: "device-manager",
31717
+ capScope: "system",
31718
+ addonId: null,
31719
+ access: "view"
31720
+ },
31462
31721
  "deviceManager.getChildren": {
31463
31722
  capName: "device-manager",
31464
31723
  capScope: "system",
@@ -31519,6 +31778,12 @@ Object.freeze({
31519
31778
  addonId: null,
31520
31779
  access: "view"
31521
31780
  },
31781
+ "deviceManager.getLinkedDevicesBatch": {
31782
+ capName: "device-manager",
31783
+ capScope: "system",
31784
+ addonId: null,
31785
+ access: "view"
31786
+ },
31522
31787
  "deviceManager.getRoleDisplayDefaults": {
31523
31788
  capName: "device-manager",
31524
31789
  capScope: "system",
@@ -33223,6 +33488,12 @@ Object.freeze({
33223
33488
  addonId: null,
33224
33489
  access: "create"
33225
33490
  },
33491
+ "pipelineAnalytics.cancelRelocateMedia": {
33492
+ capName: "pipeline-analytics",
33493
+ capScope: "device",
33494
+ addonId: null,
33495
+ access: "create"
33496
+ },
33226
33497
  "pipelineAnalytics.cancelStorageMigrationMove": {
33227
33498
  capName: "pipeline-analytics",
33228
33499
  capScope: "device",
@@ -33289,6 +33560,12 @@ Object.freeze({
33289
33560
  addonId: null,
33290
33561
  access: "view"
33291
33562
  },
33563
+ "pipelineAnalytics.getGroup": {
33564
+ capName: "pipeline-analytics",
33565
+ capScope: "device",
33566
+ addonId: null,
33567
+ access: "view"
33568
+ },
33292
33569
  "pipelineAnalytics.getKeyEvents": {
33293
33570
  capName: "pipeline-analytics",
33294
33571
  capScope: "device",
@@ -33373,6 +33650,12 @@ Object.freeze({
33373
33650
  addonId: null,
33374
33651
  access: "view"
33375
33652
  },
33653
+ "pipelineAnalytics.listGroups": {
33654
+ capName: "pipeline-analytics",
33655
+ capScope: "device",
33656
+ addonId: null,
33657
+ access: "view"
33658
+ },
33376
33659
  "pipelineAnalytics.listOpsLog": {
33377
33660
  capName: "pipeline-analytics",
33378
33661
  capScope: "device",
@@ -33385,6 +33668,12 @@ Object.freeze({
33385
33668
  addonId: null,
33386
33669
  access: "view"
33387
33670
  },
33671
+ "pipelineAnalytics.listRelocateMediaJobs": {
33672
+ capName: "pipeline-analytics",
33673
+ capScope: "device",
33674
+ addonId: null,
33675
+ access: "view"
33676
+ },
33388
33677
  "pipelineAnalytics.listRetrainAnnotations": {
33389
33678
  capName: "pipeline-analytics",
33390
33679
  capScope: "device",
@@ -33463,6 +33752,12 @@ Object.freeze({
33463
33752
  addonId: null,
33464
33753
  access: "create"
33465
33754
  },
33755
+ "pipelineAnalytics.relocateMedia": {
33756
+ capName: "pipeline-analytics",
33757
+ capScope: "device",
33758
+ addonId: null,
33759
+ access: "create"
33760
+ },
33466
33761
  "pipelineAnalytics.restageRetrainTrack": {
33467
33762
  capName: "pipeline-analytics",
33468
33763
  capScope: "device",
@@ -36154,6 +36449,11 @@ Object.freeze({
36154
36449
  form: "single",
36155
36450
  optional: false
36156
36451
  }],
36452
+ "deviceManager.getBindingsBatch": [{
36453
+ name: "deviceIds",
36454
+ form: "array",
36455
+ optional: false
36456
+ }],
36157
36457
  "deviceManager.getChildren": [{
36158
36458
  name: "parentDeviceId",
36159
36459
  form: "single",
@@ -36199,6 +36499,11 @@ Object.freeze({
36199
36499
  form: "single",
36200
36500
  optional: false
36201
36501
  }],
36502
+ "deviceManager.getLinkedDevicesBatch": [{
36503
+ name: "deviceIds",
36504
+ form: "array",
36505
+ optional: false
36506
+ }],
36202
36507
  "deviceManager.getSettingsSchema": [{
36203
36508
  name: "deviceId",
36204
36509
  form: "single",
@@ -36219,6 +36524,11 @@ Object.freeze({
36219
36524
  form: "single",
36220
36525
  optional: false
36221
36526
  }],
36527
+ "deviceManager.listAll": [{
36528
+ name: "deviceIds",
36529
+ form: "array",
36530
+ optional: true
36531
+ }],
36222
36532
  "deviceManager.loadConfig": [{
36223
36533
  name: "deviceId",
36224
36534
  form: "single",
@@ -36792,6 +37102,11 @@ Object.freeze({
36792
37102
  form: "single",
36793
37103
  optional: false
36794
37104
  }],
37105
+ "pipelineAnalytics.getGroup": [{
37106
+ name: "deviceId",
37107
+ form: "single",
37108
+ optional: false
37109
+ }],
36795
37110
  "pipelineAnalytics.getKeyEvents": [{
36796
37111
  name: "deviceId",
36797
37112
  form: "single",
@@ -36847,6 +37162,11 @@ Object.freeze({
36847
37162
  form: "array",
36848
37163
  optional: false
36849
37164
  }],
37165
+ "pipelineAnalytics.listGroups": [{
37166
+ name: "deviceIds",
37167
+ form: "array",
37168
+ optional: false
37169
+ }],
36850
37170
  "pipelineAnalytics.listOpsLog": [{
36851
37171
  name: "deviceId",
36852
37172
  form: "single",