@camstack/addon-mqtt-broker 1.2.27 → 1.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.
@@ -5841,6 +5841,13 @@ var BaseAddon = class {
5841
5841
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5842
5842
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5843
5843
  _registeredCapNames = [];
5844
+ /**
5845
+ * True only after `readAddonStore` actually answered. Constructor
5846
+ * defaults look like stored config when the store is down — a forked
5847
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5848
+ * mode, 2026-08-25) is not "the operator chose this".
5849
+ */
5850
+ settingsStoreReady = false;
5844
5851
  /** Default config values. Provided via constructor. */
5845
5852
  defaults;
5846
5853
  constructor(defaults) {
@@ -6241,7 +6248,9 @@ var BaseAddon = class {
6241
6248
  ];
6242
6249
  let lastErr;
6243
6250
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6244
- return await settings.readAddonStore() ?? {};
6251
+ const stored = await settings.readAddonStore() ?? {};
6252
+ this.settingsStoreReady = true;
6253
+ return stored;
6245
6254
  } catch (err) {
6246
6255
  lastErr = err;
6247
6256
  const msg = err instanceof Error ? err.message : String(err);
@@ -6249,6 +6258,7 @@ var BaseAddon = class {
6249
6258
  if (attempt === delaysMs.length) break;
6250
6259
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6251
6260
  }
6261
+ this.settingsStoreReady = false;
6252
6262
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6253
6263
  return {};
6254
6264
  }
@@ -6660,7 +6670,7 @@ function method(input, output, options) {
6660
6670
  input,
6661
6671
  output,
6662
6672
  kind: options?.kind ?? "query",
6663
- auth: options?.auth ?? "protected",
6673
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6664
6674
  ...options?.access !== void 0 ? { access: options.access } : {},
6665
6675
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6666
6676
  timeoutMs: options?.timeoutMs
@@ -6680,7 +6690,7 @@ function systemMethod(input, output, options) {
6680
6690
  }
6681
6691
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6682
6692
  var VersionOutputSchema$1 = object({ version: string() });
6683
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6693
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6684
6694
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6685
6695
  DeviceType["Camera"] = "camera";
6686
6696
  DeviceType["Hub"] = "hub";
@@ -7001,7 +7011,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7001
7011
  }({});
7002
7012
  var StaticDirOutputSchema = object({ staticDir: string() });
7003
7013
  var VersionOutputSchema = object({ version: string() });
7004
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7014
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7005
7015
  /**
7006
7016
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7007
7017
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7615,24 +7625,6 @@ var RecordingRetentionSchema = object({
7615
7625
  maxSizeGb: number().min(0).optional()
7616
7626
  });
7617
7627
  /**
7618
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7619
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7620
- * previews at. Five graduated steps; absent on a config = `standard` (the
7621
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7622
- *
7623
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7624
- * Each window's index sidecar carries its own tile dims, so a camera whose
7625
- * preset changed over time renders every historical window at the dims it was
7626
- * written with.
7627
- */
7628
- var ScrubThumbnailPresetSchema = _enum([
7629
- "minimal",
7630
- "low",
7631
- "standard",
7632
- "high",
7633
- "max"
7634
- ]);
7635
- /**
7636
7628
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7637
7629
  *
7638
7630
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7640,7 +7632,11 @@ var ScrubThumbnailPresetSchema = _enum([
7640
7632
  * other field is a storage knob (profiles, segment length, retention, scrub).
7641
7633
  *
7642
7634
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7643
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7635
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7636
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7637
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7638
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7639
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7644
7640
  * A stale caller must fail loudly — silently stripping its legacy intent would
7645
7641
  * persist a band-less config, i.e. silently stop recording the camera.
7646
7642
  */
@@ -7663,14 +7659,7 @@ var RecordingConfigSchema = object({
7663
7659
  * "off" is the absence of a covering band, never a band value.
7664
7660
  */
7665
7661
  bands: array(RecordingBandSchema).default([]),
7666
- retention: RecordingRetentionSchema.optional(),
7667
- /**
7668
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7669
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7670
- * windows only — existing sheets are immutable, and each window's index
7671
- * carries its own tile dims so mixed-preset history renders correctly.
7672
- */
7673
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7662
+ retention: RecordingRetentionSchema.optional()
7674
7663
  }).strict();
7675
7664
  /**
7676
7665
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7746,10 +7735,11 @@ var RelocateFootageInputSchema = object({
7746
7735
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7747
7736
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7748
7737
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7749
- var StorageMigrationMediaMoveInputSchema = object({
7738
+ var RelocateMediaInputSchema = object({
7750
7739
  toLocationId: string(),
7751
7740
  throttleMbps: number().min(1).max(1e3).optional()
7752
- }).extend({ leaseId: string().min(1) });
7741
+ });
7742
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7753
7743
  /** The independently selectable logical storage classes. `recordings`
7754
7744
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7755
7745
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8044,7 +8034,26 @@ var LabelDefinitionSchema = object({
8044
8034
  description: string().optional(),
8045
8035
  icon: string().optional()
8046
8036
  });
8047
- var ClassMapDefinitionSchema = object({
8037
+ /**
8038
+ * Wire schema for a per-model CATALOG classMap override
8039
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8040
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8041
+ * detection pipeline executor actually routes.
8042
+ *
8043
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8044
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8045
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8046
+ * enum) — the two used to share the name `ClassMapDefinition`/
8047
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8048
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8049
+ * are not: it is two different concepts colliding on a name. Keep this type
8050
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8051
+ * would either narrow every `ClassMapDefinition` consumer to the four
8052
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8053
+ * schema exists for (see the "rejects a classMap whose target is not a
8054
+ * detection macro" test in `model-catalog-schema.test.ts`).
8055
+ */
8056
+ var DetectionCatalogClassMapSchema = object({
8048
8057
  mapping: record(string(), _enum([
8049
8058
  "person",
8050
8059
  "vehicle",
@@ -8136,6 +8145,12 @@ var ModelVariantGroupSchema = object({
8136
8145
  */
8137
8146
  resolution: number().int().positive().optional()
8138
8147
  });
8148
+ var ModelProviderIdSchema = _enum([
8149
+ "camstack",
8150
+ "frigate",
8151
+ "scrypted",
8152
+ "custom"
8153
+ ]);
8139
8154
  var ModelCatalogEntrySchema = object({
8140
8155
  id: string(),
8141
8156
  name: string(),
@@ -8233,11 +8248,17 @@ var ModelCatalogEntrySchema = object({
8233
8248
  */
8234
8249
  group: ModelVariantGroupSchema.optional(),
8235
8250
  /**
8251
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8252
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8253
+ * persisted before this field existed (`inferModelProvider` fills those).
8254
+ */
8255
+ provider: ModelProviderIdSchema.optional(),
8256
+ /**
8236
8257
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8237
8258
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8238
8259
  * labels already ARE the CamStack macros (Scrypted identity map).
8239
8260
  */
8240
- classMap: ClassMapDefinitionSchema.optional()
8261
+ classMap: DetectionCatalogClassMapSchema.optional()
8241
8262
  });
8242
8263
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8243
8264
  format: literal("openvino"),
@@ -8267,7 +8288,7 @@ var ModelConvertMetadataSchema = object({
8267
8288
  "segmentation"
8268
8289
  ]),
8269
8290
  faceAlignment: boolean().optional(),
8270
- classMap: ClassMapDefinitionSchema.optional()
8291
+ classMap: DetectionCatalogClassMapSchema.optional()
8271
8292
  });
8272
8293
  var ConvertResultSchema = object({
8273
8294
  entry: ModelCatalogEntrySchema,
@@ -9130,7 +9151,7 @@ var AddonPageDeclarationSchema = object({
9130
9151
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9131
9152
  sectionLabel: string().optional()
9132
9153
  });
9133
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9154
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9134
9155
  var AddonHttpRouteSchema = object({
9135
9156
  method: _enum([
9136
9157
  "GET",
@@ -9365,7 +9386,7 @@ var WidgetMetadataSchema = object({
9365
9386
  defaultColumns: number().int().min(1).max(12).default(6),
9366
9387
  defaultRows: number().int().min(1).max(12).default(1)
9367
9388
  });
9368
- method(_void(), array(WidgetMetadataSchema).readonly());
9389
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9369
9390
  /**
9370
9391
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9371
9392
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -10936,7 +10957,7 @@ var CustomModelDescriptorSchema = object({
10936
10957
  stepId: string(),
10937
10958
  entry: ModelCatalogEntrySchema
10938
10959
  });
10939
- method(_void(), array(CustomModelDescriptorSchema).readonly());
10960
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
10940
10961
  /**
10941
10962
  * Query filter for settings-store collections.
10942
10963
  */
@@ -11023,7 +11044,8 @@ method(object({
11023
11044
  }), _void(), { kind: "mutation" }), method(object({
11024
11045
  namespace: string().optional(),
11025
11046
  collection: string(),
11026
- filter: QueryFilterSchema.optional()
11047
+ filter: QueryFilterSchema.optional(),
11048
+ columns: array(string()).readonly().optional()
11027
11049
  }), array(SettingsRecordSchema).readonly()), method(object({
11028
11050
  namespace: string().optional(),
11029
11051
  collection: string(),
@@ -11086,46 +11108,87 @@ var EngineInfoSchema = object({
11086
11108
  kind: _enum(["relational", "vector"]),
11087
11109
  displayName: string()
11088
11110
  });
11089
- method(_void(), EngineInfoSchema), method(object({
11111
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11090
11112
  namespace: string().optional(),
11091
11113
  collection: string(),
11092
11114
  key: string()
11093
- }), unknown()), method(object({
11115
+ }), unknown(), { auth: "admin" }), method(object({
11094
11116
  namespace: string().optional(),
11095
11117
  collection: string(),
11096
11118
  key: string(),
11097
11119
  value: unknown()
11098
- }), _void(), { kind: "mutation" }), method(object({
11120
+ }), _void(), {
11121
+ kind: "mutation",
11122
+ auth: "admin"
11123
+ }), method(object({
11099
11124
  namespace: string().optional(),
11100
11125
  collection: string(),
11101
- filter: QueryFilterSchema.optional()
11102
- }), array(SettingsRecordSchema).readonly()), method(object({
11126
+ filter: QueryFilterSchema.optional(),
11127
+ /**
11128
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11129
+ *
11130
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11131
+ * was wrong — corrected 2026-08-26 after the hop map
11132
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11133
+ * There is **no Zod parse at all** between the door and the engine: the
11134
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11135
+ * field declared here reaches `SqliteSettingsBackend` either way.
11136
+ *
11137
+ * What actually lost `columns` was the THIRD declaration of this shape:
11138
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11139
+ * interface the engine destructures from. The field existed on both
11140
+ * schemas and the engine still never read it, because nothing checks a
11141
+ * registered provider against `InferProvider<cap>` —
11142
+ * `ProviderRegistration.provider` is typed `object`.
11143
+ *
11144
+ * It is declared here anyway, and must stay in step with
11145
+ * `settings-store.query`: a caller reading only the cap definitions has
11146
+ * to be able to see that this call carries a projection.
11147
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11148
+ */
11149
+ columns: array(string()).readonly().optional()
11150
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11103
11151
  namespace: string().optional(),
11104
11152
  collection: string(),
11105
11153
  record: SettingsRecordSchema
11106
- }), _void(), { kind: "mutation" }), method(object({
11154
+ }), _void(), {
11155
+ kind: "mutation",
11156
+ auth: "admin"
11157
+ }), method(object({
11107
11158
  namespace: string().optional(),
11108
11159
  collection: string(),
11109
11160
  id: string(),
11110
11161
  data: record(string(), unknown())
11111
- }), _void(), { kind: "mutation" }), method(object({
11162
+ }), _void(), {
11163
+ kind: "mutation",
11164
+ auth: "admin"
11165
+ }), method(object({
11112
11166
  namespace: string().optional(),
11113
11167
  collection: string(),
11114
11168
  key: string()
11115
- }), _void(), { kind: "mutation" }), method(object({
11169
+ }), _void(), {
11170
+ kind: "mutation",
11171
+ auth: "admin"
11172
+ }), method(object({
11116
11173
  namespace: string().optional(),
11117
11174
  collection: string(),
11118
11175
  filter: MutationFilterSchema
11119
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11176
+ }), object({ deleted: number().int() }), {
11177
+ kind: "mutation",
11178
+ auth: "admin"
11179
+ }), method(object({
11120
11180
  namespace: string().optional(),
11121
11181
  collection: string(),
11122
11182
  filter: MutationFilterSchema,
11123
11183
  data: record(string(), unknown())
11124
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11184
+ }), object({ updated: number().int() }), {
11185
+ kind: "mutation",
11186
+ auth: "admin"
11187
+ }), method(object({
11125
11188
  namespace: string().optional(),
11126
11189
  collection: string(),
11127
11190
  filter: QueryFilterSchema.optional()
11128
- }), number()), method(object({
11191
+ }), number(), { auth: "admin" }), method(object({
11129
11192
  namespace: string().optional(),
11130
11193
  collection: string(),
11131
11194
  field: string(),
@@ -11135,15 +11198,18 @@ method(_void(), EngineInfoSchema), method(object({
11135
11198
  }), array(object({
11136
11199
  bucket: number().int(),
11137
11200
  count: number().int()
11138
- })).readonly()), method(object({
11201
+ })).readonly(), { auth: "admin" }), method(object({
11139
11202
  namespace: string().optional(),
11140
11203
  collection: string()
11141
- }), boolean()), method(object({
11204
+ }), boolean(), { auth: "admin" }), method(object({
11142
11205
  namespace: string().optional(),
11143
11206
  collection: string(),
11144
11207
  columns: array(CollectionColumnSchema).readonly(),
11145
11208
  indexes: array(CollectionIndexSchema).readonly().optional()
11146
- }), _void(), { kind: "mutation" });
11209
+ }), _void(), {
11210
+ kind: "mutation",
11211
+ auth: "admin"
11212
+ });
11147
11213
  /**
11148
11214
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11149
11215
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -11809,6 +11875,27 @@ var LinkedDeviceSchema = object({
11809
11875
  features: array(string()),
11810
11876
  producesTrackedEvents: boolean().optional()
11811
11877
  });
11878
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11879
+ * The batch answer needs the tag; the single-device answer already has it
11880
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11881
+ var LinkedDevicesForDeviceSchema = object({
11882
+ deviceId: number(),
11883
+ mode: LinkedDevicesModeSchema,
11884
+ devices: array(LinkedDeviceSchema)
11885
+ });
11886
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11887
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11888
+ * object literal is exactly how the three drift apart. */
11889
+ var DeviceBindingsForDeviceSchema = object({
11890
+ deviceId: number(),
11891
+ entries: array(object({
11892
+ capName: string(),
11893
+ kind: _enum(["native", "wrapped"]),
11894
+ providerAddonId: string(),
11895
+ providerNodeId: string(),
11896
+ nativeAddonId: string()
11897
+ }))
11898
+ });
11812
11899
  var SavedDeviceRowSchema = object({
11813
11900
  /** Numeric id reserved at allocateDeviceId time. */
11814
11901
  id: number(),
@@ -12034,11 +12121,25 @@ method(object({
12034
12121
  projection: _enum(["full", "slim"]).optional(),
12035
12122
  /** Return only camera devices. Filtering server-side instead of
12036
12123
  * shipping 293 rows to find 12. */
12037
- isCamera: boolean().optional()
12124
+ isCamera: boolean().optional(),
12125
+ /**
12126
+ * Return only these device ids. For the caller that already KNOWS the
12127
+ * handful it wants and needs a field the id-bearing answer does not
12128
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12129
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12130
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12131
+ * refetches on the reconcile interval, on a phone.
12132
+ *
12133
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12134
+ * keys rather than rejecting them (verified against the live hub
12135
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12136
+ * it answers today and the caller filters as it already does.
12137
+ */
12138
+ deviceIds: array(number()).optional()
12038
12139
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12039
12140
  mode: LinkedDevicesModeSchema,
12040
12141
  devices: array(LinkedDeviceSchema)
12041
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12142
+ })), 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({
12042
12143
  deviceId: number(),
12043
12144
  values: record(string(), unknown())
12044
12145
  }), object({ success: literal(true) }), {
@@ -12065,25 +12166,7 @@ method(object({
12065
12166
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12066
12167
  kind: "mutation",
12067
12168
  auth: "admin"
12068
- }), method(object({ deviceId: number() }), object({
12069
- deviceId: number(),
12070
- entries: array(object({
12071
- capName: string(),
12072
- kind: _enum(["native", "wrapped"]),
12073
- providerAddonId: string(),
12074
- providerNodeId: string(),
12075
- nativeAddonId: string()
12076
- }))
12077
- })), method(object({}), array(object({
12078
- deviceId: number(),
12079
- entries: array(object({
12080
- capName: string(),
12081
- kind: _enum(["native", "wrapped"]),
12082
- providerAddonId: string(),
12083
- providerNodeId: string(),
12084
- nativeAddonId: string()
12085
- }))
12086
- }))), method(object({
12169
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12087
12170
  deviceId: number(),
12088
12171
  capName: string(),
12089
12172
  wrapperAddonId: string(),
@@ -12254,7 +12337,7 @@ method(object({
12254
12337
  crop: _instanceof(Uint8Array),
12255
12338
  width: number(),
12256
12339
  height: number()
12257
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12340
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12258
12341
  /**
12259
12342
  * filesystem-browse — per-node capability for browsing the node's local
12260
12343
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12547,19 +12630,22 @@ method(LlmGenerateBaseInputSchema.extend({
12547
12630
  runtime: ManagedRuntimeConfigSchema,
12548
12631
  /** The managed profile's timeout, threaded by the hub provider. */
12549
12632
  timeoutMs: number().int().positive().optional()
12550
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12633
+ }), LlmGenerateResultSchema, {
12634
+ kind: "mutation",
12635
+ auth: "admin"
12636
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12551
12637
  kind: "mutation",
12552
12638
  auth: "admin"
12553
12639
  }), method(object({}), _void(), {
12554
12640
  kind: "mutation",
12555
12641
  auth: "admin"
12556
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12642
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12557
12643
  kind: "mutation",
12558
12644
  auth: "admin"
12559
12645
  }), method(object({ file: string() }), _void(), {
12560
12646
  kind: "mutation",
12561
12647
  auth: "admin"
12562
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12648
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12563
12649
  /**
12564
12650
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12565
12651
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14474,12 +14560,15 @@ var NcOccupancyConditionSchema = object({
14474
14560
  * there is no second switch that can disagree with the first and every rule
14475
14561
  * authored before the decision migrates for free (`audioModeOf`):
14476
14562
  *
14477
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14478
- * classifier labels with one of them. No window, no percentage:
14479
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14480
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14481
- * the analyzer's (`classificationMinScore`, per device) — a label only
14482
- * reaches this condition if the classifier was already confident enough.
14563
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14564
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14565
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14566
+ * frames is the wrong question for a classifier that labels 1–3 frames
14567
+ * per episode. The count window is the brake that drops a single-frame
14568
+ * false positive; the rule's own `throttle` cooldown is the other. The
14569
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14570
+ * per device) — a label only reaches this condition if the classifier was
14571
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14483
14572
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14484
14573
  * the condition: at least `hitPercent`% of the samples over
14485
14574
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14506,14 +14595,22 @@ var NcOccupancyConditionSchema = object({
14506
14595
  * an operator who typed `dog` mean the same thing.
14507
14596
  */
14508
14597
  var NcAudioConditionSchema = object({
14509
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14598
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14510
14599
  labels: array(string().min(1)).min(1).optional(),
14511
14600
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14512
14601
  dbThreshold: number().min(-96).max(0).optional(),
14513
14602
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14514
14603
  hitPercent: number().int().min(1).max(100).default(60),
14515
14604
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14516
- samplingSeconds: number().int().min(1).max(300).default(10)
14605
+ samplingSeconds: number().int().min(1).max(300).default(10),
14606
+ /**
14607
+ * LABEL MODE: how many labelled frames must land inside
14608
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14609
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14610
+ */
14611
+ confirmHits: number().int().min(1).max(20).optional(),
14612
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14613
+ confirmWindowSec: number().int().min(1).max(60).optional()
14517
14614
  });
14518
14615
  /**
14519
14616
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16040,7 +16137,7 @@ var OauthIntegrationDescriptorSchema = object({
16040
16137
  */
16041
16138
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16042
16139
  });
16043
- method(_void(), OauthIntegrationDescriptorSchema);
16140
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16044
16141
  /**
16045
16142
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16046
16143
  * per-frame detections emitted by the pipeline runner into tracked
@@ -16887,6 +16984,46 @@ var RecentTracksPageSchema = object({
16887
16984
  /** Cursor for the next page, or null when this page is the last. */
16888
16985
  nextCursor: string().nullable()
16889
16986
  });
16987
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
16988
+ var LIST_GROUPS_MAX_LIMIT = 100;
16989
+ var AnalyticsGroupRecordSchema = object({
16990
+ id: string(),
16991
+ deviceId: number().int(),
16992
+ openedAt: number().int(),
16993
+ closedAt: number().int(),
16994
+ timestamp: number().int(),
16995
+ memberCount: number().int(),
16996
+ memberTrackIds: array(string()).readonly(),
16997
+ className: string(),
16998
+ classes: array(string()).readonly(),
16999
+ /** Relative event-media path, or null when the group has no picture yet. */
17000
+ mediaUrl: string().nullable(),
17001
+ singleton: boolean()
17002
+ });
17003
+ var AnalyticsGroupMemberSchema = object({
17004
+ trackId: string(),
17005
+ deviceId: number().int(),
17006
+ className: string(),
17007
+ firstSeen: number().int(),
17008
+ lastSeen: number().int(),
17009
+ mediaUrl: string().nullable()
17010
+ });
17011
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17012
+ var ListGroupsQueryInput = object({
17013
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17014
+ deviceIds: array(number()),
17015
+ /** Window lower bound on `closedAt` (inclusive). */
17016
+ since: number().optional(),
17017
+ /** Window upper bound on `openedAt` (inclusive). */
17018
+ until: number().optional(),
17019
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17020
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17021
+ cursor: string().optional()
17022
+ });
17023
+ var ListGroupsPageSchema = object({
17024
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17025
+ nextCursor: string().nullable()
17026
+ });
16890
17027
  var KeyEventQueryInput = object({
16891
17028
  deviceId: number(),
16892
17029
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16962,7 +17099,9 @@ var TrackCascadeCountsSchema = object({
16962
17099
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
16963
17100
  plates: number().int(),
16964
17101
  /** Per-track CLIP search vectors removed (best-effort). */
16965
- embeddings: number().int()
17102
+ embeddings: number().int(),
17103
+ /** Group membership + group rows removed with their last member (best-effort). */
17104
+ groups: number().int()
16966
17105
  });
16967
17106
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
16968
17107
  var DiskReconcileCountsSchema = object({
@@ -17108,7 +17247,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17108
17247
  * stationary registry). Default false: the timeline lists passages,
17109
17248
  * not parking records (operator decision, 2026-08-15). */
17110
17249
  includeStationary: boolean().optional()
17111
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17250
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17251
+ deviceId: number(),
17252
+ groupId: string().min(1)
17253
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17112
17254
  kind: "mutation",
17113
17255
  auth: "admin"
17114
17256
  }), 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({
@@ -17190,6 +17332,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17190
17332
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17191
17333
  kind: "mutation",
17192
17334
  auth: "admin"
17335
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17336
+ kind: "mutation",
17337
+ auth: "admin"
17338
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17339
+ kind: "query",
17340
+ auth: "admin"
17341
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17342
+ kind: "mutation",
17343
+ auth: "admin"
17193
17344
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17194
17345
  kind: "query",
17195
17346
  auth: "admin"
@@ -17344,6 +17495,11 @@ object({
17344
17495
  "jpeg"
17345
17496
  ])
17346
17497
  });
17498
+ /**
17499
+ * Process-local frame identity. It is serializable so it can ride an in-process
17500
+ * capability call, but `registryId` deliberately prevents resolution in any
17501
+ * other process or execution group.
17502
+ */
17347
17503
  var FrameRefSchema = object({
17348
17504
  registryId: string().min(1),
17349
17505
  id: string().min(1),
@@ -17418,7 +17574,8 @@ var PipelineModelOptionSchema = object({
17418
17574
  sizeMB: number()
17419
17575
  })),
17420
17576
  group: ModelVariantGroupSchema.optional(),
17421
- legacy: boolean().optional()
17577
+ legacy: boolean().optional(),
17578
+ provider: ModelProviderIdSchema.optional()
17422
17579
  });
17423
17580
  var ConfigFieldBridge = custom();
17424
17581
  var PipelineAddonSchemaSchema = object({
@@ -19508,7 +19665,7 @@ method(object({
19508
19665
  * linking rather than produce an eternal token.
19509
19666
  */
19510
19667
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19511
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19668
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19512
19669
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19513
19670
  providerId: string().min(1),
19514
19671
  displayName: string().min(1),
@@ -19603,10 +19760,13 @@ var EvictResultSchema = object({
19603
19760
  /** True when the provider has nothing left it is willing to drop on this location. */
19604
19761
  exhausted: boolean()
19605
19762
  });
19606
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19763
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19607
19764
  locationId: string(),
19608
19765
  targetBytes: number().int().positive()
19609
- }), EvictResultSchema, { kind: "mutation" });
19766
+ }), EvictResultSchema, {
19767
+ kind: "mutation",
19768
+ auth: "admin"
19769
+ });
19610
19770
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19611
19771
  kind: "mutation",
19612
19772
  auth: "admin"
@@ -19666,26 +19826,50 @@ var ReadChunkInputSchema = object({
19666
19826
  length: number()
19667
19827
  });
19668
19828
  var EndDownloadInputSchema = object({ downloadId: string() });
19669
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19829
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19670
19830
  location: StorageLocationSchema,
19671
19831
  relativePath: string()
19672
- }), string()), method(object({
19832
+ }), string(), { auth: "admin" }), method(object({
19673
19833
  location: StorageLocationSchema,
19674
19834
  relativePath: string(),
19675
19835
  data: _instanceof(Uint8Array)
19676
- }), _void(), { kind: "mutation" }), method(object({
19836
+ }), _void(), {
19837
+ kind: "mutation",
19838
+ auth: "admin"
19839
+ }), method(object({
19677
19840
  location: StorageLocationSchema,
19678
19841
  relativePath: string()
19679
- }), _instanceof(Uint8Array)), method(object({
19842
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19680
19843
  location: StorageLocationSchema,
19681
19844
  relativePath: string()
19682
- }), boolean()), method(object({
19845
+ }), boolean(), { auth: "admin" }), method(object({
19683
19846
  location: StorageLocationSchema,
19684
19847
  prefix: string().optional()
19685
- }), array(string()).readonly()), method(object({
19848
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19686
19849
  location: StorageLocationSchema,
19687
19850
  relativePath: string()
19688
- }), _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" });
19851
+ }), _void(), {
19852
+ kind: "mutation",
19853
+ auth: "admin"
19854
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
19855
+ kind: "mutation",
19856
+ auth: "admin"
19857
+ }), method(WriteChunkInputSchema, _void(), {
19858
+ kind: "mutation",
19859
+ auth: "admin"
19860
+ }), method(FinalizeUploadInputSchema, _void(), {
19861
+ kind: "mutation",
19862
+ auth: "admin"
19863
+ }), method(AbortUploadInputSchema, _void(), {
19864
+ kind: "mutation",
19865
+ auth: "admin"
19866
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
19867
+ kind: "mutation",
19868
+ auth: "admin"
19869
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
19870
+ kind: "mutation",
19871
+ auth: "admin"
19872
+ });
19689
19873
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19690
19874
  var ProfileSettingsSchemaBridge = unknown().nullable();
19691
19875
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -19943,7 +20127,8 @@ method(object({
19943
20127
  access: "create"
19944
20128
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
19945
20129
  kind: "mutation",
19946
- access: "view"
20130
+ access: "view",
20131
+ auth: "admin"
19947
20132
  }), method(object({
19948
20133
  /** Required — the user the assertion belongs to (verified). */
19949
20134
  userId: string(),
@@ -19951,10 +20136,12 @@ method(object({
19951
20136
  response: record(string(), unknown())
19952
20137
  }), object({ verified: boolean() }), {
19953
20138
  kind: "mutation",
19954
- access: "view"
20139
+ access: "view",
20140
+ auth: "admin"
19955
20141
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19956
20142
  kind: "mutation",
19957
- access: "view"
20143
+ access: "view",
20144
+ auth: "admin"
19958
20145
  }), method(object({
19959
20146
  /** AuthenticationResponseJSON from the browser. */
19960
20147
  response: record(string(), unknown()) }), object({
@@ -19962,7 +20149,8 @@ response: record(string(), unknown()) }), object({
19962
20149
  userId: string().nullable()
19963
20150
  }), {
19964
20151
  kind: "mutation",
19965
- access: "view"
20152
+ access: "view",
20153
+ auth: "admin"
19966
20154
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19967
20155
  userId: string(),
19968
20156
  credentialId: string()
@@ -20134,7 +20322,19 @@ var VectorStatsResultSchema = object({
20134
20322
  /** False when the backend ranks approximately. */
20135
20323
  exact: boolean()
20136
20324
  });
20137
- 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);
20325
+ method(VectorDeclareIndexInputSchema, _void(), {
20326
+ kind: "mutation",
20327
+ auth: "admin"
20328
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20329
+ kind: "mutation",
20330
+ auth: "admin"
20331
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20332
+ kind: "mutation",
20333
+ auth: "admin"
20334
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20335
+ kind: "mutation",
20336
+ auth: "admin"
20337
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20138
20338
  var ClipSchema = object({
20139
20339
  /** Opaque, provider-namespaced id. The default provider encodes the time
20140
20340
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21857,7 +22057,27 @@ var MediaFileLiteSchema$1 = object({
21857
22057
  sizeBytes: number(),
21858
22058
  timestamp: number()
21859
22059
  });
21860
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22060
+ method(object({
22061
+ /**
22062
+ * Inline {@link IdentitySchema.coverBase64} on every row.
22063
+ *
22064
+ * Default `false`, the same inversion `listRecentFaces` and
22065
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
22066
+ * why the burden belongs on the caller that WANTS the bytes). Measured
22067
+ * on the live hub the same day: four identities cost 40,979 B with the
22068
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
22069
+ * four times and the viewer holds at `staleTime: 30_000`.
22070
+ *
22071
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
22072
+ * the `event-media` plane serves that key `immutable` with an ETag.
22073
+ *
22074
+ * **This is an INPUT field, so it does not reach the addon until the
22075
+ * next train** — the hub router validates cap inputs against its own
22076
+ * compiled Zod and strips a key it does not know. Until then the
22077
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
22078
+ * is what ships, and the opt-in becomes reachable when the train lands.
22079
+ */
22080
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
21861
22081
  kind: "mutation",
21862
22082
  auth: "admin"
21863
22083
  }), method(object({
@@ -24002,7 +24222,14 @@ var PlateInfoSchema = object({
24002
24222
  plateBbox: BoundingBoxSchema.optional(),
24003
24223
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
24004
24224
  keyFrameMediaKey: string().optional(),
24005
- base64: string().optional()
24225
+ base64: string().optional(),
24226
+ /**
24227
+ * Same crop as a data-plane URL, always present when the plate has a stored
24228
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24229
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24230
+ * left at its `true` default.
24231
+ */
24232
+ cropUrl: string().optional()
24006
24233
  });
24007
24234
  var MediaFileLiteSchema = object({
24008
24235
  key: string(),
@@ -24020,14 +24247,34 @@ var PlateClusterSchema = object({
24020
24247
  });
24021
24248
  method(object({
24022
24249
  deviceId: number().int().optional(),
24023
- limit: number().int().positive().optional()
24250
+ limit: number().int().positive().optional(),
24251
+ /**
24252
+ * Inline the base64 crop on every row. Default `true` — the existing
24253
+ * behaviour, kept so no caller breaks.
24254
+ *
24255
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24256
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24257
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24258
+ * metadata without them — and the browser then caches the images.
24259
+ *
24260
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24261
+ * plates were the one gallery list left without it.
24262
+ *
24263
+ * **This is an INPUT field, so it does not reach the addon until the
24264
+ * next train.** The hub router validates cap inputs against its own
24265
+ * compiled Zod and strips a key it does not know. Until the train
24266
+ * ships, sending `false` is harmless and keeps the crops inline.
24267
+ */
24268
+ includeCrops: boolean().optional()
24024
24269
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
24025
24270
  deviceId: number().int(),
24026
24271
  trackId: string()
24027
24272
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
24028
24273
  text: string().min(1),
24029
24274
  maxDistance: number().int().min(0).optional(),
24030
- limit: number().int().positive().optional()
24275
+ limit: number().int().positive().optional(),
24276
+ /** See `listPlates.includeCrops`. Default `true`. */
24277
+ includeCrops: boolean().optional()
24031
24278
  }), array(PlateInfoSchema).readonly()), method(object({
24032
24279
  maxDistance: number().int().min(0).optional(),
24033
24280
  minClusterSize: number().int().min(2).optional(),
@@ -24041,7 +24288,13 @@ method(object({
24041
24288
  }), method(object({ plateId: string() }), _void(), {
24042
24289
  kind: "mutation",
24043
24290
  auth: "admin"
24044
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24291
+ }), method(object({
24292
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
24293
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
24294
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
24295
+ * INPUT field: stripped by the hub router until the train ships, which
24296
+ * resolves to `false` and is exactly the intended default. */
24297
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24045
24298
  kind: "mutation",
24046
24299
  auth: "admin"
24047
24300
  }), method(object({
@@ -27642,6 +27895,12 @@ Object.freeze({
27642
27895
  addonId: null,
27643
27896
  access: "view"
27644
27897
  },
27898
+ "deviceManager.getBindingsBatch": {
27899
+ capName: "device-manager",
27900
+ capScope: "system",
27901
+ addonId: null,
27902
+ access: "view"
27903
+ },
27645
27904
  "deviceManager.getChildren": {
27646
27905
  capName: "device-manager",
27647
27906
  capScope: "system",
@@ -27702,6 +27961,12 @@ Object.freeze({
27702
27961
  addonId: null,
27703
27962
  access: "view"
27704
27963
  },
27964
+ "deviceManager.getLinkedDevicesBatch": {
27965
+ capName: "device-manager",
27966
+ capScope: "system",
27967
+ addonId: null,
27968
+ access: "view"
27969
+ },
27705
27970
  "deviceManager.getRoleDisplayDefaults": {
27706
27971
  capName: "device-manager",
27707
27972
  capScope: "system",
@@ -29406,6 +29671,12 @@ Object.freeze({
29406
29671
  addonId: null,
29407
29672
  access: "create"
29408
29673
  },
29674
+ "pipelineAnalytics.cancelRelocateMedia": {
29675
+ capName: "pipeline-analytics",
29676
+ capScope: "device",
29677
+ addonId: null,
29678
+ access: "create"
29679
+ },
29409
29680
  "pipelineAnalytics.cancelStorageMigrationMove": {
29410
29681
  capName: "pipeline-analytics",
29411
29682
  capScope: "device",
@@ -29472,6 +29743,12 @@ Object.freeze({
29472
29743
  addonId: null,
29473
29744
  access: "view"
29474
29745
  },
29746
+ "pipelineAnalytics.getGroup": {
29747
+ capName: "pipeline-analytics",
29748
+ capScope: "device",
29749
+ addonId: null,
29750
+ access: "view"
29751
+ },
29475
29752
  "pipelineAnalytics.getKeyEvents": {
29476
29753
  capName: "pipeline-analytics",
29477
29754
  capScope: "device",
@@ -29556,6 +29833,12 @@ Object.freeze({
29556
29833
  addonId: null,
29557
29834
  access: "view"
29558
29835
  },
29836
+ "pipelineAnalytics.listGroups": {
29837
+ capName: "pipeline-analytics",
29838
+ capScope: "device",
29839
+ addonId: null,
29840
+ access: "view"
29841
+ },
29559
29842
  "pipelineAnalytics.listOpsLog": {
29560
29843
  capName: "pipeline-analytics",
29561
29844
  capScope: "device",
@@ -29568,6 +29851,12 @@ Object.freeze({
29568
29851
  addonId: null,
29569
29852
  access: "view"
29570
29853
  },
29854
+ "pipelineAnalytics.listRelocateMediaJobs": {
29855
+ capName: "pipeline-analytics",
29856
+ capScope: "device",
29857
+ addonId: null,
29858
+ access: "view"
29859
+ },
29571
29860
  "pipelineAnalytics.listRetrainAnnotations": {
29572
29861
  capName: "pipeline-analytics",
29573
29862
  capScope: "device",
@@ -29646,6 +29935,12 @@ Object.freeze({
29646
29935
  addonId: null,
29647
29936
  access: "create"
29648
29937
  },
29938
+ "pipelineAnalytics.relocateMedia": {
29939
+ capName: "pipeline-analytics",
29940
+ capScope: "device",
29941
+ addonId: null,
29942
+ access: "create"
29943
+ },
29649
29944
  "pipelineAnalytics.restageRetrainTrack": {
29650
29945
  capName: "pipeline-analytics",
29651
29946
  capScope: "device",
@@ -32337,6 +32632,11 @@ Object.freeze({
32337
32632
  form: "single",
32338
32633
  optional: false
32339
32634
  }],
32635
+ "deviceManager.getBindingsBatch": [{
32636
+ name: "deviceIds",
32637
+ form: "array",
32638
+ optional: false
32639
+ }],
32340
32640
  "deviceManager.getChildren": [{
32341
32641
  name: "parentDeviceId",
32342
32642
  form: "single",
@@ -32382,6 +32682,11 @@ Object.freeze({
32382
32682
  form: "single",
32383
32683
  optional: false
32384
32684
  }],
32685
+ "deviceManager.getLinkedDevicesBatch": [{
32686
+ name: "deviceIds",
32687
+ form: "array",
32688
+ optional: false
32689
+ }],
32385
32690
  "deviceManager.getSettingsSchema": [{
32386
32691
  name: "deviceId",
32387
32692
  form: "single",
@@ -32402,6 +32707,11 @@ Object.freeze({
32402
32707
  form: "single",
32403
32708
  optional: false
32404
32709
  }],
32710
+ "deviceManager.listAll": [{
32711
+ name: "deviceIds",
32712
+ form: "array",
32713
+ optional: true
32714
+ }],
32405
32715
  "deviceManager.loadConfig": [{
32406
32716
  name: "deviceId",
32407
32717
  form: "single",
@@ -32975,6 +33285,11 @@ Object.freeze({
32975
33285
  form: "single",
32976
33286
  optional: false
32977
33287
  }],
33288
+ "pipelineAnalytics.getGroup": [{
33289
+ name: "deviceId",
33290
+ form: "single",
33291
+ optional: false
33292
+ }],
32978
33293
  "pipelineAnalytics.getKeyEvents": [{
32979
33294
  name: "deviceId",
32980
33295
  form: "single",
@@ -33030,6 +33345,11 @@ Object.freeze({
33030
33345
  form: "array",
33031
33346
  optional: false
33032
33347
  }],
33348
+ "pipelineAnalytics.listGroups": [{
33349
+ name: "deviceIds",
33350
+ form: "array",
33351
+ optional: false
33352
+ }],
33033
33353
  "pipelineAnalytics.listOpsLog": [{
33034
33354
  name: "deviceId",
33035
33355
  form: "single",