@camstack/addon-provider-petkit 0.2.27 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +431 -111
  2. package/dist/addon.mjs +431 -111
  3. package/package.json +1 -1
package/dist/addon.mjs CHANGED
@@ -6902,6 +6902,13 @@ var BaseAddon = class {
6902
6902
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
6903
6903
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
6904
6904
  _registeredCapNames = [];
6905
+ /**
6906
+ * True only after `readAddonStore` actually answered. Constructor
6907
+ * defaults look like stored config when the store is down — a forked
6908
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
6909
+ * mode, 2026-08-25) is not "the operator chose this".
6910
+ */
6911
+ settingsStoreReady = false;
6905
6912
  /** Default config values. Provided via constructor. */
6906
6913
  defaults;
6907
6914
  constructor(defaults) {
@@ -7302,7 +7309,9 @@ var BaseAddon = class {
7302
7309
  ];
7303
7310
  let lastErr;
7304
7311
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
7305
- return await settings.readAddonStore() ?? {};
7312
+ const stored = await settings.readAddonStore() ?? {};
7313
+ this.settingsStoreReady = true;
7314
+ return stored;
7306
7315
  } catch (err) {
7307
7316
  lastErr = err;
7308
7317
  const msg = err instanceof Error ? err.message : String(err);
@@ -7310,6 +7319,7 @@ var BaseAddon = class {
7310
7319
  if (attempt === delaysMs.length) break;
7311
7320
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
7312
7321
  }
7322
+ this.settingsStoreReady = false;
7313
7323
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
7314
7324
  return {};
7315
7325
  }
@@ -7721,7 +7731,7 @@ function method(input, output, options) {
7721
7731
  input,
7722
7732
  output,
7723
7733
  kind: options?.kind ?? "query",
7724
- auth: options?.auth ?? "protected",
7734
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
7725
7735
  ...options?.access !== void 0 ? { access: options.access } : {},
7726
7736
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
7727
7737
  timeoutMs: options?.timeoutMs
@@ -7745,7 +7755,7 @@ function event(data) {
7745
7755
  }
7746
7756
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
7747
7757
  var VersionOutputSchema$1 = object({ version: string() });
7748
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
7758
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
7749
7759
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
7750
7760
  DeviceType["Camera"] = "camera";
7751
7761
  DeviceType["Hub"] = "hub";
@@ -8066,7 +8076,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
8066
8076
  }({});
8067
8077
  var StaticDirOutputSchema = object({ staticDir: string() });
8068
8078
  var VersionOutputSchema = object({ version: string() });
8069
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
8079
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
8070
8080
  /**
8071
8081
  * device-ops — device-scoped cap that unifies the per-IDevice operations
8072
8082
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -8692,24 +8702,6 @@ var RecordingRetentionSchema = object({
8692
8702
  maxSizeGb: number().min(0).optional()
8693
8703
  });
8694
8704
  /**
8695
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
8696
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
8697
- * previews at. Five graduated steps; absent on a config = `standard` (the
8698
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
8699
- *
8700
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
8701
- * Each window's index sidecar carries its own tile dims, so a camera whose
8702
- * preset changed over time renders every historical window at the dims it was
8703
- * written with.
8704
- */
8705
- var ScrubThumbnailPresetSchema = _enum([
8706
- "minimal",
8707
- "low",
8708
- "standard",
8709
- "high",
8710
- "max"
8711
- ]);
8712
- /**
8713
8705
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
8714
8706
  *
8715
8707
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -8717,7 +8709,11 @@ var ScrubThumbnailPresetSchema = _enum([
8717
8709
  * other field is a storage knob (profiles, segment length, retention, scrub).
8718
8710
  *
8719
8711
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
8720
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
8712
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
8713
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
8714
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
8715
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
8716
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
8721
8717
  * A stale caller must fail loudly — silently stripping its legacy intent would
8722
8718
  * persist a band-less config, i.e. silently stop recording the camera.
8723
8719
  */
@@ -8740,14 +8736,7 @@ var RecordingConfigSchema = object({
8740
8736
  * "off" is the absence of a covering band, never a band value.
8741
8737
  */
8742
8738
  bands: array(RecordingBandSchema).default([]),
8743
- retention: RecordingRetentionSchema.optional(),
8744
- /**
8745
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
8746
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
8747
- * windows only — existing sheets are immutable, and each window's index
8748
- * carries its own tile dims so mixed-preset history renders correctly.
8749
- */
8750
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
8739
+ retention: RecordingRetentionSchema.optional()
8751
8740
  }).strict();
8752
8741
  /**
8753
8742
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -8823,10 +8812,11 @@ var RelocateFootageInputSchema = object({
8823
8812
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8824
8813
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8825
8814
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8826
- var StorageMigrationMediaMoveInputSchema = object({
8815
+ var RelocateMediaInputSchema = object({
8827
8816
  toLocationId: string(),
8828
8817
  throttleMbps: number().min(1).max(1e3).optional()
8829
- }).extend({ leaseId: string().min(1) });
8818
+ });
8819
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8830
8820
  /** The independently selectable logical storage classes. `recordings`
8831
8821
  * encompasses the high and mid segment profiles; `recordingsLow` is low
8832
8822
  * segments; `eventMedia` is post-analysis blobs. */
@@ -9121,7 +9111,26 @@ var LabelDefinitionSchema = object({
9121
9111
  description: string().optional(),
9122
9112
  icon: string().optional()
9123
9113
  });
9124
- var ClassMapDefinitionSchema = object({
9114
+ /**
9115
+ * Wire schema for a per-model CATALOG classMap override
9116
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
9117
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
9118
+ * detection pipeline executor actually routes.
9119
+ *
9120
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
9121
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
9122
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
9123
+ * enum) — the two used to share the name `ClassMapDefinition`/
9124
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
9125
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
9126
+ * are not: it is two different concepts colliding on a name. Keep this type
9127
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
9128
+ * would either narrow every `ClassMapDefinition` consumer to the four
9129
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
9130
+ * schema exists for (see the "rejects a classMap whose target is not a
9131
+ * detection macro" test in `model-catalog-schema.test.ts`).
9132
+ */
9133
+ var DetectionCatalogClassMapSchema = object({
9125
9134
  mapping: record(string(), _enum([
9126
9135
  "person",
9127
9136
  "vehicle",
@@ -9213,6 +9222,12 @@ var ModelVariantGroupSchema = object({
9213
9222
  */
9214
9223
  resolution: number().int().positive().optional()
9215
9224
  });
9225
+ var ModelProviderIdSchema = _enum([
9226
+ "camstack",
9227
+ "frigate",
9228
+ "scrypted",
9229
+ "custom"
9230
+ ]);
9216
9231
  var ModelCatalogEntrySchema = object({
9217
9232
  id: string(),
9218
9233
  name: string(),
@@ -9310,11 +9325,17 @@ var ModelCatalogEntrySchema = object({
9310
9325
  */
9311
9326
  group: ModelVariantGroupSchema.optional(),
9312
9327
  /**
9328
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
9329
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
9330
+ * persisted before this field existed (`inferModelProvider` fills those).
9331
+ */
9332
+ provider: ModelProviderIdSchema.optional(),
9333
+ /**
9313
9334
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
9314
9335
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
9315
9336
  * labels already ARE the CamStack macros (Scrypted identity map).
9316
9337
  */
9317
- classMap: ClassMapDefinitionSchema.optional()
9338
+ classMap: DetectionCatalogClassMapSchema.optional()
9318
9339
  });
9319
9340
  var ConvertTargetSchema = discriminatedUnion("format", [object({
9320
9341
  format: literal("openvino"),
@@ -9344,7 +9365,7 @@ var ModelConvertMetadataSchema = object({
9344
9365
  "segmentation"
9345
9366
  ]),
9346
9367
  faceAlignment: boolean().optional(),
9347
- classMap: ClassMapDefinitionSchema.optional()
9368
+ classMap: DetectionCatalogClassMapSchema.optional()
9348
9369
  });
9349
9370
  var ConvertResultSchema = object({
9350
9371
  entry: ModelCatalogEntrySchema,
@@ -10207,7 +10228,7 @@ var AddonPageDeclarationSchema = object({
10207
10228
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
10208
10229
  sectionLabel: string().optional()
10209
10230
  });
10210
- method(_void(), array(AddonPageDeclarationSchema).readonly());
10231
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
10211
10232
  var AddonHttpRouteSchema = object({
10212
10233
  method: _enum([
10213
10234
  "GET",
@@ -10442,7 +10463,7 @@ var WidgetMetadataSchema = object({
10442
10463
  defaultColumns: number().int().min(1).max(12).default(6),
10443
10464
  defaultRows: number().int().min(1).max(12).default(1)
10444
10465
  });
10445
- method(_void(), array(WidgetMetadataSchema).readonly());
10466
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
10446
10467
  /**
10447
10468
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
10448
10469
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -12066,7 +12087,7 @@ var CustomModelDescriptorSchema = object({
12066
12087
  stepId: string(),
12067
12088
  entry: ModelCatalogEntrySchema
12068
12089
  });
12069
- method(_void(), array(CustomModelDescriptorSchema).readonly());
12090
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
12070
12091
  /**
12071
12092
  * Query filter for settings-store collections.
12072
12093
  */
@@ -12153,7 +12174,8 @@ method(object({
12153
12174
  }), _void(), { kind: "mutation" }), method(object({
12154
12175
  namespace: string().optional(),
12155
12176
  collection: string(),
12156
- filter: QueryFilterSchema.optional()
12177
+ filter: QueryFilterSchema.optional(),
12178
+ columns: array(string()).readonly().optional()
12157
12179
  }), array(SettingsRecordSchema).readonly()), method(object({
12158
12180
  namespace: string().optional(),
12159
12181
  collection: string(),
@@ -12216,46 +12238,87 @@ var EngineInfoSchema = object({
12216
12238
  kind: _enum(["relational", "vector"]),
12217
12239
  displayName: string()
12218
12240
  });
12219
- method(_void(), EngineInfoSchema), method(object({
12241
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12220
12242
  namespace: string().optional(),
12221
12243
  collection: string(),
12222
12244
  key: string()
12223
- }), unknown()), method(object({
12245
+ }), unknown(), { auth: "admin" }), method(object({
12224
12246
  namespace: string().optional(),
12225
12247
  collection: string(),
12226
12248
  key: string(),
12227
12249
  value: unknown()
12228
- }), _void(), { kind: "mutation" }), method(object({
12250
+ }), _void(), {
12251
+ kind: "mutation",
12252
+ auth: "admin"
12253
+ }), method(object({
12229
12254
  namespace: string().optional(),
12230
12255
  collection: string(),
12231
- filter: QueryFilterSchema.optional()
12232
- }), array(SettingsRecordSchema).readonly()), method(object({
12256
+ filter: QueryFilterSchema.optional(),
12257
+ /**
12258
+ * SQL-level column projection — MUST mirror `settings-store.query`.
12259
+ *
12260
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
12261
+ * was wrong — corrected 2026-08-26 after the hop map
12262
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
12263
+ * There is **no Zod parse at all** between the door and the engine: the
12264
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
12265
+ * field declared here reaches `SqliteSettingsBackend` either way.
12266
+ *
12267
+ * What actually lost `columns` was the THIRD declaration of this shape:
12268
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
12269
+ * interface the engine destructures from. The field existed on both
12270
+ * schemas and the engine still never read it, because nothing checks a
12271
+ * registered provider against `InferProvider<cap>` —
12272
+ * `ProviderRegistration.provider` is typed `object`.
12273
+ *
12274
+ * It is declared here anyway, and must stay in step with
12275
+ * `settings-store.query`: a caller reading only the cap definitions has
12276
+ * to be able to see that this call carries a projection.
12277
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
12278
+ */
12279
+ columns: array(string()).readonly().optional()
12280
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
12233
12281
  namespace: string().optional(),
12234
12282
  collection: string(),
12235
12283
  record: SettingsRecordSchema
12236
- }), _void(), { kind: "mutation" }), method(object({
12284
+ }), _void(), {
12285
+ kind: "mutation",
12286
+ auth: "admin"
12287
+ }), method(object({
12237
12288
  namespace: string().optional(),
12238
12289
  collection: string(),
12239
12290
  id: string(),
12240
12291
  data: record(string(), unknown())
12241
- }), _void(), { kind: "mutation" }), method(object({
12292
+ }), _void(), {
12293
+ kind: "mutation",
12294
+ auth: "admin"
12295
+ }), method(object({
12242
12296
  namespace: string().optional(),
12243
12297
  collection: string(),
12244
12298
  key: string()
12245
- }), _void(), { kind: "mutation" }), method(object({
12299
+ }), _void(), {
12300
+ kind: "mutation",
12301
+ auth: "admin"
12302
+ }), method(object({
12246
12303
  namespace: string().optional(),
12247
12304
  collection: string(),
12248
12305
  filter: MutationFilterSchema
12249
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
12306
+ }), object({ deleted: number().int() }), {
12307
+ kind: "mutation",
12308
+ auth: "admin"
12309
+ }), method(object({
12250
12310
  namespace: string().optional(),
12251
12311
  collection: string(),
12252
12312
  filter: MutationFilterSchema,
12253
12313
  data: record(string(), unknown())
12254
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
12314
+ }), object({ updated: number().int() }), {
12315
+ kind: "mutation",
12316
+ auth: "admin"
12317
+ }), method(object({
12255
12318
  namespace: string().optional(),
12256
12319
  collection: string(),
12257
12320
  filter: QueryFilterSchema.optional()
12258
- }), number()), method(object({
12321
+ }), number(), { auth: "admin" }), method(object({
12259
12322
  namespace: string().optional(),
12260
12323
  collection: string(),
12261
12324
  field: string(),
@@ -12265,15 +12328,18 @@ method(_void(), EngineInfoSchema), method(object({
12265
12328
  }), array(object({
12266
12329
  bucket: number().int(),
12267
12330
  count: number().int()
12268
- })).readonly()), method(object({
12331
+ })).readonly(), { auth: "admin" }), method(object({
12269
12332
  namespace: string().optional(),
12270
12333
  collection: string()
12271
- }), boolean()), method(object({
12334
+ }), boolean(), { auth: "admin" }), method(object({
12272
12335
  namespace: string().optional(),
12273
12336
  collection: string(),
12274
12337
  columns: array(CollectionColumnSchema).readonly(),
12275
12338
  indexes: array(CollectionIndexSchema).readonly().optional()
12276
- }), _void(), { kind: "mutation" });
12339
+ }), _void(), {
12340
+ kind: "mutation",
12341
+ auth: "admin"
12342
+ });
12277
12343
  /**
12278
12344
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
12279
12345
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -13118,6 +13184,27 @@ var LinkedDeviceSchema = object({
13118
13184
  features: array(string()),
13119
13185
  producesTrackedEvents: boolean().optional()
13120
13186
  });
13187
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
13188
+ * The batch answer needs the tag; the single-device answer already has it
13189
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
13190
+ var LinkedDevicesForDeviceSchema = object({
13191
+ deviceId: number(),
13192
+ mode: LinkedDevicesModeSchema,
13193
+ devices: array(LinkedDeviceSchema)
13194
+ });
13195
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
13196
+ * `getAllBindings` all answer in. Declared once: three copies of the same
13197
+ * object literal is exactly how the three drift apart. */
13198
+ var DeviceBindingsForDeviceSchema = object({
13199
+ deviceId: number(),
13200
+ entries: array(object({
13201
+ capName: string(),
13202
+ kind: _enum(["native", "wrapped"]),
13203
+ providerAddonId: string(),
13204
+ providerNodeId: string(),
13205
+ nativeAddonId: string()
13206
+ }))
13207
+ });
13121
13208
  var SavedDeviceRowSchema = object({
13122
13209
  /** Numeric id reserved at allocateDeviceId time. */
13123
13210
  id: number(),
@@ -13343,11 +13430,25 @@ method(object({
13343
13430
  projection: _enum(["full", "slim"]).optional(),
13344
13431
  /** Return only camera devices. Filtering server-side instead of
13345
13432
  * shipping 293 rows to find 12. */
13346
- isCamera: boolean().optional()
13433
+ isCamera: boolean().optional(),
13434
+ /**
13435
+ * Return only these device ids. For the caller that already KNOWS the
13436
+ * handful it wants and needs a field the id-bearing answer does not
13437
+ * carry — the viewer's linked-devices panel joins `type` and `online`
13438
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
13439
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
13440
+ * refetches on the reconcile interval, on a phone.
13441
+ *
13442
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
13443
+ * keys rather than rejecting them (verified against the live hub
13444
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
13445
+ * it answers today and the caller filters as it already does.
13446
+ */
13447
+ deviceIds: array(number()).optional()
13347
13448
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
13348
13449
  mode: LinkedDevicesModeSchema,
13349
13450
  devices: array(LinkedDeviceSchema)
13350
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
13451
+ })), 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({
13351
13452
  deviceId: number(),
13352
13453
  values: record(string(), unknown())
13353
13454
  }), object({ success: literal(true) }), {
@@ -13374,25 +13475,7 @@ method(object({
13374
13475
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
13375
13476
  kind: "mutation",
13376
13477
  auth: "admin"
13377
- }), method(object({ deviceId: number() }), object({
13378
- deviceId: number(),
13379
- entries: array(object({
13380
- capName: string(),
13381
- kind: _enum(["native", "wrapped"]),
13382
- providerAddonId: string(),
13383
- providerNodeId: string(),
13384
- nativeAddonId: string()
13385
- }))
13386
- })), method(object({}), array(object({
13387
- deviceId: number(),
13388
- entries: array(object({
13389
- capName: string(),
13390
- kind: _enum(["native", "wrapped"]),
13391
- providerAddonId: string(),
13392
- providerNodeId: string(),
13393
- nativeAddonId: string()
13394
- }))
13395
- }))), method(object({
13478
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
13396
13479
  deviceId: number(),
13397
13480
  capName: string(),
13398
13481
  wrapperAddonId: string(),
@@ -13563,7 +13646,7 @@ method(object({
13563
13646
  crop: _instanceof(Uint8Array),
13564
13647
  width: number(),
13565
13648
  height: number()
13566
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
13649
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
13567
13650
  /**
13568
13651
  * filesystem-browse — per-node capability for browsing the node's local
13569
13652
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -13856,19 +13939,22 @@ method(LlmGenerateBaseInputSchema.extend({
13856
13939
  runtime: ManagedRuntimeConfigSchema,
13857
13940
  /** The managed profile's timeout, threaded by the hub provider. */
13858
13941
  timeoutMs: number().int().positive().optional()
13859
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
13942
+ }), LlmGenerateResultSchema, {
13943
+ kind: "mutation",
13944
+ auth: "admin"
13945
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
13860
13946
  kind: "mutation",
13861
13947
  auth: "admin"
13862
13948
  }), method(object({}), _void(), {
13863
13949
  kind: "mutation",
13864
13950
  auth: "admin"
13865
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
13951
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
13866
13952
  kind: "mutation",
13867
13953
  auth: "admin"
13868
13954
  }), method(object({ file: string() }), _void(), {
13869
13955
  kind: "mutation",
13870
13956
  auth: "admin"
13871
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
13957
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
13872
13958
  /**
13873
13959
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
13874
13960
  * methods concat-fan across providers; single-row methods route to ONE
@@ -15802,12 +15888,15 @@ var NcOccupancyConditionSchema = object({
15802
15888
  * there is no second switch that can disagree with the first and every rule
15803
15889
  * authored before the decision migrates for free (`audioModeOf`):
15804
15890
  *
15805
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
15806
- * classifier labels with one of them. No window, no percentage:
15807
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
15808
- * `throttle` cooldown is the only brake. The per-label confidence floor is
15809
- * the analyzer's (`classificationMinScore`, per device) a label only
15810
- * reaches this condition if the classifier was already confident enough.
15891
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
15892
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
15893
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
15894
+ * frames is the wrong question for a classifier that labels 1–3 frames
15895
+ * per episode. The count window is the brake that drops a single-frame
15896
+ * false positive; the rule's own `throttle` cooldown is the other. The
15897
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
15898
+ * per device) — a label only reaches this condition if the classifier was
15899
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
15811
15900
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
15812
15901
  * the condition: at least `hitPercent`% of the samples over
15813
15902
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -15834,14 +15923,22 @@ var NcOccupancyConditionSchema = object({
15834
15923
  * an operator who typed `dog` mean the same thing.
15835
15924
  */
15836
15925
  var NcAudioConditionSchema = object({
15837
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
15926
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
15838
15927
  labels: array(string().min(1)).min(1).optional(),
15839
15928
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
15840
15929
  dbThreshold: number().min(-96).max(0).optional(),
15841
15930
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
15842
15931
  hitPercent: number().int().min(1).max(100).default(60),
15843
15932
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
15844
- samplingSeconds: number().int().min(1).max(300).default(10)
15933
+ samplingSeconds: number().int().min(1).max(300).default(10),
15934
+ /**
15935
+ * LABEL MODE: how many labelled frames must land inside
15936
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
15937
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
15938
+ */
15939
+ confirmHits: number().int().min(1).max(20).optional(),
15940
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
15941
+ confirmWindowSec: number().int().min(1).max(60).optional()
15845
15942
  });
15846
15943
  /**
15847
15944
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -17368,7 +17465,7 @@ var OauthIntegrationDescriptorSchema = object({
17368
17465
  */
17369
17466
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
17370
17467
  });
17371
- method(_void(), OauthIntegrationDescriptorSchema);
17468
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
17372
17469
  /**
17373
17470
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
17374
17471
  * per-frame detections emitted by the pipeline runner into tracked
@@ -18215,6 +18312,46 @@ var RecentTracksPageSchema = object({
18215
18312
  /** Cursor for the next page, or null when this page is the last. */
18216
18313
  nextCursor: string().nullable()
18217
18314
  });
18315
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
18316
+ var LIST_GROUPS_MAX_LIMIT = 100;
18317
+ var AnalyticsGroupRecordSchema = object({
18318
+ id: string(),
18319
+ deviceId: number().int(),
18320
+ openedAt: number().int(),
18321
+ closedAt: number().int(),
18322
+ timestamp: number().int(),
18323
+ memberCount: number().int(),
18324
+ memberTrackIds: array(string()).readonly(),
18325
+ className: string(),
18326
+ classes: array(string()).readonly(),
18327
+ /** Relative event-media path, or null when the group has no picture yet. */
18328
+ mediaUrl: string().nullable(),
18329
+ singleton: boolean()
18330
+ });
18331
+ var AnalyticsGroupMemberSchema = object({
18332
+ trackId: string(),
18333
+ deviceId: number().int(),
18334
+ className: string(),
18335
+ firstSeen: number().int(),
18336
+ lastSeen: number().int(),
18337
+ mediaUrl: string().nullable()
18338
+ });
18339
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
18340
+ var ListGroupsQueryInput = object({
18341
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
18342
+ deviceIds: array(number()),
18343
+ /** Window lower bound on `closedAt` (inclusive). */
18344
+ since: number().optional(),
18345
+ /** Window upper bound on `openedAt` (inclusive). */
18346
+ until: number().optional(),
18347
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
18348
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
18349
+ cursor: string().optional()
18350
+ });
18351
+ var ListGroupsPageSchema = object({
18352
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
18353
+ nextCursor: string().nullable()
18354
+ });
18218
18355
  var KeyEventQueryInput = object({
18219
18356
  deviceId: number(),
18220
18357
  /** Window lower bound (track firstSeen ≥ since). */
@@ -18290,7 +18427,9 @@ var TrackCascadeCountsSchema = object({
18290
18427
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
18291
18428
  plates: number().int(),
18292
18429
  /** Per-track CLIP search vectors removed (best-effort). */
18293
- embeddings: number().int()
18430
+ embeddings: number().int(),
18431
+ /** Group membership + group rows removed with their last member (best-effort). */
18432
+ groups: number().int()
18294
18433
  });
18295
18434
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
18296
18435
  var DiskReconcileCountsSchema = object({
@@ -18436,7 +18575,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18436
18575
  * stationary registry). Default false: the timeline lists passages,
18437
18576
  * not parking records (operator decision, 2026-08-15). */
18438
18577
  includeStationary: boolean().optional()
18439
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
18578
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
18579
+ deviceId: number(),
18580
+ groupId: string().min(1)
18581
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
18440
18582
  kind: "mutation",
18441
18583
  auth: "admin"
18442
18584
  }), 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({
@@ -18518,6 +18660,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18518
18660
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
18519
18661
  kind: "mutation",
18520
18662
  auth: "admin"
18663
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18664
+ kind: "mutation",
18665
+ auth: "admin"
18666
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
18667
+ kind: "query",
18668
+ auth: "admin"
18669
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
18670
+ kind: "mutation",
18671
+ auth: "admin"
18521
18672
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
18522
18673
  kind: "query",
18523
18674
  auth: "admin"
@@ -18672,6 +18823,11 @@ object({
18672
18823
  "jpeg"
18673
18824
  ])
18674
18825
  });
18826
+ /**
18827
+ * Process-local frame identity. It is serializable so it can ride an in-process
18828
+ * capability call, but `registryId` deliberately prevents resolution in any
18829
+ * other process or execution group.
18830
+ */
18675
18831
  var FrameRefSchema = object({
18676
18832
  registryId: string().min(1),
18677
18833
  id: string().min(1),
@@ -18746,7 +18902,8 @@ var PipelineModelOptionSchema = object({
18746
18902
  sizeMB: number()
18747
18903
  })),
18748
18904
  group: ModelVariantGroupSchema.optional(),
18749
- legacy: boolean().optional()
18905
+ legacy: boolean().optional(),
18906
+ provider: ModelProviderIdSchema.optional()
18750
18907
  });
18751
18908
  var ConfigFieldBridge = custom();
18752
18909
  var PipelineAddonSchemaSchema = object({
@@ -20876,7 +21033,7 @@ method(object({
20876
21033
  * linking rather than produce an eternal token.
20877
21034
  */
20878
21035
  ttlSec: union([number().int().positive(), literal("never")]).optional()
20879
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
21036
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
20880
21037
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
20881
21038
  providerId: string().min(1),
20882
21039
  displayName: string().min(1),
@@ -20971,10 +21128,13 @@ var EvictResultSchema = object({
20971
21128
  /** True when the provider has nothing left it is willing to drop on this location. */
20972
21129
  exhausted: boolean()
20973
21130
  });
20974
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
21131
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
20975
21132
  locationId: string(),
20976
21133
  targetBytes: number().int().positive()
20977
- }), EvictResultSchema, { kind: "mutation" });
21134
+ }), EvictResultSchema, {
21135
+ kind: "mutation",
21136
+ auth: "admin"
21137
+ });
20978
21138
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
20979
21139
  kind: "mutation",
20980
21140
  auth: "admin"
@@ -21034,26 +21194,50 @@ var ReadChunkInputSchema = object({
21034
21194
  length: number()
21035
21195
  });
21036
21196
  var EndDownloadInputSchema = object({ downloadId: string() });
21037
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
21197
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
21038
21198
  location: StorageLocationSchema,
21039
21199
  relativePath: string()
21040
- }), string()), method(object({
21200
+ }), string(), { auth: "admin" }), method(object({
21041
21201
  location: StorageLocationSchema,
21042
21202
  relativePath: string(),
21043
21203
  data: _instanceof(Uint8Array)
21044
- }), _void(), { kind: "mutation" }), method(object({
21204
+ }), _void(), {
21205
+ kind: "mutation",
21206
+ auth: "admin"
21207
+ }), method(object({
21045
21208
  location: StorageLocationSchema,
21046
21209
  relativePath: string()
21047
- }), _instanceof(Uint8Array)), method(object({
21210
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
21048
21211
  location: StorageLocationSchema,
21049
21212
  relativePath: string()
21050
- }), boolean()), method(object({
21213
+ }), boolean(), { auth: "admin" }), method(object({
21051
21214
  location: StorageLocationSchema,
21052
21215
  prefix: string().optional()
21053
- }), array(string()).readonly()), method(object({
21216
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
21054
21217
  location: StorageLocationSchema,
21055
21218
  relativePath: string()
21056
- }), _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" });
21219
+ }), _void(), {
21220
+ kind: "mutation",
21221
+ auth: "admin"
21222
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
21223
+ kind: "mutation",
21224
+ auth: "admin"
21225
+ }), method(WriteChunkInputSchema, _void(), {
21226
+ kind: "mutation",
21227
+ auth: "admin"
21228
+ }), method(FinalizeUploadInputSchema, _void(), {
21229
+ kind: "mutation",
21230
+ auth: "admin"
21231
+ }), method(AbortUploadInputSchema, _void(), {
21232
+ kind: "mutation",
21233
+ auth: "admin"
21234
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
21235
+ kind: "mutation",
21236
+ auth: "admin"
21237
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
21238
+ kind: "mutation",
21239
+ auth: "admin"
21240
+ });
21057
21241
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
21058
21242
  var ProfileSettingsSchemaBridge = unknown().nullable();
21059
21243
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -21311,7 +21495,8 @@ method(object({
21311
21495
  access: "create"
21312
21496
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
21313
21497
  kind: "mutation",
21314
- access: "view"
21498
+ access: "view",
21499
+ auth: "admin"
21315
21500
  }), method(object({
21316
21501
  /** Required — the user the assertion belongs to (verified). */
21317
21502
  userId: string(),
@@ -21319,10 +21504,12 @@ method(object({
21319
21504
  response: record(string(), unknown())
21320
21505
  }), object({ verified: boolean() }), {
21321
21506
  kind: "mutation",
21322
- access: "view"
21507
+ access: "view",
21508
+ auth: "admin"
21323
21509
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
21324
21510
  kind: "mutation",
21325
- access: "view"
21511
+ access: "view",
21512
+ auth: "admin"
21326
21513
  }), method(object({
21327
21514
  /** AuthenticationResponseJSON from the browser. */
21328
21515
  response: record(string(), unknown()) }), object({
@@ -21330,7 +21517,8 @@ response: record(string(), unknown()) }), object({
21330
21517
  userId: string().nullable()
21331
21518
  }), {
21332
21519
  kind: "mutation",
21333
- access: "view"
21520
+ access: "view",
21521
+ auth: "admin"
21334
21522
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
21335
21523
  userId: string(),
21336
21524
  credentialId: string()
@@ -21502,7 +21690,19 @@ var VectorStatsResultSchema = object({
21502
21690
  /** False when the backend ranks approximately. */
21503
21691
  exact: boolean()
21504
21692
  });
21505
- 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);
21693
+ method(VectorDeclareIndexInputSchema, _void(), {
21694
+ kind: "mutation",
21695
+ auth: "admin"
21696
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
21697
+ kind: "mutation",
21698
+ auth: "admin"
21699
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
21700
+ kind: "mutation",
21701
+ auth: "admin"
21702
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
21703
+ kind: "mutation",
21704
+ auth: "admin"
21705
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
21506
21706
  var ClipSchema = object({
21507
21707
  /** Opaque, provider-namespaced id. The default provider encodes the time
21508
21708
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -23963,7 +24163,27 @@ var MediaFileLiteSchema$1 = object({
23963
24163
  sizeBytes: number(),
23964
24164
  timestamp: number()
23965
24165
  });
23966
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
24166
+ method(object({
24167
+ /**
24168
+ * Inline {@link IdentitySchema.coverBase64} on every row.
24169
+ *
24170
+ * Default `false`, the same inversion `listRecentFaces` and
24171
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
24172
+ * why the burden belongs on the caller that WANTS the bytes). Measured
24173
+ * on the live hub the same day: four identities cost 40,979 B with the
24174
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
24175
+ * four times and the viewer holds at `staleTime: 30_000`.
24176
+ *
24177
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
24178
+ * the `event-media` plane serves that key `immutable` with an ETag.
24179
+ *
24180
+ * **This is an INPUT field, so it does not reach the addon until the
24181
+ * next train** — the hub router validates cap inputs against its own
24182
+ * compiled Zod and strips a key it does not know. Until then the
24183
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
24184
+ * is what ships, and the opt-in becomes reachable when the train lands.
24185
+ */
24186
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
23967
24187
  kind: "mutation",
23968
24188
  auth: "admin"
23969
24189
  }), method(object({
@@ -26851,7 +27071,14 @@ var PlateInfoSchema = object({
26851
27071
  plateBbox: BoundingBoxSchema.optional(),
26852
27072
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
26853
27073
  keyFrameMediaKey: string().optional(),
26854
- base64: string().optional()
27074
+ base64: string().optional(),
27075
+ /**
27076
+ * Same crop as a data-plane URL, always present when the plate has a stored
27077
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
27078
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
27079
+ * left at its `true` default.
27080
+ */
27081
+ cropUrl: string().optional()
26855
27082
  });
26856
27083
  var MediaFileLiteSchema = object({
26857
27084
  key: string(),
@@ -26869,14 +27096,34 @@ var PlateClusterSchema = object({
26869
27096
  });
26870
27097
  method(object({
26871
27098
  deviceId: number().int().optional(),
26872
- limit: number().int().positive().optional()
27099
+ limit: number().int().positive().optional(),
27100
+ /**
27101
+ * Inline the base64 crop on every row. Default `true` — the existing
27102
+ * behaviour, kept so no caller breaks.
27103
+ *
27104
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
27105
+ * Measured on the live hub at the 500 rows the Plates view asks for:
27106
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
27107
+ * metadata without them — and the browser then caches the images.
27108
+ *
27109
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
27110
+ * plates were the one gallery list left without it.
27111
+ *
27112
+ * **This is an INPUT field, so it does not reach the addon until the
27113
+ * next train.** The hub router validates cap inputs against its own
27114
+ * compiled Zod and strips a key it does not know. Until the train
27115
+ * ships, sending `false` is harmless and keeps the crops inline.
27116
+ */
27117
+ includeCrops: boolean().optional()
26873
27118
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
26874
27119
  deviceId: number().int(),
26875
27120
  trackId: string()
26876
27121
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
26877
27122
  text: string().min(1),
26878
27123
  maxDistance: number().int().min(0).optional(),
26879
- limit: number().int().positive().optional()
27124
+ limit: number().int().positive().optional(),
27125
+ /** See `listPlates.includeCrops`. Default `true`. */
27126
+ includeCrops: boolean().optional()
26880
27127
  }), array(PlateInfoSchema).readonly()), method(object({
26881
27128
  maxDistance: number().int().min(0).optional(),
26882
27129
  minClusterSize: number().int().min(2).optional(),
@@ -26890,7 +27137,13 @@ method(object({
26890
27137
  }), method(object({ plateId: string() }), _void(), {
26891
27138
  kind: "mutation",
26892
27139
  auth: "admin"
26893
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
27140
+ }), method(object({
27141
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
27142
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
27143
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
27144
+ * INPUT field: stripped by the hub router until the train ships, which
27145
+ * resolves to `false` and is exactly the intended default. */
27146
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
26894
27147
  kind: "mutation",
26895
27148
  auth: "admin"
26896
27149
  }), method(object({
@@ -32375,6 +32628,12 @@ Object.freeze({
32375
32628
  addonId: null,
32376
32629
  access: "view"
32377
32630
  },
32631
+ "deviceManager.getBindingsBatch": {
32632
+ capName: "device-manager",
32633
+ capScope: "system",
32634
+ addonId: null,
32635
+ access: "view"
32636
+ },
32378
32637
  "deviceManager.getChildren": {
32379
32638
  capName: "device-manager",
32380
32639
  capScope: "system",
@@ -32435,6 +32694,12 @@ Object.freeze({
32435
32694
  addonId: null,
32436
32695
  access: "view"
32437
32696
  },
32697
+ "deviceManager.getLinkedDevicesBatch": {
32698
+ capName: "device-manager",
32699
+ capScope: "system",
32700
+ addonId: null,
32701
+ access: "view"
32702
+ },
32438
32703
  "deviceManager.getRoleDisplayDefaults": {
32439
32704
  capName: "device-manager",
32440
32705
  capScope: "system",
@@ -34139,6 +34404,12 @@ Object.freeze({
34139
34404
  addonId: null,
34140
34405
  access: "create"
34141
34406
  },
34407
+ "pipelineAnalytics.cancelRelocateMedia": {
34408
+ capName: "pipeline-analytics",
34409
+ capScope: "device",
34410
+ addonId: null,
34411
+ access: "create"
34412
+ },
34142
34413
  "pipelineAnalytics.cancelStorageMigrationMove": {
34143
34414
  capName: "pipeline-analytics",
34144
34415
  capScope: "device",
@@ -34205,6 +34476,12 @@ Object.freeze({
34205
34476
  addonId: null,
34206
34477
  access: "view"
34207
34478
  },
34479
+ "pipelineAnalytics.getGroup": {
34480
+ capName: "pipeline-analytics",
34481
+ capScope: "device",
34482
+ addonId: null,
34483
+ access: "view"
34484
+ },
34208
34485
  "pipelineAnalytics.getKeyEvents": {
34209
34486
  capName: "pipeline-analytics",
34210
34487
  capScope: "device",
@@ -34289,6 +34566,12 @@ Object.freeze({
34289
34566
  addonId: null,
34290
34567
  access: "view"
34291
34568
  },
34569
+ "pipelineAnalytics.listGroups": {
34570
+ capName: "pipeline-analytics",
34571
+ capScope: "device",
34572
+ addonId: null,
34573
+ access: "view"
34574
+ },
34292
34575
  "pipelineAnalytics.listOpsLog": {
34293
34576
  capName: "pipeline-analytics",
34294
34577
  capScope: "device",
@@ -34301,6 +34584,12 @@ Object.freeze({
34301
34584
  addonId: null,
34302
34585
  access: "view"
34303
34586
  },
34587
+ "pipelineAnalytics.listRelocateMediaJobs": {
34588
+ capName: "pipeline-analytics",
34589
+ capScope: "device",
34590
+ addonId: null,
34591
+ access: "view"
34592
+ },
34304
34593
  "pipelineAnalytics.listRetrainAnnotations": {
34305
34594
  capName: "pipeline-analytics",
34306
34595
  capScope: "device",
@@ -34379,6 +34668,12 @@ Object.freeze({
34379
34668
  addonId: null,
34380
34669
  access: "create"
34381
34670
  },
34671
+ "pipelineAnalytics.relocateMedia": {
34672
+ capName: "pipeline-analytics",
34673
+ capScope: "device",
34674
+ addonId: null,
34675
+ access: "create"
34676
+ },
34382
34677
  "pipelineAnalytics.restageRetrainTrack": {
34383
34678
  capName: "pipeline-analytics",
34384
34679
  capScope: "device",
@@ -37070,6 +37365,11 @@ Object.freeze({
37070
37365
  form: "single",
37071
37366
  optional: false
37072
37367
  }],
37368
+ "deviceManager.getBindingsBatch": [{
37369
+ name: "deviceIds",
37370
+ form: "array",
37371
+ optional: false
37372
+ }],
37073
37373
  "deviceManager.getChildren": [{
37074
37374
  name: "parentDeviceId",
37075
37375
  form: "single",
@@ -37115,6 +37415,11 @@ Object.freeze({
37115
37415
  form: "single",
37116
37416
  optional: false
37117
37417
  }],
37418
+ "deviceManager.getLinkedDevicesBatch": [{
37419
+ name: "deviceIds",
37420
+ form: "array",
37421
+ optional: false
37422
+ }],
37118
37423
  "deviceManager.getSettingsSchema": [{
37119
37424
  name: "deviceId",
37120
37425
  form: "single",
@@ -37135,6 +37440,11 @@ Object.freeze({
37135
37440
  form: "single",
37136
37441
  optional: false
37137
37442
  }],
37443
+ "deviceManager.listAll": [{
37444
+ name: "deviceIds",
37445
+ form: "array",
37446
+ optional: true
37447
+ }],
37138
37448
  "deviceManager.loadConfig": [{
37139
37449
  name: "deviceId",
37140
37450
  form: "single",
@@ -37708,6 +38018,11 @@ Object.freeze({
37708
38018
  form: "single",
37709
38019
  optional: false
37710
38020
  }],
38021
+ "pipelineAnalytics.getGroup": [{
38022
+ name: "deviceId",
38023
+ form: "single",
38024
+ optional: false
38025
+ }],
37711
38026
  "pipelineAnalytics.getKeyEvents": [{
37712
38027
  name: "deviceId",
37713
38028
  form: "single",
@@ -37763,6 +38078,11 @@ Object.freeze({
37763
38078
  form: "array",
37764
38079
  optional: false
37765
38080
  }],
38081
+ "pipelineAnalytics.listGroups": [{
38082
+ name: "deviceIds",
38083
+ form: "array",
38084
+ optional: false
38085
+ }],
37766
38086
  "pipelineAnalytics.listOpsLog": [{
37767
38087
  name: "deviceId",
37768
38088
  form: "single",