@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.mjs CHANGED
@@ -5804,6 +5804,13 @@ var BaseAddon = class {
5804
5804
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5805
5805
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5806
5806
  _registeredCapNames = [];
5807
+ /**
5808
+ * True only after `readAddonStore` actually answered. Constructor
5809
+ * defaults look like stored config when the store is down — a forked
5810
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5811
+ * mode, 2026-08-25) is not "the operator chose this".
5812
+ */
5813
+ settingsStoreReady = false;
5807
5814
  /** Default config values. Provided via constructor. */
5808
5815
  defaults;
5809
5816
  constructor(defaults) {
@@ -6204,7 +6211,9 @@ var BaseAddon = class {
6204
6211
  ];
6205
6212
  let lastErr;
6206
6213
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6207
- return await settings.readAddonStore() ?? {};
6214
+ const stored = await settings.readAddonStore() ?? {};
6215
+ this.settingsStoreReady = true;
6216
+ return stored;
6208
6217
  } catch (err) {
6209
6218
  lastErr = err;
6210
6219
  const msg = err instanceof Error ? err.message : String(err);
@@ -6212,6 +6221,7 @@ var BaseAddon = class {
6212
6221
  if (attempt === delaysMs.length) break;
6213
6222
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6214
6223
  }
6224
+ this.settingsStoreReady = false;
6215
6225
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6216
6226
  return {};
6217
6227
  }
@@ -6623,7 +6633,7 @@ function method(input, output, options) {
6623
6633
  input,
6624
6634
  output,
6625
6635
  kind: options?.kind ?? "query",
6626
- auth: options?.auth ?? "protected",
6636
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6627
6637
  ...options?.access !== void 0 ? { access: options.access } : {},
6628
6638
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6629
6639
  timeoutMs: options?.timeoutMs
@@ -6643,7 +6653,7 @@ function systemMethod(input, output, options) {
6643
6653
  }
6644
6654
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6645
6655
  var VersionOutputSchema$1 = object({ version: string() });
6646
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6656
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6647
6657
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6648
6658
  DeviceType["Camera"] = "camera";
6649
6659
  DeviceType["Hub"] = "hub";
@@ -6964,7 +6974,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6964
6974
  }({});
6965
6975
  var StaticDirOutputSchema = object({ staticDir: string() });
6966
6976
  var VersionOutputSchema = object({ version: string() });
6967
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
6977
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
6968
6978
  /**
6969
6979
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6970
6980
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7697,24 +7707,6 @@ var RecordingRetentionSchema = object({
7697
7707
  maxSizeGb: number().min(0).optional()
7698
7708
  });
7699
7709
  /**
7700
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7701
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7702
- * previews at. Five graduated steps; absent on a config = `standard` (the
7703
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7704
- *
7705
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7706
- * Each window's index sidecar carries its own tile dims, so a camera whose
7707
- * preset changed over time renders every historical window at the dims it was
7708
- * written with.
7709
- */
7710
- var ScrubThumbnailPresetSchema = _enum([
7711
- "minimal",
7712
- "low",
7713
- "standard",
7714
- "high",
7715
- "max"
7716
- ]);
7717
- /**
7718
7710
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7719
7711
  *
7720
7712
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7722,7 +7714,11 @@ var ScrubThumbnailPresetSchema = _enum([
7722
7714
  * other field is a storage knob (profiles, segment length, retention, scrub).
7723
7715
  *
7724
7716
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7725
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7717
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7718
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7719
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7720
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7721
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7726
7722
  * A stale caller must fail loudly — silently stripping its legacy intent would
7727
7723
  * persist a band-less config, i.e. silently stop recording the camera.
7728
7724
  */
@@ -7745,14 +7741,7 @@ var RecordingConfigSchema = object({
7745
7741
  * "off" is the absence of a covering band, never a band value.
7746
7742
  */
7747
7743
  bands: array(RecordingBandSchema).default([]),
7748
- retention: RecordingRetentionSchema.optional(),
7749
- /**
7750
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7751
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7752
- * windows only — existing sheets are immutable, and each window's index
7753
- * carries its own tile dims so mixed-preset history renders correctly.
7754
- */
7755
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7744
+ retention: RecordingRetentionSchema.optional()
7756
7745
  }).strict();
7757
7746
  /**
7758
7747
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7828,10 +7817,11 @@ var RelocateFootageInputSchema = object({
7828
7817
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7829
7818
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7830
7819
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7831
- var StorageMigrationMediaMoveInputSchema = object({
7820
+ var RelocateMediaInputSchema = object({
7832
7821
  toLocationId: string(),
7833
7822
  throttleMbps: number().min(1).max(1e3).optional()
7834
- }).extend({ leaseId: string().min(1) });
7823
+ });
7824
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7835
7825
  /** The independently selectable logical storage classes. `recordings`
7836
7826
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7837
7827
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8126,7 +8116,26 @@ var LabelDefinitionSchema = object({
8126
8116
  description: string().optional(),
8127
8117
  icon: string().optional()
8128
8118
  });
8129
- var ClassMapDefinitionSchema = object({
8119
+ /**
8120
+ * Wire schema for a per-model CATALOG classMap override
8121
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8122
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8123
+ * detection pipeline executor actually routes.
8124
+ *
8125
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8126
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8127
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8128
+ * enum) — the two used to share the name `ClassMapDefinition`/
8129
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8130
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8131
+ * are not: it is two different concepts colliding on a name. Keep this type
8132
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8133
+ * would either narrow every `ClassMapDefinition` consumer to the four
8134
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8135
+ * schema exists for (see the "rejects a classMap whose target is not a
8136
+ * detection macro" test in `model-catalog-schema.test.ts`).
8137
+ */
8138
+ var DetectionCatalogClassMapSchema = object({
8130
8139
  mapping: record(string(), _enum([
8131
8140
  "person",
8132
8141
  "vehicle",
@@ -8218,6 +8227,12 @@ var ModelVariantGroupSchema = object({
8218
8227
  */
8219
8228
  resolution: number().int().positive().optional()
8220
8229
  });
8230
+ var ModelProviderIdSchema = _enum([
8231
+ "camstack",
8232
+ "frigate",
8233
+ "scrypted",
8234
+ "custom"
8235
+ ]);
8221
8236
  var ModelCatalogEntrySchema = object({
8222
8237
  id: string(),
8223
8238
  name: string(),
@@ -8315,11 +8330,17 @@ var ModelCatalogEntrySchema = object({
8315
8330
  */
8316
8331
  group: ModelVariantGroupSchema.optional(),
8317
8332
  /**
8333
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8334
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8335
+ * persisted before this field existed (`inferModelProvider` fills those).
8336
+ */
8337
+ provider: ModelProviderIdSchema.optional(),
8338
+ /**
8318
8339
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8319
8340
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8320
8341
  * labels already ARE the CamStack macros (Scrypted identity map).
8321
8342
  */
8322
- classMap: ClassMapDefinitionSchema.optional()
8343
+ classMap: DetectionCatalogClassMapSchema.optional()
8323
8344
  });
8324
8345
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8325
8346
  format: literal("openvino"),
@@ -8349,7 +8370,7 @@ var ModelConvertMetadataSchema = object({
8349
8370
  "segmentation"
8350
8371
  ]),
8351
8372
  faceAlignment: boolean().optional(),
8352
- classMap: ClassMapDefinitionSchema.optional()
8373
+ classMap: DetectionCatalogClassMapSchema.optional()
8353
8374
  });
8354
8375
  var ConvertResultSchema = object({
8355
8376
  entry: ModelCatalogEntrySchema,
@@ -9212,7 +9233,7 @@ var AddonPageDeclarationSchema = object({
9212
9233
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9213
9234
  sectionLabel: string().optional()
9214
9235
  });
9215
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9236
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9216
9237
  var AddonHttpRouteSchema = object({
9217
9238
  method: _enum([
9218
9239
  "GET",
@@ -9466,7 +9487,7 @@ var WidgetMetadataSchema = object({
9466
9487
  defaultColumns: number().int().min(1).max(12).default(6),
9467
9488
  defaultRows: number().int().min(1).max(12).default(1)
9468
9489
  });
9469
- method(_void(), array(WidgetMetadataSchema).readonly());
9490
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9470
9491
  /**
9471
9492
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9472
9493
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -11010,7 +11031,7 @@ var CustomModelDescriptorSchema = object({
11010
11031
  stepId: string(),
11011
11032
  entry: ModelCatalogEntrySchema
11012
11033
  });
11013
- method(_void(), array(CustomModelDescriptorSchema).readonly());
11034
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
11014
11035
  /**
11015
11036
  * Query filter for settings-store collections.
11016
11037
  */
@@ -11097,7 +11118,8 @@ method(object({
11097
11118
  }), _void(), { kind: "mutation" }), method(object({
11098
11119
  namespace: string().optional(),
11099
11120
  collection: string(),
11100
- filter: QueryFilterSchema.optional()
11121
+ filter: QueryFilterSchema.optional(),
11122
+ columns: array(string()).readonly().optional()
11101
11123
  }), array(SettingsRecordSchema).readonly()), method(object({
11102
11124
  namespace: string().optional(),
11103
11125
  collection: string(),
@@ -11160,46 +11182,87 @@ var EngineInfoSchema = object({
11160
11182
  kind: _enum(["relational", "vector"]),
11161
11183
  displayName: string()
11162
11184
  });
11163
- method(_void(), EngineInfoSchema), method(object({
11185
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11164
11186
  namespace: string().optional(),
11165
11187
  collection: string(),
11166
11188
  key: string()
11167
- }), unknown()), method(object({
11189
+ }), unknown(), { auth: "admin" }), method(object({
11168
11190
  namespace: string().optional(),
11169
11191
  collection: string(),
11170
11192
  key: string(),
11171
11193
  value: unknown()
11172
- }), _void(), { kind: "mutation" }), method(object({
11194
+ }), _void(), {
11195
+ kind: "mutation",
11196
+ auth: "admin"
11197
+ }), method(object({
11173
11198
  namespace: string().optional(),
11174
11199
  collection: string(),
11175
- filter: QueryFilterSchema.optional()
11176
- }), array(SettingsRecordSchema).readonly()), method(object({
11200
+ filter: QueryFilterSchema.optional(),
11201
+ /**
11202
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11203
+ *
11204
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11205
+ * was wrong — corrected 2026-08-26 after the hop map
11206
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11207
+ * There is **no Zod parse at all** between the door and the engine: the
11208
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11209
+ * field declared here reaches `SqliteSettingsBackend` either way.
11210
+ *
11211
+ * What actually lost `columns` was the THIRD declaration of this shape:
11212
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11213
+ * interface the engine destructures from. The field existed on both
11214
+ * schemas and the engine still never read it, because nothing checks a
11215
+ * registered provider against `InferProvider<cap>` —
11216
+ * `ProviderRegistration.provider` is typed `object`.
11217
+ *
11218
+ * It is declared here anyway, and must stay in step with
11219
+ * `settings-store.query`: a caller reading only the cap definitions has
11220
+ * to be able to see that this call carries a projection.
11221
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11222
+ */
11223
+ columns: array(string()).readonly().optional()
11224
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11177
11225
  namespace: string().optional(),
11178
11226
  collection: string(),
11179
11227
  record: SettingsRecordSchema
11180
- }), _void(), { kind: "mutation" }), method(object({
11228
+ }), _void(), {
11229
+ kind: "mutation",
11230
+ auth: "admin"
11231
+ }), method(object({
11181
11232
  namespace: string().optional(),
11182
11233
  collection: string(),
11183
11234
  id: string(),
11184
11235
  data: record(string(), unknown())
11185
- }), _void(), { kind: "mutation" }), method(object({
11236
+ }), _void(), {
11237
+ kind: "mutation",
11238
+ auth: "admin"
11239
+ }), method(object({
11186
11240
  namespace: string().optional(),
11187
11241
  collection: string(),
11188
11242
  key: string()
11189
- }), _void(), { kind: "mutation" }), method(object({
11243
+ }), _void(), {
11244
+ kind: "mutation",
11245
+ auth: "admin"
11246
+ }), method(object({
11190
11247
  namespace: string().optional(),
11191
11248
  collection: string(),
11192
11249
  filter: MutationFilterSchema
11193
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11250
+ }), object({ deleted: number().int() }), {
11251
+ kind: "mutation",
11252
+ auth: "admin"
11253
+ }), method(object({
11194
11254
  namespace: string().optional(),
11195
11255
  collection: string(),
11196
11256
  filter: MutationFilterSchema,
11197
11257
  data: record(string(), unknown())
11198
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11258
+ }), object({ updated: number().int() }), {
11259
+ kind: "mutation",
11260
+ auth: "admin"
11261
+ }), method(object({
11199
11262
  namespace: string().optional(),
11200
11263
  collection: string(),
11201
11264
  filter: QueryFilterSchema.optional()
11202
- }), number()), method(object({
11265
+ }), number(), { auth: "admin" }), method(object({
11203
11266
  namespace: string().optional(),
11204
11267
  collection: string(),
11205
11268
  field: string(),
@@ -11209,15 +11272,18 @@ method(_void(), EngineInfoSchema), method(object({
11209
11272
  }), array(object({
11210
11273
  bucket: number().int(),
11211
11274
  count: number().int()
11212
- })).readonly()), method(object({
11275
+ })).readonly(), { auth: "admin" }), method(object({
11213
11276
  namespace: string().optional(),
11214
11277
  collection: string()
11215
- }), boolean()), method(object({
11278
+ }), boolean(), { auth: "admin" }), method(object({
11216
11279
  namespace: string().optional(),
11217
11280
  collection: string(),
11218
11281
  columns: array(CollectionColumnSchema).readonly(),
11219
11282
  indexes: array(CollectionIndexSchema).readonly().optional()
11220
- }), _void(), { kind: "mutation" });
11283
+ }), _void(), {
11284
+ kind: "mutation",
11285
+ auth: "admin"
11286
+ });
11221
11287
  /**
11222
11288
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11223
11289
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -11883,6 +11949,27 @@ var LinkedDeviceSchema = object({
11883
11949
  features: array(string()),
11884
11950
  producesTrackedEvents: boolean().optional()
11885
11951
  });
11952
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11953
+ * The batch answer needs the tag; the single-device answer already has it
11954
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11955
+ var LinkedDevicesForDeviceSchema = object({
11956
+ deviceId: number(),
11957
+ mode: LinkedDevicesModeSchema,
11958
+ devices: array(LinkedDeviceSchema)
11959
+ });
11960
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11961
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11962
+ * object literal is exactly how the three drift apart. */
11963
+ var DeviceBindingsForDeviceSchema = object({
11964
+ deviceId: number(),
11965
+ entries: array(object({
11966
+ capName: string(),
11967
+ kind: _enum(["native", "wrapped"]),
11968
+ providerAddonId: string(),
11969
+ providerNodeId: string(),
11970
+ nativeAddonId: string()
11971
+ }))
11972
+ });
11886
11973
  var SavedDeviceRowSchema = object({
11887
11974
  /** Numeric id reserved at allocateDeviceId time. */
11888
11975
  id: number(),
@@ -12108,11 +12195,25 @@ method(object({
12108
12195
  projection: _enum(["full", "slim"]).optional(),
12109
12196
  /** Return only camera devices. Filtering server-side instead of
12110
12197
  * shipping 293 rows to find 12. */
12111
- isCamera: boolean().optional()
12198
+ isCamera: boolean().optional(),
12199
+ /**
12200
+ * Return only these device ids. For the caller that already KNOWS the
12201
+ * handful it wants and needs a field the id-bearing answer does not
12202
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12203
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12204
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12205
+ * refetches on the reconcile interval, on a phone.
12206
+ *
12207
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12208
+ * keys rather than rejecting them (verified against the live hub
12209
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12210
+ * it answers today and the caller filters as it already does.
12211
+ */
12212
+ deviceIds: array(number()).optional()
12112
12213
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12113
12214
  mode: LinkedDevicesModeSchema,
12114
12215
  devices: array(LinkedDeviceSchema)
12115
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12216
+ })), 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({
12116
12217
  deviceId: number(),
12117
12218
  values: record(string(), unknown())
12118
12219
  }), object({ success: literal(true) }), {
@@ -12139,25 +12240,7 @@ method(object({
12139
12240
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12140
12241
  kind: "mutation",
12141
12242
  auth: "admin"
12142
- }), method(object({ deviceId: number() }), object({
12143
- deviceId: number(),
12144
- entries: array(object({
12145
- capName: string(),
12146
- kind: _enum(["native", "wrapped"]),
12147
- providerAddonId: string(),
12148
- providerNodeId: string(),
12149
- nativeAddonId: string()
12150
- }))
12151
- })), method(object({}), array(object({
12152
- deviceId: number(),
12153
- entries: array(object({
12154
- capName: string(),
12155
- kind: _enum(["native", "wrapped"]),
12156
- providerAddonId: string(),
12157
- providerNodeId: string(),
12158
- nativeAddonId: string()
12159
- }))
12160
- }))), method(object({
12243
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12161
12244
  deviceId: number(),
12162
12245
  capName: string(),
12163
12246
  wrapperAddonId: string(),
@@ -12328,7 +12411,7 @@ method(object({
12328
12411
  crop: _instanceof(Uint8Array),
12329
12412
  width: number(),
12330
12413
  height: number()
12331
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12414
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12332
12415
  /**
12333
12416
  * filesystem-browse — per-node capability for browsing the node's local
12334
12417
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12621,19 +12704,22 @@ method(LlmGenerateBaseInputSchema.extend({
12621
12704
  runtime: ManagedRuntimeConfigSchema,
12622
12705
  /** The managed profile's timeout, threaded by the hub provider. */
12623
12706
  timeoutMs: number().int().positive().optional()
12624
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12707
+ }), LlmGenerateResultSchema, {
12708
+ kind: "mutation",
12709
+ auth: "admin"
12710
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12625
12711
  kind: "mutation",
12626
12712
  auth: "admin"
12627
12713
  }), method(object({}), _void(), {
12628
12714
  kind: "mutation",
12629
12715
  auth: "admin"
12630
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12716
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12631
12717
  kind: "mutation",
12632
12718
  auth: "admin"
12633
12719
  }), method(object({ file: string() }), _void(), {
12634
12720
  kind: "mutation",
12635
12721
  auth: "admin"
12636
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12722
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12637
12723
  /**
12638
12724
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12639
12725
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14543,12 +14629,15 @@ var NcOccupancyConditionSchema = object({
14543
14629
  * there is no second switch that can disagree with the first and every rule
14544
14630
  * authored before the decision migrates for free (`audioModeOf`):
14545
14631
  *
14546
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14547
- * classifier labels with one of them. No window, no percentage:
14548
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14549
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14550
- * the analyzer's (`classificationMinScore`, per device) — a label only
14551
- * reaches this condition if the classifier was already confident enough.
14632
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14633
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14634
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14635
+ * frames is the wrong question for a classifier that labels 1–3 frames
14636
+ * per episode. The count window is the brake that drops a single-frame
14637
+ * false positive; the rule's own `throttle` cooldown is the other. The
14638
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14639
+ * per device) — a label only reaches this condition if the classifier was
14640
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14552
14641
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14553
14642
  * the condition: at least `hitPercent`% of the samples over
14554
14643
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14575,14 +14664,22 @@ var NcOccupancyConditionSchema = object({
14575
14664
  * an operator who typed `dog` mean the same thing.
14576
14665
  */
14577
14666
  var NcAudioConditionSchema = object({
14578
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14667
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14579
14668
  labels: array(string().min(1)).min(1).optional(),
14580
14669
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14581
14670
  dbThreshold: number().min(-96).max(0).optional(),
14582
14671
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14583
14672
  hitPercent: number().int().min(1).max(100).default(60),
14584
14673
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14585
- samplingSeconds: number().int().min(1).max(300).default(10)
14674
+ samplingSeconds: number().int().min(1).max(300).default(10),
14675
+ /**
14676
+ * LABEL MODE: how many labelled frames must land inside
14677
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14678
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14679
+ */
14680
+ confirmHits: number().int().min(1).max(20).optional(),
14681
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14682
+ confirmWindowSec: number().int().min(1).max(60).optional()
14586
14683
  });
14587
14684
  /**
14588
14685
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16109,7 +16206,7 @@ var OauthIntegrationDescriptorSchema = object({
16109
16206
  */
16110
16207
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16111
16208
  });
16112
- method(_void(), OauthIntegrationDescriptorSchema);
16209
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16113
16210
  /**
16114
16211
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16115
16212
  * per-frame detections emitted by the pipeline runner into tracked
@@ -16956,6 +17053,46 @@ var RecentTracksPageSchema = object({
16956
17053
  /** Cursor for the next page, or null when this page is the last. */
16957
17054
  nextCursor: string().nullable()
16958
17055
  });
17056
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17057
+ var LIST_GROUPS_MAX_LIMIT = 100;
17058
+ var AnalyticsGroupRecordSchema = object({
17059
+ id: string(),
17060
+ deviceId: number().int(),
17061
+ openedAt: number().int(),
17062
+ closedAt: number().int(),
17063
+ timestamp: number().int(),
17064
+ memberCount: number().int(),
17065
+ memberTrackIds: array(string()).readonly(),
17066
+ className: string(),
17067
+ classes: array(string()).readonly(),
17068
+ /** Relative event-media path, or null when the group has no picture yet. */
17069
+ mediaUrl: string().nullable(),
17070
+ singleton: boolean()
17071
+ });
17072
+ var AnalyticsGroupMemberSchema = object({
17073
+ trackId: string(),
17074
+ deviceId: number().int(),
17075
+ className: string(),
17076
+ firstSeen: number().int(),
17077
+ lastSeen: number().int(),
17078
+ mediaUrl: string().nullable()
17079
+ });
17080
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17081
+ var ListGroupsQueryInput = object({
17082
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17083
+ deviceIds: array(number()),
17084
+ /** Window lower bound on `closedAt` (inclusive). */
17085
+ since: number().optional(),
17086
+ /** Window upper bound on `openedAt` (inclusive). */
17087
+ until: number().optional(),
17088
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17089
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17090
+ cursor: string().optional()
17091
+ });
17092
+ var ListGroupsPageSchema = object({
17093
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17094
+ nextCursor: string().nullable()
17095
+ });
16959
17096
  var KeyEventQueryInput = object({
16960
17097
  deviceId: number(),
16961
17098
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17031,7 +17168,9 @@ var TrackCascadeCountsSchema = object({
17031
17168
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17032
17169
  plates: number().int(),
17033
17170
  /** Per-track CLIP search vectors removed (best-effort). */
17034
- embeddings: number().int()
17171
+ embeddings: number().int(),
17172
+ /** Group membership + group rows removed with their last member (best-effort). */
17173
+ groups: number().int()
17035
17174
  });
17036
17175
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17037
17176
  var DiskReconcileCountsSchema = object({
@@ -17177,7 +17316,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17177
17316
  * stationary registry). Default false: the timeline lists passages,
17178
17317
  * not parking records (operator decision, 2026-08-15). */
17179
17318
  includeStationary: boolean().optional()
17180
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17319
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17320
+ deviceId: number(),
17321
+ groupId: string().min(1)
17322
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17181
17323
  kind: "mutation",
17182
17324
  auth: "admin"
17183
17325
  }), 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({
@@ -17259,6 +17401,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17259
17401
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17260
17402
  kind: "mutation",
17261
17403
  auth: "admin"
17404
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17405
+ kind: "mutation",
17406
+ auth: "admin"
17407
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17408
+ kind: "query",
17409
+ auth: "admin"
17410
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17411
+ kind: "mutation",
17412
+ auth: "admin"
17262
17413
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17263
17414
  kind: "query",
17264
17415
  auth: "admin"
@@ -17413,6 +17564,11 @@ object({
17413
17564
  "jpeg"
17414
17565
  ])
17415
17566
  });
17567
+ /**
17568
+ * Process-local frame identity. It is serializable so it can ride an in-process
17569
+ * capability call, but `registryId` deliberately prevents resolution in any
17570
+ * other process or execution group.
17571
+ */
17416
17572
  var FrameRefSchema = object({
17417
17573
  registryId: string().min(1),
17418
17574
  id: string().min(1),
@@ -17487,7 +17643,8 @@ var PipelineModelOptionSchema = object({
17487
17643
  sizeMB: number()
17488
17644
  })),
17489
17645
  group: ModelVariantGroupSchema.optional(),
17490
- legacy: boolean().optional()
17646
+ legacy: boolean().optional(),
17647
+ provider: ModelProviderIdSchema.optional()
17491
17648
  });
17492
17649
  var ConfigFieldBridge = custom();
17493
17650
  var PipelineAddonSchemaSchema = object({
@@ -19577,7 +19734,7 @@ method(object({
19577
19734
  * linking rather than produce an eternal token.
19578
19735
  */
19579
19736
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19580
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19737
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19581
19738
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19582
19739
  providerId: string().min(1),
19583
19740
  displayName: string().min(1),
@@ -19672,10 +19829,13 @@ var EvictResultSchema = object({
19672
19829
  /** True when the provider has nothing left it is willing to drop on this location. */
19673
19830
  exhausted: boolean()
19674
19831
  });
19675
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19832
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19676
19833
  locationId: string(),
19677
19834
  targetBytes: number().int().positive()
19678
- }), EvictResultSchema, { kind: "mutation" });
19835
+ }), EvictResultSchema, {
19836
+ kind: "mutation",
19837
+ auth: "admin"
19838
+ });
19679
19839
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19680
19840
  kind: "mutation",
19681
19841
  auth: "admin"
@@ -19735,26 +19895,50 @@ var ReadChunkInputSchema = object({
19735
19895
  length: number()
19736
19896
  });
19737
19897
  var EndDownloadInputSchema = object({ downloadId: string() });
19738
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19898
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19739
19899
  location: StorageLocationSchema,
19740
19900
  relativePath: string()
19741
- }), string()), method(object({
19901
+ }), string(), { auth: "admin" }), method(object({
19742
19902
  location: StorageLocationSchema,
19743
19903
  relativePath: string(),
19744
19904
  data: _instanceof(Uint8Array)
19745
- }), _void(), { kind: "mutation" }), method(object({
19905
+ }), _void(), {
19906
+ kind: "mutation",
19907
+ auth: "admin"
19908
+ }), method(object({
19746
19909
  location: StorageLocationSchema,
19747
19910
  relativePath: string()
19748
- }), _instanceof(Uint8Array)), method(object({
19911
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19749
19912
  location: StorageLocationSchema,
19750
19913
  relativePath: string()
19751
- }), boolean()), method(object({
19914
+ }), boolean(), { auth: "admin" }), method(object({
19752
19915
  location: StorageLocationSchema,
19753
19916
  prefix: string().optional()
19754
- }), array(string()).readonly()), method(object({
19917
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19755
19918
  location: StorageLocationSchema,
19756
19919
  relativePath: string()
19757
- }), _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" });
19920
+ }), _void(), {
19921
+ kind: "mutation",
19922
+ auth: "admin"
19923
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
19924
+ kind: "mutation",
19925
+ auth: "admin"
19926
+ }), method(WriteChunkInputSchema, _void(), {
19927
+ kind: "mutation",
19928
+ auth: "admin"
19929
+ }), method(FinalizeUploadInputSchema, _void(), {
19930
+ kind: "mutation",
19931
+ auth: "admin"
19932
+ }), method(AbortUploadInputSchema, _void(), {
19933
+ kind: "mutation",
19934
+ auth: "admin"
19935
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
19936
+ kind: "mutation",
19937
+ auth: "admin"
19938
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
19939
+ kind: "mutation",
19940
+ auth: "admin"
19941
+ });
19758
19942
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19759
19943
  var ProfileSettingsSchemaBridge = unknown().nullable();
19760
19944
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -20012,7 +20196,8 @@ method(object({
20012
20196
  access: "create"
20013
20197
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
20014
20198
  kind: "mutation",
20015
- access: "view"
20199
+ access: "view",
20200
+ auth: "admin"
20016
20201
  }), method(object({
20017
20202
  /** Required — the user the assertion belongs to (verified). */
20018
20203
  userId: string(),
@@ -20020,10 +20205,12 @@ method(object({
20020
20205
  response: record(string(), unknown())
20021
20206
  }), object({ verified: boolean() }), {
20022
20207
  kind: "mutation",
20023
- access: "view"
20208
+ access: "view",
20209
+ auth: "admin"
20024
20210
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
20025
20211
  kind: "mutation",
20026
- access: "view"
20212
+ access: "view",
20213
+ auth: "admin"
20027
20214
  }), method(object({
20028
20215
  /** AuthenticationResponseJSON from the browser. */
20029
20216
  response: record(string(), unknown()) }), object({
@@ -20031,7 +20218,8 @@ response: record(string(), unknown()) }), object({
20031
20218
  userId: string().nullable()
20032
20219
  }), {
20033
20220
  kind: "mutation",
20034
- access: "view"
20221
+ access: "view",
20222
+ auth: "admin"
20035
20223
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
20036
20224
  userId: string(),
20037
20225
  credentialId: string()
@@ -20203,7 +20391,19 @@ var VectorStatsResultSchema = object({
20203
20391
  /** False when the backend ranks approximately. */
20204
20392
  exact: boolean()
20205
20393
  });
20206
- 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);
20394
+ method(VectorDeclareIndexInputSchema, _void(), {
20395
+ kind: "mutation",
20396
+ auth: "admin"
20397
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20398
+ kind: "mutation",
20399
+ auth: "admin"
20400
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20401
+ kind: "mutation",
20402
+ auth: "admin"
20403
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20404
+ kind: "mutation",
20405
+ auth: "admin"
20406
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20207
20407
  var ClipSchema = object({
20208
20408
  /** Opaque, provider-namespaced id. The default provider encodes the time
20209
20409
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21926,7 +22126,27 @@ var MediaFileLiteSchema$1 = object({
21926
22126
  sizeBytes: number(),
21927
22127
  timestamp: number()
21928
22128
  });
21929
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22129
+ method(object({
22130
+ /**
22131
+ * Inline {@link IdentitySchema.coverBase64} on every row.
22132
+ *
22133
+ * Default `false`, the same inversion `listRecentFaces` and
22134
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
22135
+ * why the burden belongs on the caller that WANTS the bytes). Measured
22136
+ * on the live hub the same day: four identities cost 40,979 B with the
22137
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
22138
+ * four times and the viewer holds at `staleTime: 30_000`.
22139
+ *
22140
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
22141
+ * the `event-media` plane serves that key `immutable` with an ETag.
22142
+ *
22143
+ * **This is an INPUT field, so it does not reach the addon until the
22144
+ * next train** — the hub router validates cap inputs against its own
22145
+ * compiled Zod and strips a key it does not know. Until then the
22146
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
22147
+ * is what ships, and the opt-in becomes reachable when the train lands.
22148
+ */
22149
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
21930
22150
  kind: "mutation",
21931
22151
  auth: "admin"
21932
22152
  }), method(object({
@@ -24071,7 +24291,14 @@ var PlateInfoSchema = object({
24071
24291
  plateBbox: BoundingBoxSchema.optional(),
24072
24292
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
24073
24293
  keyFrameMediaKey: string().optional(),
24074
- base64: string().optional()
24294
+ base64: string().optional(),
24295
+ /**
24296
+ * Same crop as a data-plane URL, always present when the plate has a stored
24297
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24298
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24299
+ * left at its `true` default.
24300
+ */
24301
+ cropUrl: string().optional()
24075
24302
  });
24076
24303
  var MediaFileLiteSchema = object({
24077
24304
  key: string(),
@@ -24089,14 +24316,34 @@ var PlateClusterSchema = object({
24089
24316
  });
24090
24317
  method(object({
24091
24318
  deviceId: number().int().optional(),
24092
- limit: number().int().positive().optional()
24319
+ limit: number().int().positive().optional(),
24320
+ /**
24321
+ * Inline the base64 crop on every row. Default `true` — the existing
24322
+ * behaviour, kept so no caller breaks.
24323
+ *
24324
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24325
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24326
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24327
+ * metadata without them — and the browser then caches the images.
24328
+ *
24329
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24330
+ * plates were the one gallery list left without it.
24331
+ *
24332
+ * **This is an INPUT field, so it does not reach the addon until the
24333
+ * next train.** The hub router validates cap inputs against its own
24334
+ * compiled Zod and strips a key it does not know. Until the train
24335
+ * ships, sending `false` is harmless and keeps the crops inline.
24336
+ */
24337
+ includeCrops: boolean().optional()
24093
24338
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
24094
24339
  deviceId: number().int(),
24095
24340
  trackId: string()
24096
24341
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
24097
24342
  text: string().min(1),
24098
24343
  maxDistance: number().int().min(0).optional(),
24099
- limit: number().int().positive().optional()
24344
+ limit: number().int().positive().optional(),
24345
+ /** See `listPlates.includeCrops`. Default `true`. */
24346
+ includeCrops: boolean().optional()
24100
24347
  }), array(PlateInfoSchema).readonly()), method(object({
24101
24348
  maxDistance: number().int().min(0).optional(),
24102
24349
  minClusterSize: number().int().min(2).optional(),
@@ -24110,7 +24357,13 @@ method(object({
24110
24357
  }), method(object({ plateId: string() }), _void(), {
24111
24358
  kind: "mutation",
24112
24359
  auth: "admin"
24113
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24360
+ }), method(object({
24361
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
24362
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
24363
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
24364
+ * INPUT field: stripped by the hub router until the train ships, which
24365
+ * resolves to `false` and is exactly the intended default. */
24366
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24114
24367
  kind: "mutation",
24115
24368
  auth: "admin"
24116
24369
  }), method(object({
@@ -27711,6 +27964,12 @@ Object.freeze({
27711
27964
  addonId: null,
27712
27965
  access: "view"
27713
27966
  },
27967
+ "deviceManager.getBindingsBatch": {
27968
+ capName: "device-manager",
27969
+ capScope: "system",
27970
+ addonId: null,
27971
+ access: "view"
27972
+ },
27714
27973
  "deviceManager.getChildren": {
27715
27974
  capName: "device-manager",
27716
27975
  capScope: "system",
@@ -27771,6 +28030,12 @@ Object.freeze({
27771
28030
  addonId: null,
27772
28031
  access: "view"
27773
28032
  },
28033
+ "deviceManager.getLinkedDevicesBatch": {
28034
+ capName: "device-manager",
28035
+ capScope: "system",
28036
+ addonId: null,
28037
+ access: "view"
28038
+ },
27774
28039
  "deviceManager.getRoleDisplayDefaults": {
27775
28040
  capName: "device-manager",
27776
28041
  capScope: "system",
@@ -29475,6 +29740,12 @@ Object.freeze({
29475
29740
  addonId: null,
29476
29741
  access: "create"
29477
29742
  },
29743
+ "pipelineAnalytics.cancelRelocateMedia": {
29744
+ capName: "pipeline-analytics",
29745
+ capScope: "device",
29746
+ addonId: null,
29747
+ access: "create"
29748
+ },
29478
29749
  "pipelineAnalytics.cancelStorageMigrationMove": {
29479
29750
  capName: "pipeline-analytics",
29480
29751
  capScope: "device",
@@ -29541,6 +29812,12 @@ Object.freeze({
29541
29812
  addonId: null,
29542
29813
  access: "view"
29543
29814
  },
29815
+ "pipelineAnalytics.getGroup": {
29816
+ capName: "pipeline-analytics",
29817
+ capScope: "device",
29818
+ addonId: null,
29819
+ access: "view"
29820
+ },
29544
29821
  "pipelineAnalytics.getKeyEvents": {
29545
29822
  capName: "pipeline-analytics",
29546
29823
  capScope: "device",
@@ -29625,6 +29902,12 @@ Object.freeze({
29625
29902
  addonId: null,
29626
29903
  access: "view"
29627
29904
  },
29905
+ "pipelineAnalytics.listGroups": {
29906
+ capName: "pipeline-analytics",
29907
+ capScope: "device",
29908
+ addonId: null,
29909
+ access: "view"
29910
+ },
29628
29911
  "pipelineAnalytics.listOpsLog": {
29629
29912
  capName: "pipeline-analytics",
29630
29913
  capScope: "device",
@@ -29637,6 +29920,12 @@ Object.freeze({
29637
29920
  addonId: null,
29638
29921
  access: "view"
29639
29922
  },
29923
+ "pipelineAnalytics.listRelocateMediaJobs": {
29924
+ capName: "pipeline-analytics",
29925
+ capScope: "device",
29926
+ addonId: null,
29927
+ access: "view"
29928
+ },
29640
29929
  "pipelineAnalytics.listRetrainAnnotations": {
29641
29930
  capName: "pipeline-analytics",
29642
29931
  capScope: "device",
@@ -29715,6 +30004,12 @@ Object.freeze({
29715
30004
  addonId: null,
29716
30005
  access: "create"
29717
30006
  },
30007
+ "pipelineAnalytics.relocateMedia": {
30008
+ capName: "pipeline-analytics",
30009
+ capScope: "device",
30010
+ addonId: null,
30011
+ access: "create"
30012
+ },
29718
30013
  "pipelineAnalytics.restageRetrainTrack": {
29719
30014
  capName: "pipeline-analytics",
29720
30015
  capScope: "device",
@@ -32406,6 +32701,11 @@ Object.freeze({
32406
32701
  form: "single",
32407
32702
  optional: false
32408
32703
  }],
32704
+ "deviceManager.getBindingsBatch": [{
32705
+ name: "deviceIds",
32706
+ form: "array",
32707
+ optional: false
32708
+ }],
32409
32709
  "deviceManager.getChildren": [{
32410
32710
  name: "parentDeviceId",
32411
32711
  form: "single",
@@ -32451,6 +32751,11 @@ Object.freeze({
32451
32751
  form: "single",
32452
32752
  optional: false
32453
32753
  }],
32754
+ "deviceManager.getLinkedDevicesBatch": [{
32755
+ name: "deviceIds",
32756
+ form: "array",
32757
+ optional: false
32758
+ }],
32454
32759
  "deviceManager.getSettingsSchema": [{
32455
32760
  name: "deviceId",
32456
32761
  form: "single",
@@ -32471,6 +32776,11 @@ Object.freeze({
32471
32776
  form: "single",
32472
32777
  optional: false
32473
32778
  }],
32779
+ "deviceManager.listAll": [{
32780
+ name: "deviceIds",
32781
+ form: "array",
32782
+ optional: true
32783
+ }],
32474
32784
  "deviceManager.loadConfig": [{
32475
32785
  name: "deviceId",
32476
32786
  form: "single",
@@ -33044,6 +33354,11 @@ Object.freeze({
33044
33354
  form: "single",
33045
33355
  optional: false
33046
33356
  }],
33357
+ "pipelineAnalytics.getGroup": [{
33358
+ name: "deviceId",
33359
+ form: "single",
33360
+ optional: false
33361
+ }],
33047
33362
  "pipelineAnalytics.getKeyEvents": [{
33048
33363
  name: "deviceId",
33049
33364
  form: "single",
@@ -33099,6 +33414,11 @@ Object.freeze({
33099
33414
  form: "array",
33100
33415
  optional: false
33101
33416
  }],
33417
+ "pipelineAnalytics.listGroups": [{
33418
+ name: "deviceIds",
33419
+ form: "array",
33420
+ optional: false
33421
+ }],
33102
33422
  "pipelineAnalytics.listOpsLog": [{
33103
33423
  name: "deviceId",
33104
33424
  form: "single",