@camstack/addon-notifiers 1.2.31 → 1.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +431 -111
  2. package/dist/addon.mjs +431 -111
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5831,6 +5831,13 @@ var BaseAddon = class {
5831
5831
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5832
5832
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5833
5833
  _registeredCapNames = [];
5834
+ /**
5835
+ * True only after `readAddonStore` actually answered. Constructor
5836
+ * defaults look like stored config when the store is down — a forked
5837
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5838
+ * mode, 2026-08-25) is not "the operator chose this".
5839
+ */
5840
+ settingsStoreReady = false;
5834
5841
  /** Default config values. Provided via constructor. */
5835
5842
  defaults;
5836
5843
  constructor(defaults) {
@@ -6231,7 +6238,9 @@ var BaseAddon = class {
6231
6238
  ];
6232
6239
  let lastErr;
6233
6240
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6234
- return await settings.readAddonStore() ?? {};
6241
+ const stored = await settings.readAddonStore() ?? {};
6242
+ this.settingsStoreReady = true;
6243
+ return stored;
6235
6244
  } catch (err) {
6236
6245
  lastErr = err;
6237
6246
  const msg = err instanceof Error ? err.message : String(err);
@@ -6239,6 +6248,7 @@ var BaseAddon = class {
6239
6248
  if (attempt === delaysMs.length) break;
6240
6249
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6241
6250
  }
6251
+ this.settingsStoreReady = false;
6242
6252
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6243
6253
  return {};
6244
6254
  }
@@ -6650,7 +6660,7 @@ function method(input, output, options) {
6650
6660
  input,
6651
6661
  output,
6652
6662
  kind: options?.kind ?? "query",
6653
- auth: options?.auth ?? "protected",
6663
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6654
6664
  ...options?.access !== void 0 ? { access: options.access } : {},
6655
6665
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6656
6666
  timeoutMs: options?.timeoutMs
@@ -6670,7 +6680,7 @@ function systemMethod(input, output, options) {
6670
6680
  }
6671
6681
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6672
6682
  var VersionOutputSchema$1 = object({ version: string() });
6673
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6683
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6674
6684
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6675
6685
  DeviceType["Camera"] = "camera";
6676
6686
  DeviceType["Hub"] = "hub";
@@ -6991,7 +7001,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6991
7001
  }({});
6992
7002
  var StaticDirOutputSchema = object({ staticDir: string() });
6993
7003
  var VersionOutputSchema = object({ version: string() });
6994
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7004
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
6995
7005
  /**
6996
7006
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6997
7007
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7724,24 +7734,6 @@ var RecordingRetentionSchema = object({
7724
7734
  maxSizeGb: number().min(0).optional()
7725
7735
  });
7726
7736
  /**
7727
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7728
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7729
- * previews at. Five graduated steps; absent on a config = `standard` (the
7730
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7731
- *
7732
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7733
- * Each window's index sidecar carries its own tile dims, so a camera whose
7734
- * preset changed over time renders every historical window at the dims it was
7735
- * written with.
7736
- */
7737
- var ScrubThumbnailPresetSchema = _enum([
7738
- "minimal",
7739
- "low",
7740
- "standard",
7741
- "high",
7742
- "max"
7743
- ]);
7744
- /**
7745
7737
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7746
7738
  *
7747
7739
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7749,7 +7741,11 @@ var ScrubThumbnailPresetSchema = _enum([
7749
7741
  * other field is a storage knob (profiles, segment length, retention, scrub).
7750
7742
  *
7751
7743
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7752
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7744
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7745
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7746
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7747
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7748
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7753
7749
  * A stale caller must fail loudly — silently stripping its legacy intent would
7754
7750
  * persist a band-less config, i.e. silently stop recording the camera.
7755
7751
  */
@@ -7772,14 +7768,7 @@ var RecordingConfigSchema = object({
7772
7768
  * "off" is the absence of a covering band, never a band value.
7773
7769
  */
7774
7770
  bands: array(RecordingBandSchema).default([]),
7775
- retention: RecordingRetentionSchema.optional(),
7776
- /**
7777
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7778
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7779
- * windows only — existing sheets are immutable, and each window's index
7780
- * carries its own tile dims so mixed-preset history renders correctly.
7781
- */
7782
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7771
+ retention: RecordingRetentionSchema.optional()
7783
7772
  }).strict();
7784
7773
  /**
7785
7774
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7855,10 +7844,11 @@ var RelocateFootageInputSchema = object({
7855
7844
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7856
7845
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7857
7846
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7858
- var StorageMigrationMediaMoveInputSchema = object({
7847
+ var RelocateMediaInputSchema = object({
7859
7848
  toLocationId: string(),
7860
7849
  throttleMbps: number().min(1).max(1e3).optional()
7861
- }).extend({ leaseId: string().min(1) });
7850
+ });
7851
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7862
7852
  /** The independently selectable logical storage classes. `recordings`
7863
7853
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7864
7854
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8153,7 +8143,26 @@ var LabelDefinitionSchema = object({
8153
8143
  description: string().optional(),
8154
8144
  icon: string().optional()
8155
8145
  });
8156
- var ClassMapDefinitionSchema = object({
8146
+ /**
8147
+ * Wire schema for a per-model CATALOG classMap override
8148
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8149
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8150
+ * detection pipeline executor actually routes.
8151
+ *
8152
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8153
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8154
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8155
+ * enum) — the two used to share the name `ClassMapDefinition`/
8156
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8157
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8158
+ * are not: it is two different concepts colliding on a name. Keep this type
8159
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8160
+ * would either narrow every `ClassMapDefinition` consumer to the four
8161
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8162
+ * schema exists for (see the "rejects a classMap whose target is not a
8163
+ * detection macro" test in `model-catalog-schema.test.ts`).
8164
+ */
8165
+ var DetectionCatalogClassMapSchema = object({
8157
8166
  mapping: record(string(), _enum([
8158
8167
  "person",
8159
8168
  "vehicle",
@@ -8245,6 +8254,12 @@ var ModelVariantGroupSchema = object({
8245
8254
  */
8246
8255
  resolution: number().int().positive().optional()
8247
8256
  });
8257
+ var ModelProviderIdSchema = _enum([
8258
+ "camstack",
8259
+ "frigate",
8260
+ "scrypted",
8261
+ "custom"
8262
+ ]);
8248
8263
  var ModelCatalogEntrySchema = object({
8249
8264
  id: string(),
8250
8265
  name: string(),
@@ -8342,11 +8357,17 @@ var ModelCatalogEntrySchema = object({
8342
8357
  */
8343
8358
  group: ModelVariantGroupSchema.optional(),
8344
8359
  /**
8360
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8361
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8362
+ * persisted before this field existed (`inferModelProvider` fills those).
8363
+ */
8364
+ provider: ModelProviderIdSchema.optional(),
8365
+ /**
8345
8366
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8346
8367
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8347
8368
  * labels already ARE the CamStack macros (Scrypted identity map).
8348
8369
  */
8349
- classMap: ClassMapDefinitionSchema.optional()
8370
+ classMap: DetectionCatalogClassMapSchema.optional()
8350
8371
  });
8351
8372
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8352
8373
  format: literal("openvino"),
@@ -8376,7 +8397,7 @@ var ModelConvertMetadataSchema = object({
8376
8397
  "segmentation"
8377
8398
  ]),
8378
8399
  faceAlignment: boolean().optional(),
8379
- classMap: ClassMapDefinitionSchema.optional()
8400
+ classMap: DetectionCatalogClassMapSchema.optional()
8380
8401
  });
8381
8402
  var ConvertResultSchema = object({
8382
8403
  entry: ModelCatalogEntrySchema,
@@ -9239,7 +9260,7 @@ var AddonPageDeclarationSchema = object({
9239
9260
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9240
9261
  sectionLabel: string().optional()
9241
9262
  });
9242
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9263
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9243
9264
  var AddonHttpRouteSchema = object({
9244
9265
  method: _enum([
9245
9266
  "GET",
@@ -9493,7 +9514,7 @@ var WidgetMetadataSchema = object({
9493
9514
  defaultColumns: number().int().min(1).max(12).default(6),
9494
9515
  defaultRows: number().int().min(1).max(12).default(1)
9495
9516
  });
9496
- method(_void(), array(WidgetMetadataSchema).readonly());
9517
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9497
9518
  /**
9498
9519
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9499
9520
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11037,7 +11058,7 @@ var CustomModelDescriptorSchema = object({
11037
11058
  stepId: string(),
11038
11059
  entry: ModelCatalogEntrySchema
11039
11060
  });
11040
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11061
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11041
11062
  /**
11042
11063
  * Query filter for settings-store collections.
11043
11064
  */
@@ -11124,7 +11145,8 @@ method(object({
11124
11145
  }), _void(), { kind: "mutation" }), method(object({
11125
11146
  namespace: string().optional(),
11126
11147
  collection: string(),
11127
- filter: QueryFilterSchema.optional()
11148
+ filter: QueryFilterSchema.optional(),
11149
+ columns: array(string()).readonly().optional()
11128
11150
  }), array(SettingsRecordSchema).readonly()), method(object({
11129
11151
  namespace: string().optional(),
11130
11152
  collection: string(),
@@ -11187,46 +11209,87 @@ var EngineInfoSchema = object({
11187
11209
  kind: _enum(["relational", "vector"]),
11188
11210
  displayName: string()
11189
11211
  });
11190
- method(_void(), EngineInfoSchema), method(object({
11212
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11191
11213
  namespace: string().optional(),
11192
11214
  collection: string(),
11193
11215
  key: string()
11194
- }), unknown()), method(object({
11216
+ }), unknown(), { auth: "admin" }), method(object({
11195
11217
  namespace: string().optional(),
11196
11218
  collection: string(),
11197
11219
  key: string(),
11198
11220
  value: unknown()
11199
- }), _void(), { kind: "mutation" }), method(object({
11221
+ }), _void(), {
11222
+ kind: "mutation",
11223
+ auth: "admin"
11224
+ }), method(object({
11200
11225
  namespace: string().optional(),
11201
11226
  collection: string(),
11202
- filter: QueryFilterSchema.optional()
11203
- }), array(SettingsRecordSchema).readonly()), method(object({
11227
+ filter: QueryFilterSchema.optional(),
11228
+ /**
11229
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11230
+ *
11231
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11232
+ * was wrong — corrected 2026-08-26 after the hop map
11233
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11234
+ * There is **no Zod parse at all** between the door and the engine: the
11235
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11236
+ * field declared here reaches `SqliteSettingsBackend` either way.
11237
+ *
11238
+ * What actually lost `columns` was the THIRD declaration of this shape:
11239
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11240
+ * interface the engine destructures from. The field existed on both
11241
+ * schemas and the engine still never read it, because nothing checks a
11242
+ * registered provider against `InferProvider<cap>` —
11243
+ * `ProviderRegistration.provider` is typed `object`.
11244
+ *
11245
+ * It is declared here anyway, and must stay in step with
11246
+ * `settings-store.query`: a caller reading only the cap definitions has
11247
+ * to be able to see that this call carries a projection.
11248
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11249
+ */
11250
+ columns: array(string()).readonly().optional()
11251
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11204
11252
  namespace: string().optional(),
11205
11253
  collection: string(),
11206
11254
  record: SettingsRecordSchema
11207
- }), _void(), { kind: "mutation" }), method(object({
11255
+ }), _void(), {
11256
+ kind: "mutation",
11257
+ auth: "admin"
11258
+ }), method(object({
11208
11259
  namespace: string().optional(),
11209
11260
  collection: string(),
11210
11261
  id: string(),
11211
11262
  data: record(string(), unknown())
11212
- }), _void(), { kind: "mutation" }), method(object({
11263
+ }), _void(), {
11264
+ kind: "mutation",
11265
+ auth: "admin"
11266
+ }), method(object({
11213
11267
  namespace: string().optional(),
11214
11268
  collection: string(),
11215
11269
  key: string()
11216
- }), _void(), { kind: "mutation" }), method(object({
11270
+ }), _void(), {
11271
+ kind: "mutation",
11272
+ auth: "admin"
11273
+ }), method(object({
11217
11274
  namespace: string().optional(),
11218
11275
  collection: string(),
11219
11276
  filter: MutationFilterSchema
11220
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11277
+ }), object({ deleted: number().int() }), {
11278
+ kind: "mutation",
11279
+ auth: "admin"
11280
+ }), method(object({
11221
11281
  namespace: string().optional(),
11222
11282
  collection: string(),
11223
11283
  filter: MutationFilterSchema,
11224
11284
  data: record(string(), unknown())
11225
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11285
+ }), object({ updated: number().int() }), {
11286
+ kind: "mutation",
11287
+ auth: "admin"
11288
+ }), method(object({
11226
11289
  namespace: string().optional(),
11227
11290
  collection: string(),
11228
11291
  filter: QueryFilterSchema.optional()
11229
- }), number()), method(object({
11292
+ }), number(), { auth: "admin" }), method(object({
11230
11293
  namespace: string().optional(),
11231
11294
  collection: string(),
11232
11295
  field: string(),
@@ -11236,15 +11299,18 @@ method(_void(), EngineInfoSchema), method(object({
11236
11299
  }), array(object({
11237
11300
  bucket: number().int(),
11238
11301
  count: number().int()
11239
- })).readonly()), method(object({
11302
+ })).readonly(), { auth: "admin" }), method(object({
11240
11303
  namespace: string().optional(),
11241
11304
  collection: string()
11242
- }), boolean()), method(object({
11305
+ }), boolean(), { auth: "admin" }), method(object({
11243
11306
  namespace: string().optional(),
11244
11307
  collection: string(),
11245
11308
  columns: array(CollectionColumnSchema).readonly(),
11246
11309
  indexes: array(CollectionIndexSchema).readonly().optional()
11247
- }), _void(), { kind: "mutation" });
11310
+ }), _void(), {
11311
+ kind: "mutation",
11312
+ auth: "admin"
11313
+ });
11248
11314
  /**
11249
11315
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11250
11316
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -11910,6 +11976,27 @@ var LinkedDeviceSchema = object({
11910
11976
  features: array(string()),
11911
11977
  producesTrackedEvents: boolean().optional()
11912
11978
  });
11979
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11980
+ * The batch answer needs the tag; the single-device answer already has it
11981
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11982
+ var LinkedDevicesForDeviceSchema = object({
11983
+ deviceId: number(),
11984
+ mode: LinkedDevicesModeSchema,
11985
+ devices: array(LinkedDeviceSchema)
11986
+ });
11987
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11988
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11989
+ * object literal is exactly how the three drift apart. */
11990
+ var DeviceBindingsForDeviceSchema = object({
11991
+ deviceId: number(),
11992
+ entries: array(object({
11993
+ capName: string(),
11994
+ kind: _enum(["native", "wrapped"]),
11995
+ providerAddonId: string(),
11996
+ providerNodeId: string(),
11997
+ nativeAddonId: string()
11998
+ }))
11999
+ });
11913
12000
  var SavedDeviceRowSchema = object({
11914
12001
  /** Numeric id reserved at allocateDeviceId time. */
11915
12002
  id: number(),
@@ -12135,11 +12222,25 @@ method(object({
12135
12222
  projection: _enum(["full", "slim"]).optional(),
12136
12223
  /** Return only camera devices. Filtering server-side instead of
12137
12224
  * shipping 293 rows to find 12. */
12138
- isCamera: boolean().optional()
12225
+ isCamera: boolean().optional(),
12226
+ /**
12227
+ * Return only these device ids. For the caller that already KNOWS the
12228
+ * handful it wants and needs a field the id-bearing answer does not
12229
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12230
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12231
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12232
+ * refetches on the reconcile interval, on a phone.
12233
+ *
12234
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12235
+ * keys rather than rejecting them (verified against the live hub
12236
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12237
+ * it answers today and the caller filters as it already does.
12238
+ */
12239
+ deviceIds: array(number()).optional()
12139
12240
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12140
12241
  mode: LinkedDevicesModeSchema,
12141
12242
  devices: array(LinkedDeviceSchema)
12142
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12243
+ })), 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({
12143
12244
  deviceId: number(),
12144
12245
  values: record(string(), unknown())
12145
12246
  }), object({ success: literal(true) }), {
@@ -12166,25 +12267,7 @@ method(object({
12166
12267
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12167
12268
  kind: "mutation",
12168
12269
  auth: "admin"
12169
- }), method(object({ deviceId: number() }), object({
12170
- deviceId: number(),
12171
- entries: array(object({
12172
- capName: string(),
12173
- kind: _enum(["native", "wrapped"]),
12174
- providerAddonId: string(),
12175
- providerNodeId: string(),
12176
- nativeAddonId: string()
12177
- }))
12178
- })), method(object({}), array(object({
12179
- deviceId: number(),
12180
- entries: array(object({
12181
- capName: string(),
12182
- kind: _enum(["native", "wrapped"]),
12183
- providerAddonId: string(),
12184
- providerNodeId: string(),
12185
- nativeAddonId: string()
12186
- }))
12187
- }))), method(object({
12270
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12188
12271
  deviceId: number(),
12189
12272
  capName: string(),
12190
12273
  wrapperAddonId: string(),
@@ -12355,7 +12438,7 @@ method(object({
12355
12438
  crop: _instanceof(Uint8Array),
12356
12439
  width: number(),
12357
12440
  height: number()
12358
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12441
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12359
12442
  /**
12360
12443
  * filesystem-browse — per-node capability for browsing the node's local
12361
12444
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12648,19 +12731,22 @@ method(LlmGenerateBaseInputSchema.extend({
12648
12731
  runtime: ManagedRuntimeConfigSchema,
12649
12732
  /** The managed profile's timeout, threaded by the hub provider. */
12650
12733
  timeoutMs: number().int().positive().optional()
12651
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12734
+ }), LlmGenerateResultSchema, {
12735
+ kind: "mutation",
12736
+ auth: "admin"
12737
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12652
12738
  kind: "mutation",
12653
12739
  auth: "admin"
12654
12740
  }), method(object({}), _void(), {
12655
12741
  kind: "mutation",
12656
12742
  auth: "admin"
12657
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12743
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12658
12744
  kind: "mutation",
12659
12745
  auth: "admin"
12660
12746
  }), method(object({ file: string() }), _void(), {
12661
12747
  kind: "mutation",
12662
12748
  auth: "admin"
12663
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12749
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12664
12750
  /**
12665
12751
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12666
12752
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14570,12 +14656,15 @@ var NcOccupancyConditionSchema = object({
14570
14656
  * there is no second switch that can disagree with the first and every rule
14571
14657
  * authored before the decision migrates for free (`audioModeOf`):
14572
14658
  *
14573
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14574
- * classifier labels with one of them. No window, no percentage:
14575
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14576
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14577
- * the analyzer's (`classificationMinScore`, per device) — a label only
14578
- * reaches this condition if the classifier was already confident enough.
14659
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14660
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14661
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14662
+ * frames is the wrong question for a classifier that labels 1–3 frames
14663
+ * per episode. The count window is the brake that drops a single-frame
14664
+ * false positive; the rule's own `throttle` cooldown is the other. The
14665
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14666
+ * per device) — a label only reaches this condition if the classifier was
14667
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14579
14668
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14580
14669
  * the condition: at least `hitPercent`% of the samples over
14581
14670
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14602,14 +14691,22 @@ var NcOccupancyConditionSchema = object({
14602
14691
  * an operator who typed `dog` mean the same thing.
14603
14692
  */
14604
14693
  var NcAudioConditionSchema = object({
14605
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14694
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14606
14695
  labels: array(string().min(1)).min(1).optional(),
14607
14696
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14608
14697
  dbThreshold: number().min(-96).max(0).optional(),
14609
14698
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14610
14699
  hitPercent: number().int().min(1).max(100).default(60),
14611
14700
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14612
- samplingSeconds: number().int().min(1).max(300).default(10)
14701
+ samplingSeconds: number().int().min(1).max(300).default(10),
14702
+ /**
14703
+ * LABEL MODE: how many labelled frames must land inside
14704
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14705
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14706
+ */
14707
+ confirmHits: number().int().min(1).max(20).optional(),
14708
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14709
+ confirmWindowSec: number().int().min(1).max(60).optional()
14613
14710
  });
14614
14711
  /**
14615
14712
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16136,7 +16233,7 @@ var OauthIntegrationDescriptorSchema = object({
16136
16233
  */
16137
16234
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16138
16235
  });
16139
- method(_void(), OauthIntegrationDescriptorSchema);
16236
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16140
16237
  /**
16141
16238
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16142
16239
  * per-frame detections emitted by the pipeline runner into tracked
@@ -16983,6 +17080,46 @@ var RecentTracksPageSchema = object({
16983
17080
  /** Cursor for the next page, or null when this page is the last. */
16984
17081
  nextCursor: string().nullable()
16985
17082
  });
17083
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17084
+ var LIST_GROUPS_MAX_LIMIT = 100;
17085
+ var AnalyticsGroupRecordSchema = object({
17086
+ id: string(),
17087
+ deviceId: number().int(),
17088
+ openedAt: number().int(),
17089
+ closedAt: number().int(),
17090
+ timestamp: number().int(),
17091
+ memberCount: number().int(),
17092
+ memberTrackIds: array(string()).readonly(),
17093
+ className: string(),
17094
+ classes: array(string()).readonly(),
17095
+ /** Relative event-media path, or null when the group has no picture yet. */
17096
+ mediaUrl: string().nullable(),
17097
+ singleton: boolean()
17098
+ });
17099
+ var AnalyticsGroupMemberSchema = object({
17100
+ trackId: string(),
17101
+ deviceId: number().int(),
17102
+ className: string(),
17103
+ firstSeen: number().int(),
17104
+ lastSeen: number().int(),
17105
+ mediaUrl: string().nullable()
17106
+ });
17107
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17108
+ var ListGroupsQueryInput = object({
17109
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17110
+ deviceIds: array(number()),
17111
+ /** Window lower bound on `closedAt` (inclusive). */
17112
+ since: number().optional(),
17113
+ /** Window upper bound on `openedAt` (inclusive). */
17114
+ until: number().optional(),
17115
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17116
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17117
+ cursor: string().optional()
17118
+ });
17119
+ var ListGroupsPageSchema = object({
17120
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17121
+ nextCursor: string().nullable()
17122
+ });
16986
17123
  var KeyEventQueryInput = object({
16987
17124
  deviceId: number(),
16988
17125
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17058,7 +17195,9 @@ var TrackCascadeCountsSchema = object({
17058
17195
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17059
17196
  plates: number().int(),
17060
17197
  /** Per-track CLIP search vectors removed (best-effort). */
17061
- embeddings: number().int()
17198
+ embeddings: number().int(),
17199
+ /** Group membership + group rows removed with their last member (best-effort). */
17200
+ groups: number().int()
17062
17201
  });
17063
17202
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17064
17203
  var DiskReconcileCountsSchema = object({
@@ -17204,7 +17343,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17204
17343
  * stationary registry). Default false: the timeline lists passages,
17205
17344
  * not parking records (operator decision, 2026-08-15). */
17206
17345
  includeStationary: boolean().optional()
17207
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17346
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17347
+ deviceId: number(),
17348
+ groupId: string().min(1)
17349
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17208
17350
  kind: "mutation",
17209
17351
  auth: "admin"
17210
17352
  }), 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({
@@ -17286,6 +17428,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17286
17428
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17287
17429
  kind: "mutation",
17288
17430
  auth: "admin"
17431
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17432
+ kind: "mutation",
17433
+ auth: "admin"
17434
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17435
+ kind: "query",
17436
+ auth: "admin"
17437
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17438
+ kind: "mutation",
17439
+ auth: "admin"
17289
17440
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17290
17441
  kind: "query",
17291
17442
  auth: "admin"
@@ -17440,6 +17591,11 @@ object({
17440
17591
  "jpeg"
17441
17592
  ])
17442
17593
  });
17594
+ /**
17595
+ * Process-local frame identity. It is serializable so it can ride an in-process
17596
+ * capability call, but `registryId` deliberately prevents resolution in any
17597
+ * other process or execution group.
17598
+ */
17443
17599
  var FrameRefSchema = object({
17444
17600
  registryId: string().min(1),
17445
17601
  id: string().min(1),
@@ -17514,7 +17670,8 @@ var PipelineModelOptionSchema = object({
17514
17670
  sizeMB: number()
17515
17671
  })),
17516
17672
  group: ModelVariantGroupSchema.optional(),
17517
- legacy: boolean().optional()
17673
+ legacy: boolean().optional(),
17674
+ provider: ModelProviderIdSchema.optional()
17518
17675
  });
17519
17676
  var ConfigFieldBridge = custom();
17520
17677
  var PipelineAddonSchemaSchema = object({
@@ -19604,7 +19761,7 @@ method(object({
19604
19761
  * linking rather than produce an eternal token.
19605
19762
  */
19606
19763
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19607
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19764
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19608
19765
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19609
19766
  providerId: string().min(1),
19610
19767
  displayName: string().min(1),
@@ -19699,10 +19856,13 @@ var EvictResultSchema = object({
19699
19856
  /** True when the provider has nothing left it is willing to drop on this location. */
19700
19857
  exhausted: boolean()
19701
19858
  });
19702
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19859
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19703
19860
  locationId: string(),
19704
19861
  targetBytes: number().int().positive()
19705
- }), EvictResultSchema, { kind: "mutation" });
19862
+ }), EvictResultSchema, {
19863
+ kind: "mutation",
19864
+ auth: "admin"
19865
+ });
19706
19866
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19707
19867
  kind: "mutation",
19708
19868
  auth: "admin"
@@ -19762,26 +19922,50 @@ var ReadChunkInputSchema = object({
19762
19922
  length: number()
19763
19923
  });
19764
19924
  var EndDownloadInputSchema = object({ downloadId: string() });
19765
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19925
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19766
19926
  location: StorageLocationSchema,
19767
19927
  relativePath: string()
19768
- }), string()), method(object({
19928
+ }), string(), { auth: "admin" }), method(object({
19769
19929
  location: StorageLocationSchema,
19770
19930
  relativePath: string(),
19771
19931
  data: _instanceof(Uint8Array)
19772
- }), _void(), { kind: "mutation" }), method(object({
19932
+ }), _void(), {
19933
+ kind: "mutation",
19934
+ auth: "admin"
19935
+ }), method(object({
19773
19936
  location: StorageLocationSchema,
19774
19937
  relativePath: string()
19775
- }), _instanceof(Uint8Array)), method(object({
19938
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19776
19939
  location: StorageLocationSchema,
19777
19940
  relativePath: string()
19778
- }), boolean()), method(object({
19941
+ }), boolean(), { auth: "admin" }), method(object({
19779
19942
  location: StorageLocationSchema,
19780
19943
  prefix: string().optional()
19781
- }), array(string()).readonly()), method(object({
19944
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19782
19945
  location: StorageLocationSchema,
19783
19946
  relativePath: string()
19784
- }), _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" });
19947
+ }), _void(), {
19948
+ kind: "mutation",
19949
+ auth: "admin"
19950
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
19951
+ kind: "mutation",
19952
+ auth: "admin"
19953
+ }), method(WriteChunkInputSchema, _void(), {
19954
+ kind: "mutation",
19955
+ auth: "admin"
19956
+ }), method(FinalizeUploadInputSchema, _void(), {
19957
+ kind: "mutation",
19958
+ auth: "admin"
19959
+ }), method(AbortUploadInputSchema, _void(), {
19960
+ kind: "mutation",
19961
+ auth: "admin"
19962
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
19963
+ kind: "mutation",
19964
+ auth: "admin"
19965
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
19966
+ kind: "mutation",
19967
+ auth: "admin"
19968
+ });
19785
19969
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19786
19970
  var ProfileSettingsSchemaBridge = unknown().nullable();
19787
19971
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20039,7 +20223,8 @@ method(object({
20039
20223
  access: "create"
20040
20224
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20041
20225
  kind: "mutation",
20042
- access: "view"
20226
+ access: "view",
20227
+ auth: "admin"
20043
20228
  }), method(object({
20044
20229
  /** Required — the user the assertion belongs to (verified). */
20045
20230
  userId: string(),
@@ -20047,10 +20232,12 @@ method(object({
20047
20232
  response: record(string(), unknown())
20048
20233
  }), object({ verified: boolean() }), {
20049
20234
  kind: "mutation",
20050
- access: "view"
20235
+ access: "view",
20236
+ auth: "admin"
20051
20237
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20052
20238
  kind: "mutation",
20053
- access: "view"
20239
+ access: "view",
20240
+ auth: "admin"
20054
20241
  }), method(object({
20055
20242
  /** AuthenticationResponseJSON from the browser. */
20056
20243
  response: record(string(), unknown()) }), object({
@@ -20058,7 +20245,8 @@ response: record(string(), unknown()) }), object({
20058
20245
  userId: string().nullable()
20059
20246
  }), {
20060
20247
  kind: "mutation",
20061
- access: "view"
20248
+ access: "view",
20249
+ auth: "admin"
20062
20250
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20063
20251
  userId: string(),
20064
20252
  credentialId: string()
@@ -20230,7 +20418,19 @@ var VectorStatsResultSchema = object({
20230
20418
  /** False when the backend ranks approximately. */
20231
20419
  exact: boolean()
20232
20420
  });
20233
- 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);
20421
+ method(VectorDeclareIndexInputSchema, _void(), {
20422
+ kind: "mutation",
20423
+ auth: "admin"
20424
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20425
+ kind: "mutation",
20426
+ auth: "admin"
20427
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20428
+ kind: "mutation",
20429
+ auth: "admin"
20430
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20431
+ kind: "mutation",
20432
+ auth: "admin"
20433
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20234
20434
  var ClipSchema = object({
20235
20435
  /** Opaque, provider-namespaced id. The default provider encodes the time
20236
20436
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21953,7 +22153,27 @@ var MediaFileLiteSchema$1 = object({
21953
22153
  sizeBytes: number(),
21954
22154
  timestamp: number()
21955
22155
  });
21956
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22156
+ method(object({
22157
+ /**
22158
+ * Inline {@link IdentitySchema.coverBase64} on every row.
22159
+ *
22160
+ * Default `false`, the same inversion `listRecentFaces` and
22161
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
22162
+ * why the burden belongs on the caller that WANTS the bytes). Measured
22163
+ * on the live hub the same day: four identities cost 40,979 B with the
22164
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
22165
+ * four times and the viewer holds at `staleTime: 30_000`.
22166
+ *
22167
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
22168
+ * the `event-media` plane serves that key `immutable` with an ETag.
22169
+ *
22170
+ * **This is an INPUT field, so it does not reach the addon until the
22171
+ * next train** — the hub router validates cap inputs against its own
22172
+ * compiled Zod and strips a key it does not know. Until then the
22173
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
22174
+ * is what ships, and the opt-in becomes reachable when the train lands.
22175
+ */
22176
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
21957
22177
  kind: "mutation",
21958
22178
  auth: "admin"
21959
22179
  }), method(object({
@@ -24098,7 +24318,14 @@ var PlateInfoSchema = object({
24098
24318
  plateBbox: BoundingBoxSchema.optional(),
24099
24319
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
24100
24320
  keyFrameMediaKey: string().optional(),
24101
- base64: string().optional()
24321
+ base64: string().optional(),
24322
+ /**
24323
+ * Same crop as a data-plane URL, always present when the plate has a stored
24324
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24325
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24326
+ * left at its `true` default.
24327
+ */
24328
+ cropUrl: string().optional()
24102
24329
  });
24103
24330
  var MediaFileLiteSchema = object({
24104
24331
  key: string(),
@@ -24116,14 +24343,34 @@ var PlateClusterSchema = object({
24116
24343
  });
24117
24344
  method(object({
24118
24345
  deviceId: number().int().optional(),
24119
- limit: number().int().positive().optional()
24346
+ limit: number().int().positive().optional(),
24347
+ /**
24348
+ * Inline the base64 crop on every row. Default `true` — the existing
24349
+ * behaviour, kept so no caller breaks.
24350
+ *
24351
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24352
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24353
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24354
+ * metadata without them — and the browser then caches the images.
24355
+ *
24356
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24357
+ * plates were the one gallery list left without it.
24358
+ *
24359
+ * **This is an INPUT field, so it does not reach the addon until the
24360
+ * next train.** The hub router validates cap inputs against its own
24361
+ * compiled Zod and strips a key it does not know. Until the train
24362
+ * ships, sending `false` is harmless and keeps the crops inline.
24363
+ */
24364
+ includeCrops: boolean().optional()
24120
24365
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
24121
24366
  deviceId: number().int(),
24122
24367
  trackId: string()
24123
24368
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
24124
24369
  text: string().min(1),
24125
24370
  maxDistance: number().int().min(0).optional(),
24126
- limit: number().int().positive().optional()
24371
+ limit: number().int().positive().optional(),
24372
+ /** See `listPlates.includeCrops`. Default `true`. */
24373
+ includeCrops: boolean().optional()
24127
24374
  }), array(PlateInfoSchema).readonly()), method(object({
24128
24375
  maxDistance: number().int().min(0).optional(),
24129
24376
  minClusterSize: number().int().min(2).optional(),
@@ -24137,7 +24384,13 @@ method(object({
24137
24384
  }), method(object({ plateId: string() }), _void(), {
24138
24385
  kind: "mutation",
24139
24386
  auth: "admin"
24140
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24387
+ }), method(object({
24388
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
24389
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
24390
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
24391
+ * INPUT field: stripped by the hub router until the train ships, which
24392
+ * resolves to `false` and is exactly the intended default. */
24393
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24141
24394
  kind: "mutation",
24142
24395
  auth: "admin"
24143
24396
  }), method(object({
@@ -27738,6 +27991,12 @@ Object.freeze({
27738
27991
  addonId: null,
27739
27992
  access: "view"
27740
27993
  },
27994
+ "deviceManager.getBindingsBatch": {
27995
+ capName: "device-manager",
27996
+ capScope: "system",
27997
+ addonId: null,
27998
+ access: "view"
27999
+ },
27741
28000
  "deviceManager.getChildren": {
27742
28001
  capName: "device-manager",
27743
28002
  capScope: "system",
@@ -27798,6 +28057,12 @@ Object.freeze({
27798
28057
  addonId: null,
27799
28058
  access: "view"
27800
28059
  },
28060
+ "deviceManager.getLinkedDevicesBatch": {
28061
+ capName: "device-manager",
28062
+ capScope: "system",
28063
+ addonId: null,
28064
+ access: "view"
28065
+ },
27801
28066
  "deviceManager.getRoleDisplayDefaults": {
27802
28067
  capName: "device-manager",
27803
28068
  capScope: "system",
@@ -29502,6 +29767,12 @@ Object.freeze({
29502
29767
  addonId: null,
29503
29768
  access: "create"
29504
29769
  },
29770
+ "pipelineAnalytics.cancelRelocateMedia": {
29771
+ capName: "pipeline-analytics",
29772
+ capScope: "device",
29773
+ addonId: null,
29774
+ access: "create"
29775
+ },
29505
29776
  "pipelineAnalytics.cancelStorageMigrationMove": {
29506
29777
  capName: "pipeline-analytics",
29507
29778
  capScope: "device",
@@ -29568,6 +29839,12 @@ Object.freeze({
29568
29839
  addonId: null,
29569
29840
  access: "view"
29570
29841
  },
29842
+ "pipelineAnalytics.getGroup": {
29843
+ capName: "pipeline-analytics",
29844
+ capScope: "device",
29845
+ addonId: null,
29846
+ access: "view"
29847
+ },
29571
29848
  "pipelineAnalytics.getKeyEvents": {
29572
29849
  capName: "pipeline-analytics",
29573
29850
  capScope: "device",
@@ -29652,6 +29929,12 @@ Object.freeze({
29652
29929
  addonId: null,
29653
29930
  access: "view"
29654
29931
  },
29932
+ "pipelineAnalytics.listGroups": {
29933
+ capName: "pipeline-analytics",
29934
+ capScope: "device",
29935
+ addonId: null,
29936
+ access: "view"
29937
+ },
29655
29938
  "pipelineAnalytics.listOpsLog": {
29656
29939
  capName: "pipeline-analytics",
29657
29940
  capScope: "device",
@@ -29664,6 +29947,12 @@ Object.freeze({
29664
29947
  addonId: null,
29665
29948
  access: "view"
29666
29949
  },
29950
+ "pipelineAnalytics.listRelocateMediaJobs": {
29951
+ capName: "pipeline-analytics",
29952
+ capScope: "device",
29953
+ addonId: null,
29954
+ access: "view"
29955
+ },
29667
29956
  "pipelineAnalytics.listRetrainAnnotations": {
29668
29957
  capName: "pipeline-analytics",
29669
29958
  capScope: "device",
@@ -29742,6 +30031,12 @@ Object.freeze({
29742
30031
  addonId: null,
29743
30032
  access: "create"
29744
30033
  },
30034
+ "pipelineAnalytics.relocateMedia": {
30035
+ capName: "pipeline-analytics",
30036
+ capScope: "device",
30037
+ addonId: null,
30038
+ access: "create"
30039
+ },
29745
30040
  "pipelineAnalytics.restageRetrainTrack": {
29746
30041
  capName: "pipeline-analytics",
29747
30042
  capScope: "device",
@@ -32433,6 +32728,11 @@ Object.freeze({
32433
32728
  form: "single",
32434
32729
  optional: false
32435
32730
  }],
32731
+ "deviceManager.getBindingsBatch": [{
32732
+ name: "deviceIds",
32733
+ form: "array",
32734
+ optional: false
32735
+ }],
32436
32736
  "deviceManager.getChildren": [{
32437
32737
  name: "parentDeviceId",
32438
32738
  form: "single",
@@ -32478,6 +32778,11 @@ Object.freeze({
32478
32778
  form: "single",
32479
32779
  optional: false
32480
32780
  }],
32781
+ "deviceManager.getLinkedDevicesBatch": [{
32782
+ name: "deviceIds",
32783
+ form: "array",
32784
+ optional: false
32785
+ }],
32481
32786
  "deviceManager.getSettingsSchema": [{
32482
32787
  name: "deviceId",
32483
32788
  form: "single",
@@ -32498,6 +32803,11 @@ Object.freeze({
32498
32803
  form: "single",
32499
32804
  optional: false
32500
32805
  }],
32806
+ "deviceManager.listAll": [{
32807
+ name: "deviceIds",
32808
+ form: "array",
32809
+ optional: true
32810
+ }],
32501
32811
  "deviceManager.loadConfig": [{
32502
32812
  name: "deviceId",
32503
32813
  form: "single",
@@ -33071,6 +33381,11 @@ Object.freeze({
33071
33381
  form: "single",
33072
33382
  optional: false
33073
33383
  }],
33384
+ "pipelineAnalytics.getGroup": [{
33385
+ name: "deviceId",
33386
+ form: "single",
33387
+ optional: false
33388
+ }],
33074
33389
  "pipelineAnalytics.getKeyEvents": [{
33075
33390
  name: "deviceId",
33076
33391
  form: "single",
@@ -33126,6 +33441,11 @@ Object.freeze({
33126
33441
  form: "array",
33127
33442
  optional: false
33128
33443
  }],
33444
+ "pipelineAnalytics.listGroups": [{
33445
+ name: "deviceIds",
33446
+ form: "array",
33447
+ optional: false
33448
+ }],
33129
33449
  "pipelineAnalytics.listOpsLog": [{
33130
33450
  name: "deviceId",
33131
33451
  form: "single",