@camstack/addon-import-alexa 0.2.26 → 0.2.28

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
@@ -5840,6 +5840,13 @@ var BaseAddon = class {
5840
5840
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5841
5841
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5842
5842
  _registeredCapNames = [];
5843
+ /**
5844
+ * True only after `readAddonStore` actually answered. Constructor
5845
+ * defaults look like stored config when the store is down — a forked
5846
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5847
+ * mode, 2026-08-25) is not "the operator chose this".
5848
+ */
5849
+ settingsStoreReady = false;
5843
5850
  /** Default config values. Provided via constructor. */
5844
5851
  defaults;
5845
5852
  constructor(defaults) {
@@ -6240,7 +6247,9 @@ var BaseAddon = class {
6240
6247
  ];
6241
6248
  let lastErr;
6242
6249
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6243
- return await settings.readAddonStore() ?? {};
6250
+ const stored = await settings.readAddonStore() ?? {};
6251
+ this.settingsStoreReady = true;
6252
+ return stored;
6244
6253
  } catch (err) {
6245
6254
  lastErr = err;
6246
6255
  const msg = err instanceof Error ? err.message : String(err);
@@ -6248,6 +6257,7 @@ var BaseAddon = class {
6248
6257
  if (attempt === delaysMs.length) break;
6249
6258
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6250
6259
  }
6260
+ this.settingsStoreReady = false;
6251
6261
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6252
6262
  return {};
6253
6263
  }
@@ -6659,7 +6669,7 @@ function method(input, output, options) {
6659
6669
  input,
6660
6670
  output,
6661
6671
  kind: options?.kind ?? "query",
6662
- auth: options?.auth ?? "protected",
6672
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6663
6673
  ...options?.access !== void 0 ? { access: options.access } : {},
6664
6674
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6665
6675
  timeoutMs: options?.timeoutMs
@@ -6683,7 +6693,7 @@ function event(data) {
6683
6693
  }
6684
6694
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6685
6695
  var VersionOutputSchema$1 = object({ version: string() });
6686
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6696
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6687
6697
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6688
6698
  DeviceType["Camera"] = "camera";
6689
6699
  DeviceType["Hub"] = "hub";
@@ -7004,7 +7014,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7004
7014
  }({});
7005
7015
  var StaticDirOutputSchema = object({ staticDir: string() });
7006
7016
  var VersionOutputSchema = object({ version: string() });
7007
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7017
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7008
7018
  /**
7009
7019
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7010
7020
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7749,24 +7759,6 @@ var RecordingRetentionSchema = object({
7749
7759
  maxSizeGb: number().min(0).optional()
7750
7760
  });
7751
7761
  /**
7752
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7753
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7754
- * previews at. Five graduated steps; absent on a config = `standard` (the
7755
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7756
- *
7757
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7758
- * Each window's index sidecar carries its own tile dims, so a camera whose
7759
- * preset changed over time renders every historical window at the dims it was
7760
- * written with.
7761
- */
7762
- var ScrubThumbnailPresetSchema = _enum([
7763
- "minimal",
7764
- "low",
7765
- "standard",
7766
- "high",
7767
- "max"
7768
- ]);
7769
- /**
7770
7762
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7771
7763
  *
7772
7764
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7774,7 +7766,11 @@ var ScrubThumbnailPresetSchema = _enum([
7774
7766
  * other field is a storage knob (profiles, segment length, retention, scrub).
7775
7767
  *
7776
7768
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7777
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7769
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7770
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7771
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7772
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7773
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7778
7774
  * A stale caller must fail loudly — silently stripping its legacy intent would
7779
7775
  * persist a band-less config, i.e. silently stop recording the camera.
7780
7776
  */
@@ -7797,14 +7793,7 @@ var RecordingConfigSchema = object({
7797
7793
  * "off" is the absence of a covering band, never a band value.
7798
7794
  */
7799
7795
  bands: array(RecordingBandSchema).default([]),
7800
- retention: RecordingRetentionSchema.optional(),
7801
- /**
7802
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7803
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7804
- * windows only — existing sheets are immutable, and each window's index
7805
- * carries its own tile dims so mixed-preset history renders correctly.
7806
- */
7807
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7796
+ retention: RecordingRetentionSchema.optional()
7808
7797
  }).strict();
7809
7798
  /**
7810
7799
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7880,10 +7869,11 @@ var RelocateFootageInputSchema = object({
7880
7869
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7881
7870
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7882
7871
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7883
- var StorageMigrationMediaMoveInputSchema = object({
7872
+ var RelocateMediaInputSchema = object({
7884
7873
  toLocationId: string(),
7885
7874
  throttleMbps: number().min(1).max(1e3).optional()
7886
- }).extend({ leaseId: string().min(1) });
7875
+ });
7876
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7887
7877
  /** The independently selectable logical storage classes. `recordings`
7888
7878
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7889
7879
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8178,7 +8168,26 @@ var LabelDefinitionSchema = object({
8178
8168
  description: string().optional(),
8179
8169
  icon: string().optional()
8180
8170
  });
8181
- var ClassMapDefinitionSchema = object({
8171
+ /**
8172
+ * Wire schema for a per-model CATALOG classMap override
8173
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8174
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8175
+ * detection pipeline executor actually routes.
8176
+ *
8177
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8178
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8179
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8180
+ * enum) — the two used to share the name `ClassMapDefinition`/
8181
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8182
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8183
+ * are not: it is two different concepts colliding on a name. Keep this type
8184
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8185
+ * would either narrow every `ClassMapDefinition` consumer to the four
8186
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8187
+ * schema exists for (see the "rejects a classMap whose target is not a
8188
+ * detection macro" test in `model-catalog-schema.test.ts`).
8189
+ */
8190
+ var DetectionCatalogClassMapSchema = object({
8182
8191
  mapping: record(string(), _enum([
8183
8192
  "person",
8184
8193
  "vehicle",
@@ -8270,6 +8279,12 @@ var ModelVariantGroupSchema = object({
8270
8279
  */
8271
8280
  resolution: number().int().positive().optional()
8272
8281
  });
8282
+ var ModelProviderIdSchema = _enum([
8283
+ "camstack",
8284
+ "frigate",
8285
+ "scrypted",
8286
+ "custom"
8287
+ ]);
8273
8288
  var ModelCatalogEntrySchema = object({
8274
8289
  id: string(),
8275
8290
  name: string(),
@@ -8367,11 +8382,17 @@ var ModelCatalogEntrySchema = object({
8367
8382
  */
8368
8383
  group: ModelVariantGroupSchema.optional(),
8369
8384
  /**
8385
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8386
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8387
+ * persisted before this field existed (`inferModelProvider` fills those).
8388
+ */
8389
+ provider: ModelProviderIdSchema.optional(),
8390
+ /**
8370
8391
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8371
8392
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8372
8393
  * labels already ARE the CamStack macros (Scrypted identity map).
8373
8394
  */
8374
- classMap: ClassMapDefinitionSchema.optional()
8395
+ classMap: DetectionCatalogClassMapSchema.optional()
8375
8396
  });
8376
8397
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8377
8398
  format: literal("openvino"),
@@ -8401,7 +8422,7 @@ var ModelConvertMetadataSchema = object({
8401
8422
  "segmentation"
8402
8423
  ]),
8403
8424
  faceAlignment: boolean().optional(),
8404
- classMap: ClassMapDefinitionSchema.optional()
8425
+ classMap: DetectionCatalogClassMapSchema.optional()
8405
8426
  });
8406
8427
  var ConvertResultSchema = object({
8407
8428
  entry: ModelCatalogEntrySchema,
@@ -9264,7 +9285,7 @@ var AddonPageDeclarationSchema = object({
9264
9285
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9265
9286
  sectionLabel: string().optional()
9266
9287
  });
9267
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9288
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9268
9289
  var AddonHttpRouteSchema = object({
9269
9290
  method: _enum([
9270
9291
  "GET",
@@ -9518,7 +9539,7 @@ var WidgetMetadataSchema = object({
9518
9539
  defaultColumns: number().int().min(1).max(12).default(6),
9519
9540
  defaultRows: number().int().min(1).max(12).default(1)
9520
9541
  });
9521
- method(_void(), array(WidgetMetadataSchema).readonly());
9542
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9522
9543
  /**
9523
9544
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9524
9545
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11191,7 +11212,7 @@ var CustomModelDescriptorSchema = object({
11191
11212
  stepId: string(),
11192
11213
  entry: ModelCatalogEntrySchema
11193
11214
  });
11194
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11215
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11195
11216
  /**
11196
11217
  * Query filter for settings-store collections.
11197
11218
  */
@@ -11278,7 +11299,8 @@ method(object({
11278
11299
  }), _void(), { kind: "mutation" }), method(object({
11279
11300
  namespace: string().optional(),
11280
11301
  collection: string(),
11281
- filter: QueryFilterSchema.optional()
11302
+ filter: QueryFilterSchema.optional(),
11303
+ columns: array(string()).readonly().optional()
11282
11304
  }), array(SettingsRecordSchema).readonly()), method(object({
11283
11305
  namespace: string().optional(),
11284
11306
  collection: string(),
@@ -11341,46 +11363,87 @@ var EngineInfoSchema = object({
11341
11363
  kind: _enum(["relational", "vector"]),
11342
11364
  displayName: string()
11343
11365
  });
11344
- method(_void(), EngineInfoSchema), method(object({
11366
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11345
11367
  namespace: string().optional(),
11346
11368
  collection: string(),
11347
11369
  key: string()
11348
- }), unknown()), method(object({
11370
+ }), unknown(), { auth: "admin" }), method(object({
11349
11371
  namespace: string().optional(),
11350
11372
  collection: string(),
11351
11373
  key: string(),
11352
11374
  value: unknown()
11353
- }), _void(), { kind: "mutation" }), method(object({
11375
+ }), _void(), {
11376
+ kind: "mutation",
11377
+ auth: "admin"
11378
+ }), method(object({
11354
11379
  namespace: string().optional(),
11355
11380
  collection: string(),
11356
- filter: QueryFilterSchema.optional()
11357
- }), array(SettingsRecordSchema).readonly()), method(object({
11381
+ filter: QueryFilterSchema.optional(),
11382
+ /**
11383
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11384
+ *
11385
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11386
+ * was wrong — corrected 2026-08-26 after the hop map
11387
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11388
+ * There is **no Zod parse at all** between the door and the engine: the
11389
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11390
+ * field declared here reaches `SqliteSettingsBackend` either way.
11391
+ *
11392
+ * What actually lost `columns` was the THIRD declaration of this shape:
11393
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11394
+ * interface the engine destructures from. The field existed on both
11395
+ * schemas and the engine still never read it, because nothing checks a
11396
+ * registered provider against `InferProvider<cap>` —
11397
+ * `ProviderRegistration.provider` is typed `object`.
11398
+ *
11399
+ * It is declared here anyway, and must stay in step with
11400
+ * `settings-store.query`: a caller reading only the cap definitions has
11401
+ * to be able to see that this call carries a projection.
11402
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11403
+ */
11404
+ columns: array(string()).readonly().optional()
11405
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11358
11406
  namespace: string().optional(),
11359
11407
  collection: string(),
11360
11408
  record: SettingsRecordSchema
11361
- }), _void(), { kind: "mutation" }), method(object({
11409
+ }), _void(), {
11410
+ kind: "mutation",
11411
+ auth: "admin"
11412
+ }), method(object({
11362
11413
  namespace: string().optional(),
11363
11414
  collection: string(),
11364
11415
  id: string(),
11365
11416
  data: record(string(), unknown())
11366
- }), _void(), { kind: "mutation" }), method(object({
11417
+ }), _void(), {
11418
+ kind: "mutation",
11419
+ auth: "admin"
11420
+ }), method(object({
11367
11421
  namespace: string().optional(),
11368
11422
  collection: string(),
11369
11423
  key: string()
11370
- }), _void(), { kind: "mutation" }), method(object({
11424
+ }), _void(), {
11425
+ kind: "mutation",
11426
+ auth: "admin"
11427
+ }), method(object({
11371
11428
  namespace: string().optional(),
11372
11429
  collection: string(),
11373
11430
  filter: MutationFilterSchema
11374
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11431
+ }), object({ deleted: number().int() }), {
11432
+ kind: "mutation",
11433
+ auth: "admin"
11434
+ }), method(object({
11375
11435
  namespace: string().optional(),
11376
11436
  collection: string(),
11377
11437
  filter: MutationFilterSchema,
11378
11438
  data: record(string(), unknown())
11379
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11439
+ }), object({ updated: number().int() }), {
11440
+ kind: "mutation",
11441
+ auth: "admin"
11442
+ }), method(object({
11380
11443
  namespace: string().optional(),
11381
11444
  collection: string(),
11382
11445
  filter: QueryFilterSchema.optional()
11383
- }), number()), method(object({
11446
+ }), number(), { auth: "admin" }), method(object({
11384
11447
  namespace: string().optional(),
11385
11448
  collection: string(),
11386
11449
  field: string(),
@@ -11390,15 +11453,18 @@ method(_void(), EngineInfoSchema), method(object({
11390
11453
  }), array(object({
11391
11454
  bucket: number().int(),
11392
11455
  count: number().int()
11393
- })).readonly()), method(object({
11456
+ })).readonly(), { auth: "admin" }), method(object({
11394
11457
  namespace: string().optional(),
11395
11458
  collection: string()
11396
- }), boolean()), method(object({
11459
+ }), boolean(), { auth: "admin" }), method(object({
11397
11460
  namespace: string().optional(),
11398
11461
  collection: string(),
11399
11462
  columns: array(CollectionColumnSchema).readonly(),
11400
11463
  indexes: array(CollectionIndexSchema).readonly().optional()
11401
- }), _void(), { kind: "mutation" });
11464
+ }), _void(), {
11465
+ kind: "mutation",
11466
+ auth: "admin"
11467
+ });
11402
11468
  /**
11403
11469
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11404
11470
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -12243,6 +12309,27 @@ var LinkedDeviceSchema = object({
12243
12309
  features: array(string()),
12244
12310
  producesTrackedEvents: boolean().optional()
12245
12311
  });
12312
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12313
+ * The batch answer needs the tag; the single-device answer already has it
12314
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12315
+ var LinkedDevicesForDeviceSchema = object({
12316
+ deviceId: number(),
12317
+ mode: LinkedDevicesModeSchema,
12318
+ devices: array(LinkedDeviceSchema)
12319
+ });
12320
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12321
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12322
+ * object literal is exactly how the three drift apart. */
12323
+ var DeviceBindingsForDeviceSchema = object({
12324
+ deviceId: number(),
12325
+ entries: array(object({
12326
+ capName: string(),
12327
+ kind: _enum(["native", "wrapped"]),
12328
+ providerAddonId: string(),
12329
+ providerNodeId: string(),
12330
+ nativeAddonId: string()
12331
+ }))
12332
+ });
12246
12333
  var SavedDeviceRowSchema = object({
12247
12334
  /** Numeric id reserved at allocateDeviceId time. */
12248
12335
  id: number(),
@@ -12468,11 +12555,25 @@ method(object({
12468
12555
  projection: _enum(["full", "slim"]).optional(),
12469
12556
  /** Return only camera devices. Filtering server-side instead of
12470
12557
  * shipping 293 rows to find 12. */
12471
- isCamera: boolean().optional()
12558
+ isCamera: boolean().optional(),
12559
+ /**
12560
+ * Return only these device ids. For the caller that already KNOWS the
12561
+ * handful it wants and needs a field the id-bearing answer does not
12562
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12563
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12564
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12565
+ * refetches on the reconcile interval, on a phone.
12566
+ *
12567
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12568
+ * keys rather than rejecting them (verified against the live hub
12569
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12570
+ * it answers today and the caller filters as it already does.
12571
+ */
12572
+ deviceIds: array(number()).optional()
12472
12573
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12473
12574
  mode: LinkedDevicesModeSchema,
12474
12575
  devices: array(LinkedDeviceSchema)
12475
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12576
+ })), 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({
12476
12577
  deviceId: number(),
12477
12578
  values: record(string(), unknown())
12478
12579
  }), object({ success: literal(true) }), {
@@ -12499,25 +12600,7 @@ method(object({
12499
12600
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12500
12601
  kind: "mutation",
12501
12602
  auth: "admin"
12502
- }), method(object({ deviceId: number() }), object({
12503
- deviceId: number(),
12504
- entries: array(object({
12505
- capName: string(),
12506
- kind: _enum(["native", "wrapped"]),
12507
- providerAddonId: string(),
12508
- providerNodeId: string(),
12509
- nativeAddonId: string()
12510
- }))
12511
- })), method(object({}), array(object({
12512
- deviceId: number(),
12513
- entries: array(object({
12514
- capName: string(),
12515
- kind: _enum(["native", "wrapped"]),
12516
- providerAddonId: string(),
12517
- providerNodeId: string(),
12518
- nativeAddonId: string()
12519
- }))
12520
- }))), method(object({
12603
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12521
12604
  deviceId: number(),
12522
12605
  capName: string(),
12523
12606
  wrapperAddonId: string(),
@@ -12688,7 +12771,7 @@ method(object({
12688
12771
  crop: _instanceof(Uint8Array),
12689
12772
  width: number(),
12690
12773
  height: number()
12691
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12774
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12692
12775
  /**
12693
12776
  * filesystem-browse — per-node capability for browsing the node's local
12694
12777
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12981,19 +13064,22 @@ method(LlmGenerateBaseInputSchema.extend({
12981
13064
  runtime: ManagedRuntimeConfigSchema,
12982
13065
  /** The managed profile's timeout, threaded by the hub provider. */
12983
13066
  timeoutMs: number().int().positive().optional()
12984
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
13067
+ }), LlmGenerateResultSchema, {
13068
+ kind: "mutation",
13069
+ auth: "admin"
13070
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12985
13071
  kind: "mutation",
12986
13072
  auth: "admin"
12987
13073
  }), method(object({}), _void(), {
12988
13074
  kind: "mutation",
12989
13075
  auth: "admin"
12990
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
13076
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12991
13077
  kind: "mutation",
12992
13078
  auth: "admin"
12993
13079
  }), method(object({ file: string() }), _void(), {
12994
13080
  kind: "mutation",
12995
13081
  auth: "admin"
12996
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
13082
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12997
13083
  /**
12998
13084
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12999
13085
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14927,12 +15013,15 @@ var NcOccupancyConditionSchema = object({
14927
15013
  * there is no second switch that can disagree with the first and every rule
14928
15014
  * authored before the decision migrates for free (`audioModeOf`):
14929
15015
  *
14930
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14931
- * classifier labels with one of them. No window, no percentage:
14932
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14933
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14934
- * the analyzer's (`classificationMinScore`, per device) — a label only
14935
- * reaches this condition if the classifier was already confident enough.
15016
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
15017
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
15018
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
15019
+ * frames is the wrong question for a classifier that labels 1–3 frames
15020
+ * per episode. The count window is the brake that drops a single-frame
15021
+ * false positive; the rule's own `throttle` cooldown is the other. The
15022
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
15023
+ * per device) — a label only reaches this condition if the classifier was
15024
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14936
15025
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14937
15026
  * the condition: at least `hitPercent`% of the samples over
14938
15027
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14959,14 +15048,22 @@ var NcOccupancyConditionSchema = object({
14959
15048
  * an operator who typed `dog` mean the same thing.
14960
15049
  */
14961
15050
  var NcAudioConditionSchema = object({
14962
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
15051
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14963
15052
  labels: array(string().min(1)).min(1).optional(),
14964
15053
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14965
15054
  dbThreshold: number().min(-96).max(0).optional(),
14966
15055
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14967
15056
  hitPercent: number().int().min(1).max(100).default(60),
14968
15057
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14969
- samplingSeconds: number().int().min(1).max(300).default(10)
15058
+ samplingSeconds: number().int().min(1).max(300).default(10),
15059
+ /**
15060
+ * LABEL MODE: how many labelled frames must land inside
15061
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
15062
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
15063
+ */
15064
+ confirmHits: number().int().min(1).max(20).optional(),
15065
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
15066
+ confirmWindowSec: number().int().min(1).max(60).optional()
14970
15067
  });
14971
15068
  /**
14972
15069
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16493,7 +16590,7 @@ var OauthIntegrationDescriptorSchema = object({
16493
16590
  */
16494
16591
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16495
16592
  });
16496
- method(_void(), OauthIntegrationDescriptorSchema);
16593
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16497
16594
  /**
16498
16595
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16499
16596
  * per-frame detections emitted by the pipeline runner into tracked
@@ -17340,6 +17437,46 @@ var RecentTracksPageSchema = object({
17340
17437
  /** Cursor for the next page, or null when this page is the last. */
17341
17438
  nextCursor: string().nullable()
17342
17439
  });
17440
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17441
+ var LIST_GROUPS_MAX_LIMIT = 100;
17442
+ var AnalyticsGroupRecordSchema = object({
17443
+ id: string(),
17444
+ deviceId: number().int(),
17445
+ openedAt: number().int(),
17446
+ closedAt: number().int(),
17447
+ timestamp: number().int(),
17448
+ memberCount: number().int(),
17449
+ memberTrackIds: array(string()).readonly(),
17450
+ className: string(),
17451
+ classes: array(string()).readonly(),
17452
+ /** Relative event-media path, or null when the group has no picture yet. */
17453
+ mediaUrl: string().nullable(),
17454
+ singleton: boolean()
17455
+ });
17456
+ var AnalyticsGroupMemberSchema = object({
17457
+ trackId: string(),
17458
+ deviceId: number().int(),
17459
+ className: string(),
17460
+ firstSeen: number().int(),
17461
+ lastSeen: number().int(),
17462
+ mediaUrl: string().nullable()
17463
+ });
17464
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17465
+ var ListGroupsQueryInput = object({
17466
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17467
+ deviceIds: array(number()),
17468
+ /** Window lower bound on `closedAt` (inclusive). */
17469
+ since: number().optional(),
17470
+ /** Window upper bound on `openedAt` (inclusive). */
17471
+ until: number().optional(),
17472
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17473
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17474
+ cursor: string().optional()
17475
+ });
17476
+ var ListGroupsPageSchema = object({
17477
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17478
+ nextCursor: string().nullable()
17479
+ });
17343
17480
  var KeyEventQueryInput = object({
17344
17481
  deviceId: number(),
17345
17482
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17415,7 +17552,9 @@ var TrackCascadeCountsSchema = object({
17415
17552
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17416
17553
  plates: number().int(),
17417
17554
  /** Per-track CLIP search vectors removed (best-effort). */
17418
- embeddings: number().int()
17555
+ embeddings: number().int(),
17556
+ /** Group membership + group rows removed with their last member (best-effort). */
17557
+ groups: number().int()
17419
17558
  });
17420
17559
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17421
17560
  var DiskReconcileCountsSchema = object({
@@ -17561,7 +17700,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17561
17700
  * stationary registry). Default false: the timeline lists passages,
17562
17701
  * not parking records (operator decision, 2026-08-15). */
17563
17702
  includeStationary: boolean().optional()
17564
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17703
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17704
+ deviceId: number(),
17705
+ groupId: string().min(1)
17706
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17565
17707
  kind: "mutation",
17566
17708
  auth: "admin"
17567
17709
  }), 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({
@@ -17643,6 +17785,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17643
17785
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17644
17786
  kind: "mutation",
17645
17787
  auth: "admin"
17788
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17789
+ kind: "mutation",
17790
+ auth: "admin"
17791
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17792
+ kind: "query",
17793
+ auth: "admin"
17794
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17795
+ kind: "mutation",
17796
+ auth: "admin"
17646
17797
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17647
17798
  kind: "query",
17648
17799
  auth: "admin"
@@ -17797,6 +17948,11 @@ object({
17797
17948
  "jpeg"
17798
17949
  ])
17799
17950
  });
17951
+ /**
17952
+ * Process-local frame identity. It is serializable so it can ride an in-process
17953
+ * capability call, but `registryId` deliberately prevents resolution in any
17954
+ * other process or execution group.
17955
+ */
17800
17956
  var FrameRefSchema = object({
17801
17957
  registryId: string().min(1),
17802
17958
  id: string().min(1),
@@ -17871,7 +18027,8 @@ var PipelineModelOptionSchema = object({
17871
18027
  sizeMB: number()
17872
18028
  })),
17873
18029
  group: ModelVariantGroupSchema.optional(),
17874
- legacy: boolean().optional()
18030
+ legacy: boolean().optional(),
18031
+ provider: ModelProviderIdSchema.optional()
17875
18032
  });
17876
18033
  var ConfigFieldBridge = custom();
17877
18034
  var PipelineAddonSchemaSchema = object({
@@ -20001,7 +20158,7 @@ method(object({
20001
20158
  * linking rather than produce an eternal token.
20002
20159
  */
20003
20160
  ttlSec: union([number().int().positive(), literal("never")]).optional()
20004
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
20161
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
20005
20162
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
20006
20163
  providerId: string().min(1),
20007
20164
  displayName: string().min(1),
@@ -20096,10 +20253,13 @@ var EvictResultSchema = object({
20096
20253
  /** True when the provider has nothing left it is willing to drop on this location. */
20097
20254
  exhausted: boolean()
20098
20255
  });
20099
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
20256
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
20100
20257
  locationId: string(),
20101
20258
  targetBytes: number().int().positive()
20102
- }), EvictResultSchema, { kind: "mutation" });
20259
+ }), EvictResultSchema, {
20260
+ kind: "mutation",
20261
+ auth: "admin"
20262
+ });
20103
20263
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
20104
20264
  kind: "mutation",
20105
20265
  auth: "admin"
@@ -20159,26 +20319,50 @@ var ReadChunkInputSchema = object({
20159
20319
  length: number()
20160
20320
  });
20161
20321
  var EndDownloadInputSchema = object({ downloadId: string() });
20162
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20322
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
20163
20323
  location: StorageLocationSchema,
20164
20324
  relativePath: string()
20165
- }), string()), method(object({
20325
+ }), string(), { auth: "admin" }), method(object({
20166
20326
  location: StorageLocationSchema,
20167
20327
  relativePath: string(),
20168
20328
  data: _instanceof(Uint8Array)
20169
- }), _void(), { kind: "mutation" }), method(object({
20329
+ }), _void(), {
20330
+ kind: "mutation",
20331
+ auth: "admin"
20332
+ }), method(object({
20170
20333
  location: StorageLocationSchema,
20171
20334
  relativePath: string()
20172
- }), _instanceof(Uint8Array)), method(object({
20335
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
20173
20336
  location: StorageLocationSchema,
20174
20337
  relativePath: string()
20175
- }), boolean()), method(object({
20338
+ }), boolean(), { auth: "admin" }), method(object({
20176
20339
  location: StorageLocationSchema,
20177
20340
  prefix: string().optional()
20178
- }), array(string()).readonly()), method(object({
20341
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
20179
20342
  location: StorageLocationSchema,
20180
20343
  relativePath: string()
20181
- }), _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" });
20344
+ }), _void(), {
20345
+ kind: "mutation",
20346
+ auth: "admin"
20347
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
20348
+ kind: "mutation",
20349
+ auth: "admin"
20350
+ }), method(WriteChunkInputSchema, _void(), {
20351
+ kind: "mutation",
20352
+ auth: "admin"
20353
+ }), method(FinalizeUploadInputSchema, _void(), {
20354
+ kind: "mutation",
20355
+ auth: "admin"
20356
+ }), method(AbortUploadInputSchema, _void(), {
20357
+ kind: "mutation",
20358
+ auth: "admin"
20359
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
20360
+ kind: "mutation",
20361
+ auth: "admin"
20362
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
20363
+ kind: "mutation",
20364
+ auth: "admin"
20365
+ });
20182
20366
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20183
20367
  var ProfileSettingsSchemaBridge = unknown().nullable();
20184
20368
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20436,7 +20620,8 @@ method(object({
20436
20620
  access: "create"
20437
20621
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20438
20622
  kind: "mutation",
20439
- access: "view"
20623
+ access: "view",
20624
+ auth: "admin"
20440
20625
  }), method(object({
20441
20626
  /** Required — the user the assertion belongs to (verified). */
20442
20627
  userId: string(),
@@ -20444,10 +20629,12 @@ method(object({
20444
20629
  response: record(string(), unknown())
20445
20630
  }), object({ verified: boolean() }), {
20446
20631
  kind: "mutation",
20447
- access: "view"
20632
+ access: "view",
20633
+ auth: "admin"
20448
20634
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20449
20635
  kind: "mutation",
20450
- access: "view"
20636
+ access: "view",
20637
+ auth: "admin"
20451
20638
  }), method(object({
20452
20639
  /** AuthenticationResponseJSON from the browser. */
20453
20640
  response: record(string(), unknown()) }), object({
@@ -20455,7 +20642,8 @@ response: record(string(), unknown()) }), object({
20455
20642
  userId: string().nullable()
20456
20643
  }), {
20457
20644
  kind: "mutation",
20458
- access: "view"
20645
+ access: "view",
20646
+ auth: "admin"
20459
20647
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20460
20648
  userId: string(),
20461
20649
  credentialId: string()
@@ -20627,7 +20815,19 @@ var VectorStatsResultSchema = object({
20627
20815
  /** False when the backend ranks approximately. */
20628
20816
  exact: boolean()
20629
20817
  });
20630
- 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);
20818
+ method(VectorDeclareIndexInputSchema, _void(), {
20819
+ kind: "mutation",
20820
+ auth: "admin"
20821
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20822
+ kind: "mutation",
20823
+ auth: "admin"
20824
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20825
+ kind: "mutation",
20826
+ auth: "admin"
20827
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20828
+ kind: "mutation",
20829
+ auth: "admin"
20830
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20631
20831
  var ClipSchema = object({
20632
20832
  /** Opaque, provider-namespaced id. The default provider encodes the time
20633
20833
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -23097,7 +23297,27 @@ var MediaFileLiteSchema$1 = object({
23097
23297
  sizeBytes: number(),
23098
23298
  timestamp: number()
23099
23299
  });
23100
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23300
+ method(object({
23301
+ /**
23302
+ * Inline {@link IdentitySchema.coverBase64} on every row.
23303
+ *
23304
+ * Default `false`, the same inversion `listRecentFaces` and
23305
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
23306
+ * why the burden belongs on the caller that WANTS the bytes). Measured
23307
+ * on the live hub the same day: four identities cost 40,979 B with the
23308
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
23309
+ * four times and the viewer holds at `staleTime: 30_000`.
23310
+ *
23311
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
23312
+ * the `event-media` plane serves that key `immutable` with an ETag.
23313
+ *
23314
+ * **This is an INPUT field, so it does not reach the addon until the
23315
+ * next train** — the hub router validates cap inputs against its own
23316
+ * compiled Zod and strips a key it does not know. Until then the
23317
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
23318
+ * is what ships, and the opt-in becomes reachable when the train lands.
23319
+ */
23320
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23101
23321
  kind: "mutation",
23102
23322
  auth: "admin"
23103
23323
  }), method(object({
@@ -25985,7 +26205,14 @@ var PlateInfoSchema = object({
25985
26205
  plateBbox: BoundingBoxSchema.optional(),
25986
26206
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25987
26207
  keyFrameMediaKey: string().optional(),
25988
- base64: string().optional()
26208
+ base64: string().optional(),
26209
+ /**
26210
+ * Same crop as a data-plane URL, always present when the plate has a stored
26211
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
26212
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
26213
+ * left at its `true` default.
26214
+ */
26215
+ cropUrl: string().optional()
25989
26216
  });
25990
26217
  var MediaFileLiteSchema = object({
25991
26218
  key: string(),
@@ -26003,14 +26230,34 @@ var PlateClusterSchema = object({
26003
26230
  });
26004
26231
  method(object({
26005
26232
  deviceId: number().int().optional(),
26006
- limit: number().int().positive().optional()
26233
+ limit: number().int().positive().optional(),
26234
+ /**
26235
+ * Inline the base64 crop on every row. Default `true` — the existing
26236
+ * behaviour, kept so no caller breaks.
26237
+ *
26238
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
26239
+ * Measured on the live hub at the 500 rows the Plates view asks for:
26240
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
26241
+ * metadata without them — and the browser then caches the images.
26242
+ *
26243
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
26244
+ * plates were the one gallery list left without it.
26245
+ *
26246
+ * **This is an INPUT field, so it does not reach the addon until the
26247
+ * next train.** The hub router validates cap inputs against its own
26248
+ * compiled Zod and strips a key it does not know. Until the train
26249
+ * ships, sending `false` is harmless and keeps the crops inline.
26250
+ */
26251
+ includeCrops: boolean().optional()
26007
26252
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
26008
26253
  deviceId: number().int(),
26009
26254
  trackId: string()
26010
26255
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
26011
26256
  text: string().min(1),
26012
26257
  maxDistance: number().int().min(0).optional(),
26013
- limit: number().int().positive().optional()
26258
+ limit: number().int().positive().optional(),
26259
+ /** See `listPlates.includeCrops`. Default `true`. */
26260
+ includeCrops: boolean().optional()
26014
26261
  }), array(PlateInfoSchema).readonly()), method(object({
26015
26262
  maxDistance: number().int().min(0).optional(),
26016
26263
  minClusterSize: number().int().min(2).optional(),
@@ -26024,7 +26271,13 @@ method(object({
26024
26271
  }), method(object({ plateId: string() }), _void(), {
26025
26272
  kind: "mutation",
26026
26273
  auth: "admin"
26027
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26274
+ }), method(object({
26275
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
26276
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
26277
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
26278
+ * INPUT field: stripped by the hub router until the train ships, which
26279
+ * resolves to `false` and is exactly the intended default. */
26280
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26028
26281
  kind: "mutation",
26029
26282
  auth: "admin"
26030
26283
  }), method(object({
@@ -31509,6 +31762,12 @@ Object.freeze({
31509
31762
  addonId: null,
31510
31763
  access: "view"
31511
31764
  },
31765
+ "deviceManager.getBindingsBatch": {
31766
+ capName: "device-manager",
31767
+ capScope: "system",
31768
+ addonId: null,
31769
+ access: "view"
31770
+ },
31512
31771
  "deviceManager.getChildren": {
31513
31772
  capName: "device-manager",
31514
31773
  capScope: "system",
@@ -31569,6 +31828,12 @@ Object.freeze({
31569
31828
  addonId: null,
31570
31829
  access: "view"
31571
31830
  },
31831
+ "deviceManager.getLinkedDevicesBatch": {
31832
+ capName: "device-manager",
31833
+ capScope: "system",
31834
+ addonId: null,
31835
+ access: "view"
31836
+ },
31572
31837
  "deviceManager.getRoleDisplayDefaults": {
31573
31838
  capName: "device-manager",
31574
31839
  capScope: "system",
@@ -33273,6 +33538,12 @@ Object.freeze({
33273
33538
  addonId: null,
33274
33539
  access: "create"
33275
33540
  },
33541
+ "pipelineAnalytics.cancelRelocateMedia": {
33542
+ capName: "pipeline-analytics",
33543
+ capScope: "device",
33544
+ addonId: null,
33545
+ access: "create"
33546
+ },
33276
33547
  "pipelineAnalytics.cancelStorageMigrationMove": {
33277
33548
  capName: "pipeline-analytics",
33278
33549
  capScope: "device",
@@ -33339,6 +33610,12 @@ Object.freeze({
33339
33610
  addonId: null,
33340
33611
  access: "view"
33341
33612
  },
33613
+ "pipelineAnalytics.getGroup": {
33614
+ capName: "pipeline-analytics",
33615
+ capScope: "device",
33616
+ addonId: null,
33617
+ access: "view"
33618
+ },
33342
33619
  "pipelineAnalytics.getKeyEvents": {
33343
33620
  capName: "pipeline-analytics",
33344
33621
  capScope: "device",
@@ -33423,6 +33700,12 @@ Object.freeze({
33423
33700
  addonId: null,
33424
33701
  access: "view"
33425
33702
  },
33703
+ "pipelineAnalytics.listGroups": {
33704
+ capName: "pipeline-analytics",
33705
+ capScope: "device",
33706
+ addonId: null,
33707
+ access: "view"
33708
+ },
33426
33709
  "pipelineAnalytics.listOpsLog": {
33427
33710
  capName: "pipeline-analytics",
33428
33711
  capScope: "device",
@@ -33435,6 +33718,12 @@ Object.freeze({
33435
33718
  addonId: null,
33436
33719
  access: "view"
33437
33720
  },
33721
+ "pipelineAnalytics.listRelocateMediaJobs": {
33722
+ capName: "pipeline-analytics",
33723
+ capScope: "device",
33724
+ addonId: null,
33725
+ access: "view"
33726
+ },
33438
33727
  "pipelineAnalytics.listRetrainAnnotations": {
33439
33728
  capName: "pipeline-analytics",
33440
33729
  capScope: "device",
@@ -33513,6 +33802,12 @@ Object.freeze({
33513
33802
  addonId: null,
33514
33803
  access: "create"
33515
33804
  },
33805
+ "pipelineAnalytics.relocateMedia": {
33806
+ capName: "pipeline-analytics",
33807
+ capScope: "device",
33808
+ addonId: null,
33809
+ access: "create"
33810
+ },
33516
33811
  "pipelineAnalytics.restageRetrainTrack": {
33517
33812
  capName: "pipeline-analytics",
33518
33813
  capScope: "device",
@@ -36204,6 +36499,11 @@ Object.freeze({
36204
36499
  form: "single",
36205
36500
  optional: false
36206
36501
  }],
36502
+ "deviceManager.getBindingsBatch": [{
36503
+ name: "deviceIds",
36504
+ form: "array",
36505
+ optional: false
36506
+ }],
36207
36507
  "deviceManager.getChildren": [{
36208
36508
  name: "parentDeviceId",
36209
36509
  form: "single",
@@ -36249,6 +36549,11 @@ Object.freeze({
36249
36549
  form: "single",
36250
36550
  optional: false
36251
36551
  }],
36552
+ "deviceManager.getLinkedDevicesBatch": [{
36553
+ name: "deviceIds",
36554
+ form: "array",
36555
+ optional: false
36556
+ }],
36252
36557
  "deviceManager.getSettingsSchema": [{
36253
36558
  name: "deviceId",
36254
36559
  form: "single",
@@ -36269,6 +36574,11 @@ Object.freeze({
36269
36574
  form: "single",
36270
36575
  optional: false
36271
36576
  }],
36577
+ "deviceManager.listAll": [{
36578
+ name: "deviceIds",
36579
+ form: "array",
36580
+ optional: true
36581
+ }],
36272
36582
  "deviceManager.loadConfig": [{
36273
36583
  name: "deviceId",
36274
36584
  form: "single",
@@ -36842,6 +37152,11 @@ Object.freeze({
36842
37152
  form: "single",
36843
37153
  optional: false
36844
37154
  }],
37155
+ "pipelineAnalytics.getGroup": [{
37156
+ name: "deviceId",
37157
+ form: "single",
37158
+ optional: false
37159
+ }],
36845
37160
  "pipelineAnalytics.getKeyEvents": [{
36846
37161
  name: "deviceId",
36847
37162
  form: "single",
@@ -36897,6 +37212,11 @@ Object.freeze({
36897
37212
  form: "array",
36898
37213
  optional: false
36899
37214
  }],
37215
+ "pipelineAnalytics.listGroups": [{
37216
+ name: "deviceIds",
37217
+ form: "array",
37218
+ optional: false
37219
+ }],
36900
37220
  "pipelineAnalytics.listOpsLog": [{
36901
37221
  name: "deviceId",
36902
37222
  form: "single",