@camstack/addon-provider-dreame 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
@@ -56306,6 +56306,13 @@ var BaseAddon = class {
56306
56306
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
56307
56307
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
56308
56308
  _registeredCapNames = [];
56309
+ /**
56310
+ * True only after `readAddonStore` actually answered. Constructor
56311
+ * defaults look like stored config when the store is down — a forked
56312
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
56313
+ * mode, 2026-08-25) is not "the operator chose this".
56314
+ */
56315
+ settingsStoreReady = false;
56309
56316
  /** Default config values. Provided via constructor. */
56310
56317
  defaults;
56311
56318
  constructor(defaults) {
@@ -56706,7 +56713,9 @@ var BaseAddon = class {
56706
56713
  ];
56707
56714
  let lastErr;
56708
56715
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
56709
- return await settings.readAddonStore() ?? {};
56716
+ const stored = await settings.readAddonStore() ?? {};
56717
+ this.settingsStoreReady = true;
56718
+ return stored;
56710
56719
  } catch (err) {
56711
56720
  lastErr = err;
56712
56721
  const msg = err instanceof Error ? err.message : String(err);
@@ -56714,6 +56723,7 @@ var BaseAddon = class {
56714
56723
  if (attempt === delaysMs.length) break;
56715
56724
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
56716
56725
  }
56726
+ this.settingsStoreReady = false;
56717
56727
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
56718
56728
  return {};
56719
56729
  }
@@ -57125,7 +57135,7 @@ function method(input, output, options) {
57125
57135
  input,
57126
57136
  output,
57127
57137
  kind: options?.kind ?? "query",
57128
- auth: options?.auth ?? "protected",
57138
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
57129
57139
  ...options?.access !== void 0 ? { access: options.access } : {},
57130
57140
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
57131
57141
  timeoutMs: options?.timeoutMs
@@ -57149,7 +57159,7 @@ function event(data) {
57149
57159
  }
57150
57160
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
57151
57161
  var VersionOutputSchema$1 = object({ version: string() });
57152
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
57162
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
57153
57163
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
57154
57164
  DeviceType["Camera"] = "camera";
57155
57165
  DeviceType["Hub"] = "hub";
@@ -57470,7 +57480,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
57470
57480
  }({});
57471
57481
  var StaticDirOutputSchema = object({ staticDir: string() });
57472
57482
  var VersionOutputSchema = object({ version: string() });
57473
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
57483
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
57474
57484
  /**
57475
57485
  * device-ops — device-scoped cap that unifies the per-IDevice operations
57476
57486
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -58096,24 +58106,6 @@ var RecordingRetentionSchema = object({
58096
58106
  maxSizeGb: number().min(0).optional()
58097
58107
  });
58098
58108
  /**
58099
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
58100
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
58101
- * previews at. Five graduated steps; absent on a config = `standard` (the
58102
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
58103
- *
58104
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
58105
- * Each window's index sidecar carries its own tile dims, so a camera whose
58106
- * preset changed over time renders every historical window at the dims it was
58107
- * written with.
58108
- */
58109
- var ScrubThumbnailPresetSchema = _enum([
58110
- "minimal",
58111
- "low",
58112
- "standard",
58113
- "high",
58114
- "max"
58115
- ]);
58116
- /**
58117
58109
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
58118
58110
  *
58119
58111
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -58121,7 +58113,11 @@ var ScrubThumbnailPresetSchema = _enum([
58121
58113
  * other field is a storage knob (profiles, segment length, retention, scrub).
58122
58114
  *
58123
58115
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
58124
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
58116
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
58117
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
58118
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
58119
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
58120
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
58125
58121
  * A stale caller must fail loudly — silently stripping its legacy intent would
58126
58122
  * persist a band-less config, i.e. silently stop recording the camera.
58127
58123
  */
@@ -58144,14 +58140,7 @@ var RecordingConfigSchema = object({
58144
58140
  * "off" is the absence of a covering band, never a band value.
58145
58141
  */
58146
58142
  bands: array(RecordingBandSchema).default([]),
58147
- retention: RecordingRetentionSchema.optional(),
58148
- /**
58149
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
58150
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
58151
- * windows only — existing sheets are immutable, and each window's index
58152
- * carries its own tile dims so mixed-preset history renders correctly.
58153
- */
58154
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
58143
+ retention: RecordingRetentionSchema.optional()
58155
58144
  }).strict();
58156
58145
  /**
58157
58146
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -58227,10 +58216,11 @@ var RelocateFootageInputSchema = object({
58227
58216
  * `RecordingConfig.enabled` or camera wrapper bindings. */
58228
58217
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
58229
58218
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
58230
- var StorageMigrationMediaMoveInputSchema = object({
58219
+ var RelocateMediaInputSchema = object({
58231
58220
  toLocationId: string(),
58232
58221
  throttleMbps: number().min(1).max(1e3).optional()
58233
- }).extend({ leaseId: string().min(1) });
58222
+ });
58223
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
58234
58224
  /** The independently selectable logical storage classes. `recordings`
58235
58225
  * encompasses the high and mid segment profiles; `recordingsLow` is low
58236
58226
  * segments; `eventMedia` is post-analysis blobs. */
@@ -58525,7 +58515,26 @@ var LabelDefinitionSchema = object({
58525
58515
  description: string().optional(),
58526
58516
  icon: string().optional()
58527
58517
  });
58528
- var ClassMapDefinitionSchema = object({
58518
+ /**
58519
+ * Wire schema for a per-model CATALOG classMap override
58520
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
58521
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
58522
+ * detection pipeline executor actually routes.
58523
+ *
58524
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
58525
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
58526
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
58527
+ * enum) — the two used to share the name `ClassMapDefinition`/
58528
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
58529
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
58530
+ * are not: it is two different concepts colliding on a name. Keep this type
58531
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
58532
+ * would either narrow every `ClassMapDefinition` consumer to the four
58533
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
58534
+ * schema exists for (see the "rejects a classMap whose target is not a
58535
+ * detection macro" test in `model-catalog-schema.test.ts`).
58536
+ */
58537
+ var DetectionCatalogClassMapSchema = object({
58529
58538
  mapping: record(string(), _enum([
58530
58539
  "person",
58531
58540
  "vehicle",
@@ -58617,6 +58626,12 @@ var ModelVariantGroupSchema = object({
58617
58626
  */
58618
58627
  resolution: number().int().positive().optional()
58619
58628
  });
58629
+ var ModelProviderIdSchema = _enum([
58630
+ "camstack",
58631
+ "frigate",
58632
+ "scrypted",
58633
+ "custom"
58634
+ ]);
58620
58635
  var ModelCatalogEntrySchema = object({
58621
58636
  id: string(),
58622
58637
  name: string(),
@@ -58714,11 +58729,17 @@ var ModelCatalogEntrySchema = object({
58714
58729
  */
58715
58730
  group: ModelVariantGroupSchema.optional(),
58716
58731
  /**
58732
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
58733
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
58734
+ * persisted before this field existed (`inferModelProvider` fills those).
58735
+ */
58736
+ provider: ModelProviderIdSchema.optional(),
58737
+ /**
58717
58738
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
58718
58739
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
58719
58740
  * labels already ARE the CamStack macros (Scrypted identity map).
58720
58741
  */
58721
- classMap: ClassMapDefinitionSchema.optional()
58742
+ classMap: DetectionCatalogClassMapSchema.optional()
58722
58743
  });
58723
58744
  var ConvertTargetSchema = discriminatedUnion("format", [object({
58724
58745
  format: literal("openvino"),
@@ -58748,7 +58769,7 @@ var ModelConvertMetadataSchema = object({
58748
58769
  "segmentation"
58749
58770
  ]),
58750
58771
  faceAlignment: boolean().optional(),
58751
- classMap: ClassMapDefinitionSchema.optional()
58772
+ classMap: DetectionCatalogClassMapSchema.optional()
58752
58773
  });
58753
58774
  var ConvertResultSchema = object({
58754
58775
  entry: ModelCatalogEntrySchema,
@@ -59611,7 +59632,7 @@ var AddonPageDeclarationSchema = object({
59611
59632
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
59612
59633
  sectionLabel: string().optional()
59613
59634
  });
59614
- method(_void(), array(AddonPageDeclarationSchema).readonly());
59635
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
59615
59636
  var AddonHttpRouteSchema = object({
59616
59637
  method: _enum([
59617
59638
  "GET",
@@ -59846,7 +59867,7 @@ var WidgetMetadataSchema = object({
59846
59867
  defaultColumns: number().int().min(1).max(12).default(6),
59847
59868
  defaultRows: number().int().min(1).max(12).default(1)
59848
59869
  });
59849
- method(_void(), array(WidgetMetadataSchema).readonly());
59870
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
59850
59871
  /**
59851
59872
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
59852
59873
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -61470,7 +61491,7 @@ var CustomModelDescriptorSchema = object({
61470
61491
  stepId: string(),
61471
61492
  entry: ModelCatalogEntrySchema
61472
61493
  });
61473
- method(_void(), array(CustomModelDescriptorSchema).readonly());
61494
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
61474
61495
  /**
61475
61496
  * Query filter for settings-store collections.
61476
61497
  */
@@ -61557,7 +61578,8 @@ method(object({
61557
61578
  }), _void(), { kind: "mutation" }), method(object({
61558
61579
  namespace: string().optional(),
61559
61580
  collection: string(),
61560
- filter: QueryFilterSchema.optional()
61581
+ filter: QueryFilterSchema.optional(),
61582
+ columns: array(string()).readonly().optional()
61561
61583
  }), array(SettingsRecordSchema).readonly()), method(object({
61562
61584
  namespace: string().optional(),
61563
61585
  collection: string(),
@@ -61620,46 +61642,87 @@ var EngineInfoSchema = object({
61620
61642
  kind: _enum(["relational", "vector"]),
61621
61643
  displayName: string()
61622
61644
  });
61623
- method(_void(), EngineInfoSchema), method(object({
61645
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
61624
61646
  namespace: string().optional(),
61625
61647
  collection: string(),
61626
61648
  key: string()
61627
- }), unknown()), method(object({
61649
+ }), unknown(), { auth: "admin" }), method(object({
61628
61650
  namespace: string().optional(),
61629
61651
  collection: string(),
61630
61652
  key: string(),
61631
61653
  value: unknown()
61632
- }), _void(), { kind: "mutation" }), method(object({
61654
+ }), _void(), {
61655
+ kind: "mutation",
61656
+ auth: "admin"
61657
+ }), method(object({
61633
61658
  namespace: string().optional(),
61634
61659
  collection: string(),
61635
- filter: QueryFilterSchema.optional()
61636
- }), array(SettingsRecordSchema).readonly()), method(object({
61660
+ filter: QueryFilterSchema.optional(),
61661
+ /**
61662
+ * SQL-level column projection — MUST mirror `settings-store.query`.
61663
+ *
61664
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
61665
+ * was wrong — corrected 2026-08-26 after the hop map
61666
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
61667
+ * There is **no Zod parse at all** between the door and the engine: the
61668
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
61669
+ * field declared here reaches `SqliteSettingsBackend` either way.
61670
+ *
61671
+ * What actually lost `columns` was the THIRD declaration of this shape:
61672
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
61673
+ * interface the engine destructures from. The field existed on both
61674
+ * schemas and the engine still never read it, because nothing checks a
61675
+ * registered provider against `InferProvider<cap>` —
61676
+ * `ProviderRegistration.provider` is typed `object`.
61677
+ *
61678
+ * It is declared here anyway, and must stay in step with
61679
+ * `settings-store.query`: a caller reading only the cap definitions has
61680
+ * to be able to see that this call carries a projection.
61681
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
61682
+ */
61683
+ columns: array(string()).readonly().optional()
61684
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
61637
61685
  namespace: string().optional(),
61638
61686
  collection: string(),
61639
61687
  record: SettingsRecordSchema
61640
- }), _void(), { kind: "mutation" }), method(object({
61688
+ }), _void(), {
61689
+ kind: "mutation",
61690
+ auth: "admin"
61691
+ }), method(object({
61641
61692
  namespace: string().optional(),
61642
61693
  collection: string(),
61643
61694
  id: string(),
61644
61695
  data: record(string(), unknown())
61645
- }), _void(), { kind: "mutation" }), method(object({
61696
+ }), _void(), {
61697
+ kind: "mutation",
61698
+ auth: "admin"
61699
+ }), method(object({
61646
61700
  namespace: string().optional(),
61647
61701
  collection: string(),
61648
61702
  key: string()
61649
- }), _void(), { kind: "mutation" }), method(object({
61703
+ }), _void(), {
61704
+ kind: "mutation",
61705
+ auth: "admin"
61706
+ }), method(object({
61650
61707
  namespace: string().optional(),
61651
61708
  collection: string(),
61652
61709
  filter: MutationFilterSchema
61653
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
61710
+ }), object({ deleted: number().int() }), {
61711
+ kind: "mutation",
61712
+ auth: "admin"
61713
+ }), method(object({
61654
61714
  namespace: string().optional(),
61655
61715
  collection: string(),
61656
61716
  filter: MutationFilterSchema,
61657
61717
  data: record(string(), unknown())
61658
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
61718
+ }), object({ updated: number().int() }), {
61719
+ kind: "mutation",
61720
+ auth: "admin"
61721
+ }), method(object({
61659
61722
  namespace: string().optional(),
61660
61723
  collection: string(),
61661
61724
  filter: QueryFilterSchema.optional()
61662
- }), number()), method(object({
61725
+ }), number(), { auth: "admin" }), method(object({
61663
61726
  namespace: string().optional(),
61664
61727
  collection: string(),
61665
61728
  field: string(),
@@ -61669,15 +61732,18 @@ method(_void(), EngineInfoSchema), method(object({
61669
61732
  }), array(object({
61670
61733
  bucket: number().int(),
61671
61734
  count: number().int()
61672
- })).readonly()), method(object({
61735
+ })).readonly(), { auth: "admin" }), method(object({
61673
61736
  namespace: string().optional(),
61674
61737
  collection: string()
61675
- }), boolean()), method(object({
61738
+ }), boolean(), { auth: "admin" }), method(object({
61676
61739
  namespace: string().optional(),
61677
61740
  collection: string(),
61678
61741
  columns: array(CollectionColumnSchema).readonly(),
61679
61742
  indexes: array(CollectionIndexSchema).readonly().optional()
61680
- }), _void(), { kind: "mutation" });
61743
+ }), _void(), {
61744
+ kind: "mutation",
61745
+ auth: "admin"
61746
+ });
61681
61747
  /**
61682
61748
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
61683
61749
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -62522,6 +62588,27 @@ var LinkedDeviceSchema = object({
62522
62588
  features: array(string()),
62523
62589
  producesTrackedEvents: boolean().optional()
62524
62590
  });
62591
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
62592
+ * The batch answer needs the tag; the single-device answer already has it
62593
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
62594
+ var LinkedDevicesForDeviceSchema = object({
62595
+ deviceId: number(),
62596
+ mode: LinkedDevicesModeSchema,
62597
+ devices: array(LinkedDeviceSchema)
62598
+ });
62599
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
62600
+ * `getAllBindings` all answer in. Declared once: three copies of the same
62601
+ * object literal is exactly how the three drift apart. */
62602
+ var DeviceBindingsForDeviceSchema = object({
62603
+ deviceId: number(),
62604
+ entries: array(object({
62605
+ capName: string(),
62606
+ kind: _enum(["native", "wrapped"]),
62607
+ providerAddonId: string(),
62608
+ providerNodeId: string(),
62609
+ nativeAddonId: string()
62610
+ }))
62611
+ });
62525
62612
  var SavedDeviceRowSchema = object({
62526
62613
  /** Numeric id reserved at allocateDeviceId time. */
62527
62614
  id: number(),
@@ -62747,11 +62834,25 @@ method(object({
62747
62834
  projection: _enum(["full", "slim"]).optional(),
62748
62835
  /** Return only camera devices. Filtering server-side instead of
62749
62836
  * shipping 293 rows to find 12. */
62750
- isCamera: boolean().optional()
62837
+ isCamera: boolean().optional(),
62838
+ /**
62839
+ * Return only these device ids. For the caller that already KNOWS the
62840
+ * handful it wants and needs a field the id-bearing answer does not
62841
+ * carry — the viewer's linked-devices panel joins `type` and `online`
62842
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
62843
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
62844
+ * refetches on the reconcile interval, on a phone.
62845
+ *
62846
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
62847
+ * keys rather than rejecting them (verified against the live hub
62848
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
62849
+ * it answers today and the caller filters as it already does.
62850
+ */
62851
+ deviceIds: array(number()).optional()
62751
62852
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
62752
62853
  mode: LinkedDevicesModeSchema,
62753
62854
  devices: array(LinkedDeviceSchema)
62754
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
62855
+ })), 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({
62755
62856
  deviceId: number(),
62756
62857
  values: record(string(), unknown())
62757
62858
  }), object({ success: literal(true) }), {
@@ -62778,25 +62879,7 @@ method(object({
62778
62879
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
62779
62880
  kind: "mutation",
62780
62881
  auth: "admin"
62781
- }), method(object({ deviceId: number() }), object({
62782
- deviceId: number(),
62783
- entries: array(object({
62784
- capName: string(),
62785
- kind: _enum(["native", "wrapped"]),
62786
- providerAddonId: string(),
62787
- providerNodeId: string(),
62788
- nativeAddonId: string()
62789
- }))
62790
- })), method(object({}), array(object({
62791
- deviceId: number(),
62792
- entries: array(object({
62793
- capName: string(),
62794
- kind: _enum(["native", "wrapped"]),
62795
- providerAddonId: string(),
62796
- providerNodeId: string(),
62797
- nativeAddonId: string()
62798
- }))
62799
- }))), method(object({
62882
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
62800
62883
  deviceId: number(),
62801
62884
  capName: string(),
62802
62885
  wrapperAddonId: string(),
@@ -62967,7 +63050,7 @@ method(object({
62967
63050
  crop: _instanceof(Uint8Array),
62968
63051
  width: number(),
62969
63052
  height: number()
62970
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
63053
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
62971
63054
  /**
62972
63055
  * filesystem-browse — per-node capability for browsing the node's local
62973
63056
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -63260,19 +63343,22 @@ method(LlmGenerateBaseInputSchema.extend({
63260
63343
  runtime: ManagedRuntimeConfigSchema,
63261
63344
  /** The managed profile's timeout, threaded by the hub provider. */
63262
63345
  timeoutMs: number().int().positive().optional()
63263
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
63346
+ }), LlmGenerateResultSchema, {
63347
+ kind: "mutation",
63348
+ auth: "admin"
63349
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
63264
63350
  kind: "mutation",
63265
63351
  auth: "admin"
63266
63352
  }), method(object({}), _void(), {
63267
63353
  kind: "mutation",
63268
63354
  auth: "admin"
63269
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
63355
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
63270
63356
  kind: "mutation",
63271
63357
  auth: "admin"
63272
63358
  }), method(object({ file: string() }), _void(), {
63273
63359
  kind: "mutation",
63274
63360
  auth: "admin"
63275
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
63361
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
63276
63362
  /**
63277
63363
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
63278
63364
  * methods concat-fan across providers; single-row methods route to ONE
@@ -65206,12 +65292,15 @@ var NcOccupancyConditionSchema = object({
65206
65292
  * there is no second switch that can disagree with the first and every rule
65207
65293
  * authored before the decision migrates for free (`audioModeOf`):
65208
65294
  *
65209
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
65210
- * classifier labels with one of them. No window, no percentage:
65211
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
65212
- * `throttle` cooldown is the only brake. The per-label confidence floor is
65213
- * the analyzer's (`classificationMinScore`, per device) — a label only
65214
- * reaches this condition if the classifier was already confident enough.
65295
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
65296
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
65297
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
65298
+ * frames is the wrong question for a classifier that labels 1–3 frames
65299
+ * per episode. The count window is the brake that drops a single-frame
65300
+ * false positive; the rule's own `throttle` cooldown is the other. The
65301
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
65302
+ * per device) — a label only reaches this condition if the classifier was
65303
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
65215
65304
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
65216
65305
  * the condition: at least `hitPercent`% of the samples over
65217
65306
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -65238,14 +65327,22 @@ var NcOccupancyConditionSchema = object({
65238
65327
  * an operator who typed `dog` mean the same thing.
65239
65328
  */
65240
65329
  var NcAudioConditionSchema = object({
65241
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
65330
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
65242
65331
  labels: array(string().min(1)).min(1).optional(),
65243
65332
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
65244
65333
  dbThreshold: number().min(-96).max(0).optional(),
65245
65334
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
65246
65335
  hitPercent: number().int().min(1).max(100).default(60),
65247
65336
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
65248
- samplingSeconds: number().int().min(1).max(300).default(10)
65337
+ samplingSeconds: number().int().min(1).max(300).default(10),
65338
+ /**
65339
+ * LABEL MODE: how many labelled frames must land inside
65340
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
65341
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
65342
+ */
65343
+ confirmHits: number().int().min(1).max(20).optional(),
65344
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
65345
+ confirmWindowSec: number().int().min(1).max(60).optional()
65249
65346
  });
65250
65347
  /**
65251
65348
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -66772,7 +66869,7 @@ var OauthIntegrationDescriptorSchema = object({
66772
66869
  */
66773
66870
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
66774
66871
  });
66775
- method(_void(), OauthIntegrationDescriptorSchema);
66872
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
66776
66873
  /**
66777
66874
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
66778
66875
  * per-frame detections emitted by the pipeline runner into tracked
@@ -67619,6 +67716,46 @@ var RecentTracksPageSchema = object({
67619
67716
  /** Cursor for the next page, or null when this page is the last. */
67620
67717
  nextCursor: string().nullable()
67621
67718
  });
67719
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
67720
+ var LIST_GROUPS_MAX_LIMIT = 100;
67721
+ var AnalyticsGroupRecordSchema = object({
67722
+ id: string(),
67723
+ deviceId: number().int(),
67724
+ openedAt: number().int(),
67725
+ closedAt: number().int(),
67726
+ timestamp: number().int(),
67727
+ memberCount: number().int(),
67728
+ memberTrackIds: array(string()).readonly(),
67729
+ className: string(),
67730
+ classes: array(string()).readonly(),
67731
+ /** Relative event-media path, or null when the group has no picture yet. */
67732
+ mediaUrl: string().nullable(),
67733
+ singleton: boolean()
67734
+ });
67735
+ var AnalyticsGroupMemberSchema = object({
67736
+ trackId: string(),
67737
+ deviceId: number().int(),
67738
+ className: string(),
67739
+ firstSeen: number().int(),
67740
+ lastSeen: number().int(),
67741
+ mediaUrl: string().nullable()
67742
+ });
67743
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
67744
+ var ListGroupsQueryInput = object({
67745
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
67746
+ deviceIds: array(number()),
67747
+ /** Window lower bound on `closedAt` (inclusive). */
67748
+ since: number().optional(),
67749
+ /** Window upper bound on `openedAt` (inclusive). */
67750
+ until: number().optional(),
67751
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
67752
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
67753
+ cursor: string().optional()
67754
+ });
67755
+ var ListGroupsPageSchema = object({
67756
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
67757
+ nextCursor: string().nullable()
67758
+ });
67622
67759
  var KeyEventQueryInput = object({
67623
67760
  deviceId: number(),
67624
67761
  /** Window lower bound (track firstSeen ≥ since). */
@@ -67694,7 +67831,9 @@ var TrackCascadeCountsSchema = object({
67694
67831
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
67695
67832
  plates: number().int(),
67696
67833
  /** Per-track CLIP search vectors removed (best-effort). */
67697
- embeddings: number().int()
67834
+ embeddings: number().int(),
67835
+ /** Group membership + group rows removed with their last member (best-effort). */
67836
+ groups: number().int()
67698
67837
  });
67699
67838
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
67700
67839
  var DiskReconcileCountsSchema = object({
@@ -67840,7 +67979,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
67840
67979
  * stationary registry). Default false: the timeline lists passages,
67841
67980
  * not parking records (operator decision, 2026-08-15). */
67842
67981
  includeStationary: boolean().optional()
67843
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
67982
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
67983
+ deviceId: number(),
67984
+ groupId: string().min(1)
67985
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
67844
67986
  kind: "mutation",
67845
67987
  auth: "admin"
67846
67988
  }), 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({
@@ -67922,6 +68064,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
67922
68064
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
67923
68065
  kind: "mutation",
67924
68066
  auth: "admin"
68067
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
68068
+ kind: "mutation",
68069
+ auth: "admin"
68070
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
68071
+ kind: "query",
68072
+ auth: "admin"
68073
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
68074
+ kind: "mutation",
68075
+ auth: "admin"
67925
68076
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
67926
68077
  kind: "query",
67927
68078
  auth: "admin"
@@ -68076,6 +68227,11 @@ object({
68076
68227
  "jpeg"
68077
68228
  ])
68078
68229
  });
68230
+ /**
68231
+ * Process-local frame identity. It is serializable so it can ride an in-process
68232
+ * capability call, but `registryId` deliberately prevents resolution in any
68233
+ * other process or execution group.
68234
+ */
68079
68235
  var FrameRefSchema = object({
68080
68236
  registryId: string().min(1),
68081
68237
  id: string().min(1),
@@ -68150,7 +68306,8 @@ var PipelineModelOptionSchema = object({
68150
68306
  sizeMB: number()
68151
68307
  })),
68152
68308
  group: ModelVariantGroupSchema.optional(),
68153
- legacy: boolean().optional()
68309
+ legacy: boolean().optional(),
68310
+ provider: ModelProviderIdSchema.optional()
68154
68311
  });
68155
68312
  var ConfigFieldBridge = custom();
68156
68313
  var PipelineAddonSchemaSchema = object({
@@ -70280,7 +70437,7 @@ method(object({
70280
70437
  * linking rather than produce an eternal token.
70281
70438
  */
70282
70439
  ttlSec: union([number().int().positive(), literal("never")]).optional()
70283
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
70440
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
70284
70441
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
70285
70442
  providerId: string().min(1),
70286
70443
  displayName: string().min(1),
@@ -70375,10 +70532,13 @@ var EvictResultSchema = object({
70375
70532
  /** True when the provider has nothing left it is willing to drop on this location. */
70376
70533
  exhausted: boolean()
70377
70534
  });
70378
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
70535
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
70379
70536
  locationId: string(),
70380
70537
  targetBytes: number().int().positive()
70381
- }), EvictResultSchema, { kind: "mutation" });
70538
+ }), EvictResultSchema, {
70539
+ kind: "mutation",
70540
+ auth: "admin"
70541
+ });
70382
70542
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
70383
70543
  kind: "mutation",
70384
70544
  auth: "admin"
@@ -70438,26 +70598,50 @@ var ReadChunkInputSchema = object({
70438
70598
  length: number()
70439
70599
  });
70440
70600
  var EndDownloadInputSchema = object({ downloadId: string() });
70441
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
70601
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
70442
70602
  location: StorageLocationSchema,
70443
70603
  relativePath: string()
70444
- }), string()), method(object({
70604
+ }), string(), { auth: "admin" }), method(object({
70445
70605
  location: StorageLocationSchema,
70446
70606
  relativePath: string(),
70447
70607
  data: _instanceof(Uint8Array)
70448
- }), _void(), { kind: "mutation" }), method(object({
70608
+ }), _void(), {
70609
+ kind: "mutation",
70610
+ auth: "admin"
70611
+ }), method(object({
70449
70612
  location: StorageLocationSchema,
70450
70613
  relativePath: string()
70451
- }), _instanceof(Uint8Array)), method(object({
70614
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
70452
70615
  location: StorageLocationSchema,
70453
70616
  relativePath: string()
70454
- }), boolean()), method(object({
70617
+ }), boolean(), { auth: "admin" }), method(object({
70455
70618
  location: StorageLocationSchema,
70456
70619
  prefix: string().optional()
70457
- }), array(string()).readonly()), method(object({
70620
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
70458
70621
  location: StorageLocationSchema,
70459
70622
  relativePath: string()
70460
- }), _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" });
70623
+ }), _void(), {
70624
+ kind: "mutation",
70625
+ auth: "admin"
70626
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
70627
+ kind: "mutation",
70628
+ auth: "admin"
70629
+ }), method(WriteChunkInputSchema, _void(), {
70630
+ kind: "mutation",
70631
+ auth: "admin"
70632
+ }), method(FinalizeUploadInputSchema, _void(), {
70633
+ kind: "mutation",
70634
+ auth: "admin"
70635
+ }), method(AbortUploadInputSchema, _void(), {
70636
+ kind: "mutation",
70637
+ auth: "admin"
70638
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
70639
+ kind: "mutation",
70640
+ auth: "admin"
70641
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
70642
+ kind: "mutation",
70643
+ auth: "admin"
70644
+ });
70461
70645
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
70462
70646
  var ProfileSettingsSchemaBridge = unknown().nullable();
70463
70647
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -70715,7 +70899,8 @@ method(object({
70715
70899
  access: "create"
70716
70900
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
70717
70901
  kind: "mutation",
70718
- access: "view"
70902
+ access: "view",
70903
+ auth: "admin"
70719
70904
  }), method(object({
70720
70905
  /** Required — the user the assertion belongs to (verified). */
70721
70906
  userId: string(),
@@ -70723,10 +70908,12 @@ method(object({
70723
70908
  response: record(string(), unknown())
70724
70909
  }), object({ verified: boolean() }), {
70725
70910
  kind: "mutation",
70726
- access: "view"
70911
+ access: "view",
70912
+ auth: "admin"
70727
70913
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
70728
70914
  kind: "mutation",
70729
- access: "view"
70915
+ access: "view",
70916
+ auth: "admin"
70730
70917
  }), method(object({
70731
70918
  /** AuthenticationResponseJSON from the browser. */
70732
70919
  response: record(string(), unknown()) }), object({
@@ -70734,7 +70921,8 @@ response: record(string(), unknown()) }), object({
70734
70921
  userId: string().nullable()
70735
70922
  }), {
70736
70923
  kind: "mutation",
70737
- access: "view"
70924
+ access: "view",
70925
+ auth: "admin"
70738
70926
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
70739
70927
  userId: string(),
70740
70928
  credentialId: string()
@@ -70906,7 +71094,19 @@ var VectorStatsResultSchema = object({
70906
71094
  /** False when the backend ranks approximately. */
70907
71095
  exact: boolean()
70908
71096
  });
70909
- 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);
71097
+ method(VectorDeclareIndexInputSchema, _void(), {
71098
+ kind: "mutation",
71099
+ auth: "admin"
71100
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
71101
+ kind: "mutation",
71102
+ auth: "admin"
71103
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
71104
+ kind: "mutation",
71105
+ auth: "admin"
71106
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
71107
+ kind: "mutation",
71108
+ auth: "admin"
71109
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
70910
71110
  var ClipSchema = object({
70911
71111
  /** Opaque, provider-namespaced id. The default provider encodes the time
70912
71112
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -73384,7 +73584,27 @@ var MediaFileLiteSchema$1 = object({
73384
73584
  sizeBytes: number(),
73385
73585
  timestamp: number()
73386
73586
  });
73387
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
73587
+ method(object({
73588
+ /**
73589
+ * Inline {@link IdentitySchema.coverBase64} on every row.
73590
+ *
73591
+ * Default `false`, the same inversion `listRecentFaces` and
73592
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
73593
+ * why the burden belongs on the caller that WANTS the bytes). Measured
73594
+ * on the live hub the same day: four identities cost 40,979 B with the
73595
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
73596
+ * four times and the viewer holds at `staleTime: 30_000`.
73597
+ *
73598
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
73599
+ * the `event-media` plane serves that key `immutable` with an ETag.
73600
+ *
73601
+ * **This is an INPUT field, so it does not reach the addon until the
73602
+ * next train** — the hub router validates cap inputs against its own
73603
+ * compiled Zod and strips a key it does not know. Until then the
73604
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
73605
+ * is what ships, and the opt-in becomes reachable when the train lands.
73606
+ */
73607
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
73388
73608
  kind: "mutation",
73389
73609
  auth: "admin"
73390
73610
  }), method(object({
@@ -76272,7 +76492,14 @@ var PlateInfoSchema = object({
76272
76492
  plateBbox: BoundingBoxSchema.optional(),
76273
76493
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
76274
76494
  keyFrameMediaKey: string().optional(),
76275
- base64: string().optional()
76495
+ base64: string().optional(),
76496
+ /**
76497
+ * Same crop as a data-plane URL, always present when the plate has a stored
76498
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
76499
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
76500
+ * left at its `true` default.
76501
+ */
76502
+ cropUrl: string().optional()
76276
76503
  });
76277
76504
  var MediaFileLiteSchema = object({
76278
76505
  key: string(),
@@ -76290,14 +76517,34 @@ var PlateClusterSchema = object({
76290
76517
  });
76291
76518
  method(object({
76292
76519
  deviceId: number().int().optional(),
76293
- limit: number().int().positive().optional()
76520
+ limit: number().int().positive().optional(),
76521
+ /**
76522
+ * Inline the base64 crop on every row. Default `true` — the existing
76523
+ * behaviour, kept so no caller breaks.
76524
+ *
76525
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
76526
+ * Measured on the live hub at the 500 rows the Plates view asks for:
76527
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
76528
+ * metadata without them — and the browser then caches the images.
76529
+ *
76530
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
76531
+ * plates were the one gallery list left without it.
76532
+ *
76533
+ * **This is an INPUT field, so it does not reach the addon until the
76534
+ * next train.** The hub router validates cap inputs against its own
76535
+ * compiled Zod and strips a key it does not know. Until the train
76536
+ * ships, sending `false` is harmless and keeps the crops inline.
76537
+ */
76538
+ includeCrops: boolean().optional()
76294
76539
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
76295
76540
  deviceId: number().int(),
76296
76541
  trackId: string()
76297
76542
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
76298
76543
  text: string().min(1),
76299
76544
  maxDistance: number().int().min(0).optional(),
76300
- limit: number().int().positive().optional()
76545
+ limit: number().int().positive().optional(),
76546
+ /** See `listPlates.includeCrops`. Default `true`. */
76547
+ includeCrops: boolean().optional()
76301
76548
  }), array(PlateInfoSchema).readonly()), method(object({
76302
76549
  maxDistance: number().int().min(0).optional(),
76303
76550
  minClusterSize: number().int().min(2).optional(),
@@ -76311,7 +76558,13 @@ method(object({
76311
76558
  }), method(object({ plateId: string() }), _void(), {
76312
76559
  kind: "mutation",
76313
76560
  auth: "admin"
76314
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
76561
+ }), method(object({
76562
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
76563
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
76564
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
76565
+ * INPUT field: stripped by the hub router until the train ships, which
76566
+ * resolves to `false` and is exactly the intended default. */
76567
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
76315
76568
  kind: "mutation",
76316
76569
  auth: "admin"
76317
76570
  }), method(object({
@@ -81796,6 +82049,12 @@ Object.freeze({
81796
82049
  addonId: null,
81797
82050
  access: "view"
81798
82051
  },
82052
+ "deviceManager.getBindingsBatch": {
82053
+ capName: "device-manager",
82054
+ capScope: "system",
82055
+ addonId: null,
82056
+ access: "view"
82057
+ },
81799
82058
  "deviceManager.getChildren": {
81800
82059
  capName: "device-manager",
81801
82060
  capScope: "system",
@@ -81856,6 +82115,12 @@ Object.freeze({
81856
82115
  addonId: null,
81857
82116
  access: "view"
81858
82117
  },
82118
+ "deviceManager.getLinkedDevicesBatch": {
82119
+ capName: "device-manager",
82120
+ capScope: "system",
82121
+ addonId: null,
82122
+ access: "view"
82123
+ },
81859
82124
  "deviceManager.getRoleDisplayDefaults": {
81860
82125
  capName: "device-manager",
81861
82126
  capScope: "system",
@@ -83560,6 +83825,12 @@ Object.freeze({
83560
83825
  addonId: null,
83561
83826
  access: "create"
83562
83827
  },
83828
+ "pipelineAnalytics.cancelRelocateMedia": {
83829
+ capName: "pipeline-analytics",
83830
+ capScope: "device",
83831
+ addonId: null,
83832
+ access: "create"
83833
+ },
83563
83834
  "pipelineAnalytics.cancelStorageMigrationMove": {
83564
83835
  capName: "pipeline-analytics",
83565
83836
  capScope: "device",
@@ -83626,6 +83897,12 @@ Object.freeze({
83626
83897
  addonId: null,
83627
83898
  access: "view"
83628
83899
  },
83900
+ "pipelineAnalytics.getGroup": {
83901
+ capName: "pipeline-analytics",
83902
+ capScope: "device",
83903
+ addonId: null,
83904
+ access: "view"
83905
+ },
83629
83906
  "pipelineAnalytics.getKeyEvents": {
83630
83907
  capName: "pipeline-analytics",
83631
83908
  capScope: "device",
@@ -83710,6 +83987,12 @@ Object.freeze({
83710
83987
  addonId: null,
83711
83988
  access: "view"
83712
83989
  },
83990
+ "pipelineAnalytics.listGroups": {
83991
+ capName: "pipeline-analytics",
83992
+ capScope: "device",
83993
+ addonId: null,
83994
+ access: "view"
83995
+ },
83713
83996
  "pipelineAnalytics.listOpsLog": {
83714
83997
  capName: "pipeline-analytics",
83715
83998
  capScope: "device",
@@ -83722,6 +84005,12 @@ Object.freeze({
83722
84005
  addonId: null,
83723
84006
  access: "view"
83724
84007
  },
84008
+ "pipelineAnalytics.listRelocateMediaJobs": {
84009
+ capName: "pipeline-analytics",
84010
+ capScope: "device",
84011
+ addonId: null,
84012
+ access: "view"
84013
+ },
83725
84014
  "pipelineAnalytics.listRetrainAnnotations": {
83726
84015
  capName: "pipeline-analytics",
83727
84016
  capScope: "device",
@@ -83800,6 +84089,12 @@ Object.freeze({
83800
84089
  addonId: null,
83801
84090
  access: "create"
83802
84091
  },
84092
+ "pipelineAnalytics.relocateMedia": {
84093
+ capName: "pipeline-analytics",
84094
+ capScope: "device",
84095
+ addonId: null,
84096
+ access: "create"
84097
+ },
83803
84098
  "pipelineAnalytics.restageRetrainTrack": {
83804
84099
  capName: "pipeline-analytics",
83805
84100
  capScope: "device",
@@ -86491,6 +86786,11 @@ Object.freeze({
86491
86786
  form: "single",
86492
86787
  optional: false
86493
86788
  }],
86789
+ "deviceManager.getBindingsBatch": [{
86790
+ name: "deviceIds",
86791
+ form: "array",
86792
+ optional: false
86793
+ }],
86494
86794
  "deviceManager.getChildren": [{
86495
86795
  name: "parentDeviceId",
86496
86796
  form: "single",
@@ -86536,6 +86836,11 @@ Object.freeze({
86536
86836
  form: "single",
86537
86837
  optional: false
86538
86838
  }],
86839
+ "deviceManager.getLinkedDevicesBatch": [{
86840
+ name: "deviceIds",
86841
+ form: "array",
86842
+ optional: false
86843
+ }],
86539
86844
  "deviceManager.getSettingsSchema": [{
86540
86845
  name: "deviceId",
86541
86846
  form: "single",
@@ -86556,6 +86861,11 @@ Object.freeze({
86556
86861
  form: "single",
86557
86862
  optional: false
86558
86863
  }],
86864
+ "deviceManager.listAll": [{
86865
+ name: "deviceIds",
86866
+ form: "array",
86867
+ optional: true
86868
+ }],
86559
86869
  "deviceManager.loadConfig": [{
86560
86870
  name: "deviceId",
86561
86871
  form: "single",
@@ -87129,6 +87439,11 @@ Object.freeze({
87129
87439
  form: "single",
87130
87440
  optional: false
87131
87441
  }],
87442
+ "pipelineAnalytics.getGroup": [{
87443
+ name: "deviceId",
87444
+ form: "single",
87445
+ optional: false
87446
+ }],
87132
87447
  "pipelineAnalytics.getKeyEvents": [{
87133
87448
  name: "deviceId",
87134
87449
  form: "single",
@@ -87184,6 +87499,11 @@ Object.freeze({
87184
87499
  form: "array",
87185
87500
  optional: false
87186
87501
  }],
87502
+ "pipelineAnalytics.listGroups": [{
87503
+ name: "deviceIds",
87504
+ form: "array",
87505
+ optional: false
87506
+ }],
87187
87507
  "pipelineAnalytics.listOpsLog": [{
87188
87508
  name: "deviceId",
87189
87509
  form: "single",