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