@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.
@@ -5846,6 +5846,13 @@ var BaseAddon = class {
5846
5846
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5847
5847
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5848
5848
  _registeredCapNames = [];
5849
+ /**
5850
+ * True only after `readAddonStore` actually answered. Constructor
5851
+ * defaults look like stored config when the store is down — a forked
5852
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5853
+ * mode, 2026-08-25) is not "the operator chose this".
5854
+ */
5855
+ settingsStoreReady = false;
5849
5856
  /** Default config values. Provided via constructor. */
5850
5857
  defaults;
5851
5858
  constructor(defaults) {
@@ -6246,7 +6253,9 @@ var BaseAddon = class {
6246
6253
  ];
6247
6254
  let lastErr;
6248
6255
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6249
- return await settings.readAddonStore() ?? {};
6256
+ const stored = await settings.readAddonStore() ?? {};
6257
+ this.settingsStoreReady = true;
6258
+ return stored;
6250
6259
  } catch (err) {
6251
6260
  lastErr = err;
6252
6261
  const msg = err instanceof Error ? err.message : String(err);
@@ -6254,6 +6263,7 @@ var BaseAddon = class {
6254
6263
  if (attempt === delaysMs.length) break;
6255
6264
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6256
6265
  }
6266
+ this.settingsStoreReady = false;
6257
6267
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6258
6268
  return {};
6259
6269
  }
@@ -6665,7 +6675,7 @@ function method(input, output, options) {
6665
6675
  input,
6666
6676
  output,
6667
6677
  kind: options?.kind ?? "query",
6668
- auth: options?.auth ?? "protected",
6678
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6669
6679
  ...options?.access !== void 0 ? { access: options.access } : {},
6670
6680
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6671
6681
  timeoutMs: options?.timeoutMs
@@ -6685,7 +6695,7 @@ function systemMethod(input, output, options) {
6685
6695
  }
6686
6696
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6687
6697
  var VersionOutputSchema$1 = object({ version: string() });
6688
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6698
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6689
6699
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6690
6700
  DeviceType["Camera"] = "camera";
6691
6701
  DeviceType["Hub"] = "hub";
@@ -7006,7 +7016,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7006
7016
  }({});
7007
7017
  var StaticDirOutputSchema = object({ staticDir: string() });
7008
7018
  var VersionOutputSchema = object({ version: string() });
7009
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7019
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7010
7020
  /**
7011
7021
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7012
7022
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7620,24 +7630,6 @@ var RecordingRetentionSchema = object({
7620
7630
  maxSizeGb: number().min(0).optional()
7621
7631
  });
7622
7632
  /**
7623
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7624
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7625
- * previews at. Five graduated steps; absent on a config = `standard` (the
7626
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7627
- *
7628
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7629
- * Each window's index sidecar carries its own tile dims, so a camera whose
7630
- * preset changed over time renders every historical window at the dims it was
7631
- * written with.
7632
- */
7633
- var ScrubThumbnailPresetSchema = _enum([
7634
- "minimal",
7635
- "low",
7636
- "standard",
7637
- "high",
7638
- "max"
7639
- ]);
7640
- /**
7641
7633
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7642
7634
  *
7643
7635
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7645,7 +7637,11 @@ var ScrubThumbnailPresetSchema = _enum([
7645
7637
  * other field is a storage knob (profiles, segment length, retention, scrub).
7646
7638
  *
7647
7639
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7648
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7640
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7641
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7642
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7643
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7644
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7649
7645
  * A stale caller must fail loudly — silently stripping its legacy intent would
7650
7646
  * persist a band-less config, i.e. silently stop recording the camera.
7651
7647
  */
@@ -7668,14 +7664,7 @@ var RecordingConfigSchema = object({
7668
7664
  * "off" is the absence of a covering band, never a band value.
7669
7665
  */
7670
7666
  bands: array(RecordingBandSchema).default([]),
7671
- retention: RecordingRetentionSchema.optional(),
7672
- /**
7673
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7674
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7675
- * windows only — existing sheets are immutable, and each window's index
7676
- * carries its own tile dims so mixed-preset history renders correctly.
7677
- */
7678
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7667
+ retention: RecordingRetentionSchema.optional()
7679
7668
  }).strict();
7680
7669
  /**
7681
7670
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7751,10 +7740,11 @@ var RelocateFootageInputSchema = object({
7751
7740
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7752
7741
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7753
7742
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7754
- var StorageMigrationMediaMoveInputSchema = object({
7743
+ var RelocateMediaInputSchema = object({
7755
7744
  toLocationId: string(),
7756
7745
  throttleMbps: number().min(1).max(1e3).optional()
7757
- }).extend({ leaseId: string().min(1) });
7746
+ });
7747
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7758
7748
  /** The independently selectable logical storage classes. `recordings`
7759
7749
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7760
7750
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8049,7 +8039,26 @@ var LabelDefinitionSchema = object({
8049
8039
  description: string().optional(),
8050
8040
  icon: string().optional()
8051
8041
  });
8052
- var ClassMapDefinitionSchema = object({
8042
+ /**
8043
+ * Wire schema for a per-model CATALOG classMap override
8044
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8045
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8046
+ * detection pipeline executor actually routes.
8047
+ *
8048
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8049
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8050
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8051
+ * enum) — the two used to share the name `ClassMapDefinition`/
8052
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8053
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8054
+ * are not: it is two different concepts colliding on a name. Keep this type
8055
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8056
+ * would either narrow every `ClassMapDefinition` consumer to the four
8057
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8058
+ * schema exists for (see the "rejects a classMap whose target is not a
8059
+ * detection macro" test in `model-catalog-schema.test.ts`).
8060
+ */
8061
+ var DetectionCatalogClassMapSchema = object({
8053
8062
  mapping: record(string(), _enum([
8054
8063
  "person",
8055
8064
  "vehicle",
@@ -8141,6 +8150,12 @@ var ModelVariantGroupSchema = object({
8141
8150
  */
8142
8151
  resolution: number().int().positive().optional()
8143
8152
  });
8153
+ var ModelProviderIdSchema = _enum([
8154
+ "camstack",
8155
+ "frigate",
8156
+ "scrypted",
8157
+ "custom"
8158
+ ]);
8144
8159
  var ModelCatalogEntrySchema = object({
8145
8160
  id: string(),
8146
8161
  name: string(),
@@ -8238,11 +8253,17 @@ var ModelCatalogEntrySchema = object({
8238
8253
  */
8239
8254
  group: ModelVariantGroupSchema.optional(),
8240
8255
  /**
8256
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8257
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8258
+ * persisted before this field existed (`inferModelProvider` fills those).
8259
+ */
8260
+ provider: ModelProviderIdSchema.optional(),
8261
+ /**
8241
8262
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8242
8263
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8243
8264
  * labels already ARE the CamStack macros (Scrypted identity map).
8244
8265
  */
8245
- classMap: ClassMapDefinitionSchema.optional()
8266
+ classMap: DetectionCatalogClassMapSchema.optional()
8246
8267
  });
8247
8268
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8248
8269
  format: literal("openvino"),
@@ -8272,7 +8293,7 @@ var ModelConvertMetadataSchema = object({
8272
8293
  "segmentation"
8273
8294
  ]),
8274
8295
  faceAlignment: boolean().optional(),
8275
- classMap: ClassMapDefinitionSchema.optional()
8296
+ classMap: DetectionCatalogClassMapSchema.optional()
8276
8297
  });
8277
8298
  var ConvertResultSchema = object({
8278
8299
  entry: ModelCatalogEntrySchema,
@@ -9135,7 +9156,7 @@ var AddonPageDeclarationSchema = object({
9135
9156
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9136
9157
  sectionLabel: string().optional()
9137
9158
  });
9138
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9159
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9139
9160
  var AddonHttpRouteSchema = object({
9140
9161
  method: _enum([
9141
9162
  "GET",
@@ -9370,7 +9391,7 @@ var WidgetMetadataSchema = object({
9370
9391
  defaultColumns: number().int().min(1).max(12).default(6),
9371
9392
  defaultRows: number().int().min(1).max(12).default(1)
9372
9393
  });
9373
- method(_void(), array(WidgetMetadataSchema).readonly());
9394
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9374
9395
  /**
9375
9396
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9376
9397
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -10941,7 +10962,7 @@ var CustomModelDescriptorSchema = object({
10941
10962
  stepId: string(),
10942
10963
  entry: ModelCatalogEntrySchema
10943
10964
  });
10944
- method(_void(), array(CustomModelDescriptorSchema).readonly());
10965
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
10945
10966
  /**
10946
10967
  * Query filter for settings-store collections.
10947
10968
  */
@@ -11028,7 +11049,8 @@ method(object({
11028
11049
  }), _void(), { kind: "mutation" }), method(object({
11029
11050
  namespace: string().optional(),
11030
11051
  collection: string(),
11031
- filter: QueryFilterSchema.optional()
11052
+ filter: QueryFilterSchema.optional(),
11053
+ columns: array(string()).readonly().optional()
11032
11054
  }), array(SettingsRecordSchema).readonly()), method(object({
11033
11055
  namespace: string().optional(),
11034
11056
  collection: string(),
@@ -11091,46 +11113,87 @@ var EngineInfoSchema = object({
11091
11113
  kind: _enum(["relational", "vector"]),
11092
11114
  displayName: string()
11093
11115
  });
11094
- method(_void(), EngineInfoSchema), method(object({
11116
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11095
11117
  namespace: string().optional(),
11096
11118
  collection: string(),
11097
11119
  key: string()
11098
- }), unknown()), method(object({
11120
+ }), unknown(), { auth: "admin" }), method(object({
11099
11121
  namespace: string().optional(),
11100
11122
  collection: string(),
11101
11123
  key: string(),
11102
11124
  value: unknown()
11103
- }), _void(), { kind: "mutation" }), method(object({
11125
+ }), _void(), {
11126
+ kind: "mutation",
11127
+ auth: "admin"
11128
+ }), method(object({
11104
11129
  namespace: string().optional(),
11105
11130
  collection: string(),
11106
- filter: QueryFilterSchema.optional()
11107
- }), array(SettingsRecordSchema).readonly()), method(object({
11131
+ filter: QueryFilterSchema.optional(),
11132
+ /**
11133
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11134
+ *
11135
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11136
+ * was wrong — corrected 2026-08-26 after the hop map
11137
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11138
+ * There is **no Zod parse at all** between the door and the engine: the
11139
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11140
+ * field declared here reaches `SqliteSettingsBackend` either way.
11141
+ *
11142
+ * What actually lost `columns` was the THIRD declaration of this shape:
11143
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11144
+ * interface the engine destructures from. The field existed on both
11145
+ * schemas and the engine still never read it, because nothing checks a
11146
+ * registered provider against `InferProvider<cap>` —
11147
+ * `ProviderRegistration.provider` is typed `object`.
11148
+ *
11149
+ * It is declared here anyway, and must stay in step with
11150
+ * `settings-store.query`: a caller reading only the cap definitions has
11151
+ * to be able to see that this call carries a projection.
11152
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11153
+ */
11154
+ columns: array(string()).readonly().optional()
11155
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11108
11156
  namespace: string().optional(),
11109
11157
  collection: string(),
11110
11158
  record: SettingsRecordSchema
11111
- }), _void(), { kind: "mutation" }), method(object({
11159
+ }), _void(), {
11160
+ kind: "mutation",
11161
+ auth: "admin"
11162
+ }), method(object({
11112
11163
  namespace: string().optional(),
11113
11164
  collection: string(),
11114
11165
  id: string(),
11115
11166
  data: record(string(), unknown())
11116
- }), _void(), { kind: "mutation" }), method(object({
11167
+ }), _void(), {
11168
+ kind: "mutation",
11169
+ auth: "admin"
11170
+ }), method(object({
11117
11171
  namespace: string().optional(),
11118
11172
  collection: string(),
11119
11173
  key: string()
11120
- }), _void(), { kind: "mutation" }), method(object({
11174
+ }), _void(), {
11175
+ kind: "mutation",
11176
+ auth: "admin"
11177
+ }), method(object({
11121
11178
  namespace: string().optional(),
11122
11179
  collection: string(),
11123
11180
  filter: MutationFilterSchema
11124
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11181
+ }), object({ deleted: number().int() }), {
11182
+ kind: "mutation",
11183
+ auth: "admin"
11184
+ }), method(object({
11125
11185
  namespace: string().optional(),
11126
11186
  collection: string(),
11127
11187
  filter: MutationFilterSchema,
11128
11188
  data: record(string(), unknown())
11129
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11189
+ }), object({ updated: number().int() }), {
11190
+ kind: "mutation",
11191
+ auth: "admin"
11192
+ }), method(object({
11130
11193
  namespace: string().optional(),
11131
11194
  collection: string(),
11132
11195
  filter: QueryFilterSchema.optional()
11133
- }), number()), method(object({
11196
+ }), number(), { auth: "admin" }), method(object({
11134
11197
  namespace: string().optional(),
11135
11198
  collection: string(),
11136
11199
  field: string(),
@@ -11140,15 +11203,18 @@ method(_void(), EngineInfoSchema), method(object({
11140
11203
  }), array(object({
11141
11204
  bucket: number().int(),
11142
11205
  count: number().int()
11143
- })).readonly()), method(object({
11206
+ })).readonly(), { auth: "admin" }), method(object({
11144
11207
  namespace: string().optional(),
11145
11208
  collection: string()
11146
- }), boolean()), method(object({
11209
+ }), boolean(), { auth: "admin" }), method(object({
11147
11210
  namespace: string().optional(),
11148
11211
  collection: string(),
11149
11212
  columns: array(CollectionColumnSchema).readonly(),
11150
11213
  indexes: array(CollectionIndexSchema).readonly().optional()
11151
- }), _void(), { kind: "mutation" });
11214
+ }), _void(), {
11215
+ kind: "mutation",
11216
+ auth: "admin"
11217
+ });
11152
11218
  /**
11153
11219
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11154
11220
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -11814,6 +11880,27 @@ var LinkedDeviceSchema = object({
11814
11880
  features: array(string()),
11815
11881
  producesTrackedEvents: boolean().optional()
11816
11882
  });
11883
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11884
+ * The batch answer needs the tag; the single-device answer already has it
11885
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11886
+ var LinkedDevicesForDeviceSchema = object({
11887
+ deviceId: number(),
11888
+ mode: LinkedDevicesModeSchema,
11889
+ devices: array(LinkedDeviceSchema)
11890
+ });
11891
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11892
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11893
+ * object literal is exactly how the three drift apart. */
11894
+ var DeviceBindingsForDeviceSchema = object({
11895
+ deviceId: number(),
11896
+ entries: array(object({
11897
+ capName: string(),
11898
+ kind: _enum(["native", "wrapped"]),
11899
+ providerAddonId: string(),
11900
+ providerNodeId: string(),
11901
+ nativeAddonId: string()
11902
+ }))
11903
+ });
11817
11904
  var SavedDeviceRowSchema = object({
11818
11905
  /** Numeric id reserved at allocateDeviceId time. */
11819
11906
  id: number(),
@@ -12039,11 +12126,25 @@ method(object({
12039
12126
  projection: _enum(["full", "slim"]).optional(),
12040
12127
  /** Return only camera devices. Filtering server-side instead of
12041
12128
  * shipping 293 rows to find 12. */
12042
- isCamera: boolean().optional()
12129
+ isCamera: boolean().optional(),
12130
+ /**
12131
+ * Return only these device ids. For the caller that already KNOWS the
12132
+ * handful it wants and needs a field the id-bearing answer does not
12133
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12134
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12135
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12136
+ * refetches on the reconcile interval, on a phone.
12137
+ *
12138
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12139
+ * keys rather than rejecting them (verified against the live hub
12140
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12141
+ * it answers today and the caller filters as it already does.
12142
+ */
12143
+ deviceIds: array(number()).optional()
12043
12144
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12044
12145
  mode: LinkedDevicesModeSchema,
12045
12146
  devices: array(LinkedDeviceSchema)
12046
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12147
+ })), 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({
12047
12148
  deviceId: number(),
12048
12149
  values: record(string(), unknown())
12049
12150
  }), object({ success: literal(true) }), {
@@ -12070,25 +12171,7 @@ method(object({
12070
12171
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12071
12172
  kind: "mutation",
12072
12173
  auth: "admin"
12073
- }), method(object({ deviceId: number() }), object({
12074
- deviceId: number(),
12075
- entries: array(object({
12076
- capName: string(),
12077
- kind: _enum(["native", "wrapped"]),
12078
- providerAddonId: string(),
12079
- providerNodeId: string(),
12080
- nativeAddonId: string()
12081
- }))
12082
- })), method(object({}), array(object({
12083
- deviceId: number(),
12084
- entries: array(object({
12085
- capName: string(),
12086
- kind: _enum(["native", "wrapped"]),
12087
- providerAddonId: string(),
12088
- providerNodeId: string(),
12089
- nativeAddonId: string()
12090
- }))
12091
- }))), method(object({
12174
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12092
12175
  deviceId: number(),
12093
12176
  capName: string(),
12094
12177
  wrapperAddonId: string(),
@@ -12259,7 +12342,7 @@ method(object({
12259
12342
  crop: _instanceof(Uint8Array),
12260
12343
  width: number(),
12261
12344
  height: number()
12262
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12345
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12263
12346
  /**
12264
12347
  * filesystem-browse — per-node capability for browsing the node's local
12265
12348
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12552,19 +12635,22 @@ method(LlmGenerateBaseInputSchema.extend({
12552
12635
  runtime: ManagedRuntimeConfigSchema,
12553
12636
  /** The managed profile's timeout, threaded by the hub provider. */
12554
12637
  timeoutMs: number().int().positive().optional()
12555
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12638
+ }), LlmGenerateResultSchema, {
12639
+ kind: "mutation",
12640
+ auth: "admin"
12641
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12556
12642
  kind: "mutation",
12557
12643
  auth: "admin"
12558
12644
  }), method(object({}), _void(), {
12559
12645
  kind: "mutation",
12560
12646
  auth: "admin"
12561
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12647
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12562
12648
  kind: "mutation",
12563
12649
  auth: "admin"
12564
12650
  }), method(object({ file: string() }), _void(), {
12565
12651
  kind: "mutation",
12566
12652
  auth: "admin"
12567
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12653
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12568
12654
  /**
12569
12655
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12570
12656
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14479,12 +14565,15 @@ var NcOccupancyConditionSchema = object({
14479
14565
  * there is no second switch that can disagree with the first and every rule
14480
14566
  * authored before the decision migrates for free (`audioModeOf`):
14481
14567
  *
14482
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14483
- * classifier labels with one of them. No window, no percentage:
14484
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14485
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14486
- * the analyzer's (`classificationMinScore`, per device) — a label only
14487
- * reaches this condition if the classifier was already confident enough.
14568
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14569
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14570
+ * `hitPercent` and `samplingSeconds` are still ignored — a percentage of
14571
+ * frames is the wrong question for a classifier that labels 1–3 frames
14572
+ * per episode. The count window is the brake that drops a single-frame
14573
+ * false positive; the rule's own `throttle` cooldown is the other. The
14574
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14575
+ * per device) — a label only reaches this condition if the classifier was
14576
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14488
14577
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14489
14578
  * the condition: at least `hitPercent`% of the samples over
14490
14579
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14511,14 +14600,22 @@ var NcOccupancyConditionSchema = object({
14511
14600
  * an operator who typed `dog` mean the same thing.
14512
14601
  */
14513
14602
  var NcAudioConditionSchema = object({
14514
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14603
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14515
14604
  labels: array(string().min(1)).min(1).optional(),
14516
14605
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14517
14606
  dbThreshold: number().min(-96).max(0).optional(),
14518
14607
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14519
14608
  hitPercent: number().int().min(1).max(100).default(60),
14520
14609
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14521
- samplingSeconds: number().int().min(1).max(300).default(10)
14610
+ samplingSeconds: number().int().min(1).max(300).default(10),
14611
+ /**
14612
+ * LABEL MODE: how many labelled frames must land inside
14613
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14614
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14615
+ */
14616
+ confirmHits: number().int().min(1).max(20).optional(),
14617
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14618
+ confirmWindowSec: number().int().min(1).max(60).optional()
14522
14619
  });
14523
14620
  /**
14524
14621
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16045,7 +16142,7 @@ var OauthIntegrationDescriptorSchema = object({
16045
16142
  */
16046
16143
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16047
16144
  });
16048
- method(_void(), OauthIntegrationDescriptorSchema);
16145
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
16049
16146
  /**
16050
16147
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
16051
16148
  * per-frame detections emitted by the pipeline runner into tracked
@@ -16892,6 +16989,46 @@ var RecentTracksPageSchema = object({
16892
16989
  /** Cursor for the next page, or null when this page is the last. */
16893
16990
  nextCursor: string().nullable()
16894
16991
  });
16992
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
16993
+ var LIST_GROUPS_MAX_LIMIT = 100;
16994
+ var AnalyticsGroupRecordSchema = object({
16995
+ id: string(),
16996
+ deviceId: number().int(),
16997
+ openedAt: number().int(),
16998
+ closedAt: number().int(),
16999
+ timestamp: number().int(),
17000
+ memberCount: number().int(),
17001
+ memberTrackIds: array(string()).readonly(),
17002
+ className: string(),
17003
+ classes: array(string()).readonly(),
17004
+ /** Relative event-media path, or null when the group has no picture yet. */
17005
+ mediaUrl: string().nullable(),
17006
+ singleton: boolean()
17007
+ });
17008
+ var AnalyticsGroupMemberSchema = object({
17009
+ trackId: string(),
17010
+ deviceId: number().int(),
17011
+ className: string(),
17012
+ firstSeen: number().int(),
17013
+ lastSeen: number().int(),
17014
+ mediaUrl: string().nullable()
17015
+ });
17016
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17017
+ var ListGroupsQueryInput = object({
17018
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17019
+ deviceIds: array(number()),
17020
+ /** Window lower bound on `closedAt` (inclusive). */
17021
+ since: number().optional(),
17022
+ /** Window upper bound on `openedAt` (inclusive). */
17023
+ until: number().optional(),
17024
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17025
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17026
+ cursor: string().optional()
17027
+ });
17028
+ var ListGroupsPageSchema = object({
17029
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17030
+ nextCursor: string().nullable()
17031
+ });
16895
17032
  var KeyEventQueryInput = object({
16896
17033
  deviceId: number(),
16897
17034
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16967,7 +17104,9 @@ var TrackCascadeCountsSchema = object({
16967
17104
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
16968
17105
  plates: number().int(),
16969
17106
  /** Per-track CLIP search vectors removed (best-effort). */
16970
- embeddings: number().int()
17107
+ embeddings: number().int(),
17108
+ /** Group membership + group rows removed with their last member (best-effort). */
17109
+ groups: number().int()
16971
17110
  });
16972
17111
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
16973
17112
  var DiskReconcileCountsSchema = object({
@@ -17113,7 +17252,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17113
17252
  * stationary registry). Default false: the timeline lists passages,
17114
17253
  * not parking records (operator decision, 2026-08-15). */
17115
17254
  includeStationary: boolean().optional()
17116
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17255
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17256
+ deviceId: number(),
17257
+ groupId: string().min(1)
17258
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17117
17259
  kind: "mutation",
17118
17260
  auth: "admin"
17119
17261
  }), 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({
@@ -17195,6 +17337,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17195
17337
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17196
17338
  kind: "mutation",
17197
17339
  auth: "admin"
17340
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17341
+ kind: "mutation",
17342
+ auth: "admin"
17343
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17344
+ kind: "query",
17345
+ auth: "admin"
17346
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17347
+ kind: "mutation",
17348
+ auth: "admin"
17198
17349
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17199
17350
  kind: "query",
17200
17351
  auth: "admin"
@@ -17349,6 +17500,11 @@ object({
17349
17500
  "jpeg"
17350
17501
  ])
17351
17502
  });
17503
+ /**
17504
+ * Process-local frame identity. It is serializable so it can ride an in-process
17505
+ * capability call, but `registryId` deliberately prevents resolution in any
17506
+ * other process or execution group.
17507
+ */
17352
17508
  var FrameRefSchema = object({
17353
17509
  registryId: string().min(1),
17354
17510
  id: string().min(1),
@@ -17423,7 +17579,8 @@ var PipelineModelOptionSchema = object({
17423
17579
  sizeMB: number()
17424
17580
  })),
17425
17581
  group: ModelVariantGroupSchema.optional(),
17426
- legacy: boolean().optional()
17582
+ legacy: boolean().optional(),
17583
+ provider: ModelProviderIdSchema.optional()
17427
17584
  });
17428
17585
  var ConfigFieldBridge = custom();
17429
17586
  var PipelineAddonSchemaSchema = object({
@@ -19513,7 +19670,7 @@ method(object({
19513
19670
  * linking rather than produce an eternal token.
19514
19671
  */
19515
19672
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19516
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19673
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19517
19674
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19518
19675
  providerId: string().min(1),
19519
19676
  displayName: string().min(1),
@@ -19608,10 +19765,13 @@ var EvictResultSchema = object({
19608
19765
  /** True when the provider has nothing left it is willing to drop on this location. */
19609
19766
  exhausted: boolean()
19610
19767
  });
19611
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19768
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19612
19769
  locationId: string(),
19613
19770
  targetBytes: number().int().positive()
19614
- }), EvictResultSchema, { kind: "mutation" });
19771
+ }), EvictResultSchema, {
19772
+ kind: "mutation",
19773
+ auth: "admin"
19774
+ });
19615
19775
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19616
19776
  kind: "mutation",
19617
19777
  auth: "admin"
@@ -19671,26 +19831,50 @@ var ReadChunkInputSchema = object({
19671
19831
  length: number()
19672
19832
  });
19673
19833
  var EndDownloadInputSchema = object({ downloadId: string() });
19674
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19834
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19675
19835
  location: StorageLocationSchema,
19676
19836
  relativePath: string()
19677
- }), string()), method(object({
19837
+ }), string(), { auth: "admin" }), method(object({
19678
19838
  location: StorageLocationSchema,
19679
19839
  relativePath: string(),
19680
19840
  data: _instanceof(Uint8Array)
19681
- }), _void(), { kind: "mutation" }), method(object({
19841
+ }), _void(), {
19842
+ kind: "mutation",
19843
+ auth: "admin"
19844
+ }), method(object({
19682
19845
  location: StorageLocationSchema,
19683
19846
  relativePath: string()
19684
- }), _instanceof(Uint8Array)), method(object({
19847
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19685
19848
  location: StorageLocationSchema,
19686
19849
  relativePath: string()
19687
- }), boolean()), method(object({
19850
+ }), boolean(), { auth: "admin" }), method(object({
19688
19851
  location: StorageLocationSchema,
19689
19852
  prefix: string().optional()
19690
- }), array(string()).readonly()), method(object({
19853
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19691
19854
  location: StorageLocationSchema,
19692
19855
  relativePath: string()
19693
- }), _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" });
19856
+ }), _void(), {
19857
+ kind: "mutation",
19858
+ auth: "admin"
19859
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
19860
+ kind: "mutation",
19861
+ auth: "admin"
19862
+ }), method(WriteChunkInputSchema, _void(), {
19863
+ kind: "mutation",
19864
+ auth: "admin"
19865
+ }), method(FinalizeUploadInputSchema, _void(), {
19866
+ kind: "mutation",
19867
+ auth: "admin"
19868
+ }), method(AbortUploadInputSchema, _void(), {
19869
+ kind: "mutation",
19870
+ auth: "admin"
19871
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
19872
+ kind: "mutation",
19873
+ auth: "admin"
19874
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
19875
+ kind: "mutation",
19876
+ auth: "admin"
19877
+ });
19694
19878
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19695
19879
  var ProfileSettingsSchemaBridge = unknown().nullable();
19696
19880
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -19948,7 +20132,8 @@ method(object({
19948
20132
  access: "create"
19949
20133
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
19950
20134
  kind: "mutation",
19951
- access: "view"
20135
+ access: "view",
20136
+ auth: "admin"
19952
20137
  }), method(object({
19953
20138
  /** Required — the user the assertion belongs to (verified). */
19954
20139
  userId: string(),
@@ -19956,10 +20141,12 @@ method(object({
19956
20141
  response: record(string(), unknown())
19957
20142
  }), object({ verified: boolean() }), {
19958
20143
  kind: "mutation",
19959
- access: "view"
20144
+ access: "view",
20145
+ auth: "admin"
19960
20146
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19961
20147
  kind: "mutation",
19962
- access: "view"
20148
+ access: "view",
20149
+ auth: "admin"
19963
20150
  }), method(object({
19964
20151
  /** AuthenticationResponseJSON from the browser. */
19965
20152
  response: record(string(), unknown()) }), object({
@@ -19967,7 +20154,8 @@ response: record(string(), unknown()) }), object({
19967
20154
  userId: string().nullable()
19968
20155
  }), {
19969
20156
  kind: "mutation",
19970
- access: "view"
20157
+ access: "view",
20158
+ auth: "admin"
19971
20159
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19972
20160
  userId: string(),
19973
20161
  credentialId: string()
@@ -20139,7 +20327,19 @@ var VectorStatsResultSchema = object({
20139
20327
  /** False when the backend ranks approximately. */
20140
20328
  exact: boolean()
20141
20329
  });
20142
- 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);
20330
+ method(VectorDeclareIndexInputSchema, _void(), {
20331
+ kind: "mutation",
20332
+ auth: "admin"
20333
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20334
+ kind: "mutation",
20335
+ auth: "admin"
20336
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20337
+ kind: "mutation",
20338
+ auth: "admin"
20339
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20340
+ kind: "mutation",
20341
+ auth: "admin"
20342
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20143
20343
  var ClipSchema = object({
20144
20344
  /** Opaque, provider-namespaced id. The default provider encodes the time
20145
20345
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21862,7 +22062,27 @@ var MediaFileLiteSchema$1 = object({
21862
22062
  sizeBytes: number(),
21863
22063
  timestamp: number()
21864
22064
  });
21865
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22065
+ method(object({
22066
+ /**
22067
+ * Inline {@link IdentitySchema.coverBase64} on every row.
22068
+ *
22069
+ * Default `false`, the same inversion `listRecentFaces` and
22070
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
22071
+ * why the burden belongs on the caller that WANTS the bytes). Measured
22072
+ * on the live hub the same day: four identities cost 40,979 B with the
22073
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
22074
+ * four times and the viewer holds at `staleTime: 30_000`.
22075
+ *
22076
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
22077
+ * the `event-media` plane serves that key `immutable` with an ETag.
22078
+ *
22079
+ * **This is an INPUT field, so it does not reach the addon until the
22080
+ * next train** — the hub router validates cap inputs against its own
22081
+ * compiled Zod and strips a key it does not know. Until then the
22082
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
22083
+ * is what ships, and the opt-in becomes reachable when the train lands.
22084
+ */
22085
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
21866
22086
  kind: "mutation",
21867
22087
  auth: "admin"
21868
22088
  }), method(object({
@@ -24007,7 +24227,14 @@ var PlateInfoSchema = object({
24007
24227
  plateBbox: BoundingBoxSchema.optional(),
24008
24228
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
24009
24229
  keyFrameMediaKey: string().optional(),
24010
- base64: string().optional()
24230
+ base64: string().optional(),
24231
+ /**
24232
+ * Same crop as a data-plane URL, always present when the plate has a stored
24233
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24234
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24235
+ * left at its `true` default.
24236
+ */
24237
+ cropUrl: string().optional()
24011
24238
  });
24012
24239
  var MediaFileLiteSchema = object({
24013
24240
  key: string(),
@@ -24025,14 +24252,34 @@ var PlateClusterSchema = object({
24025
24252
  });
24026
24253
  method(object({
24027
24254
  deviceId: number().int().optional(),
24028
- limit: number().int().positive().optional()
24255
+ limit: number().int().positive().optional(),
24256
+ /**
24257
+ * Inline the base64 crop on every row. Default `true` — the existing
24258
+ * behaviour, kept so no caller breaks.
24259
+ *
24260
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24261
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24262
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24263
+ * metadata without them — and the browser then caches the images.
24264
+ *
24265
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24266
+ * plates were the one gallery list left without it.
24267
+ *
24268
+ * **This is an INPUT field, so it does not reach the addon until the
24269
+ * next train.** The hub router validates cap inputs against its own
24270
+ * compiled Zod and strips a key it does not know. Until the train
24271
+ * ships, sending `false` is harmless and keeps the crops inline.
24272
+ */
24273
+ includeCrops: boolean().optional()
24029
24274
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
24030
24275
  deviceId: number().int(),
24031
24276
  trackId: string()
24032
24277
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
24033
24278
  text: string().min(1),
24034
24279
  maxDistance: number().int().min(0).optional(),
24035
- limit: number().int().positive().optional()
24280
+ limit: number().int().positive().optional(),
24281
+ /** See `listPlates.includeCrops`. Default `true`. */
24282
+ includeCrops: boolean().optional()
24036
24283
  }), array(PlateInfoSchema).readonly()), method(object({
24037
24284
  maxDistance: number().int().min(0).optional(),
24038
24285
  minClusterSize: number().int().min(2).optional(),
@@ -24046,7 +24293,13 @@ method(object({
24046
24293
  }), method(object({ plateId: string() }), _void(), {
24047
24294
  kind: "mutation",
24048
24295
  auth: "admin"
24049
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24296
+ }), method(object({
24297
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
24298
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
24299
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
24300
+ * INPUT field: stripped by the hub router until the train ships, which
24301
+ * resolves to `false` and is exactly the intended default. */
24302
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24050
24303
  kind: "mutation",
24051
24304
  auth: "admin"
24052
24305
  }), method(object({
@@ -27647,6 +27900,12 @@ Object.freeze({
27647
27900
  addonId: null,
27648
27901
  access: "view"
27649
27902
  },
27903
+ "deviceManager.getBindingsBatch": {
27904
+ capName: "device-manager",
27905
+ capScope: "system",
27906
+ addonId: null,
27907
+ access: "view"
27908
+ },
27650
27909
  "deviceManager.getChildren": {
27651
27910
  capName: "device-manager",
27652
27911
  capScope: "system",
@@ -27707,6 +27966,12 @@ Object.freeze({
27707
27966
  addonId: null,
27708
27967
  access: "view"
27709
27968
  },
27969
+ "deviceManager.getLinkedDevicesBatch": {
27970
+ capName: "device-manager",
27971
+ capScope: "system",
27972
+ addonId: null,
27973
+ access: "view"
27974
+ },
27710
27975
  "deviceManager.getRoleDisplayDefaults": {
27711
27976
  capName: "device-manager",
27712
27977
  capScope: "system",
@@ -29411,6 +29676,12 @@ Object.freeze({
29411
29676
  addonId: null,
29412
29677
  access: "create"
29413
29678
  },
29679
+ "pipelineAnalytics.cancelRelocateMedia": {
29680
+ capName: "pipeline-analytics",
29681
+ capScope: "device",
29682
+ addonId: null,
29683
+ access: "create"
29684
+ },
29414
29685
  "pipelineAnalytics.cancelStorageMigrationMove": {
29415
29686
  capName: "pipeline-analytics",
29416
29687
  capScope: "device",
@@ -29477,6 +29748,12 @@ Object.freeze({
29477
29748
  addonId: null,
29478
29749
  access: "view"
29479
29750
  },
29751
+ "pipelineAnalytics.getGroup": {
29752
+ capName: "pipeline-analytics",
29753
+ capScope: "device",
29754
+ addonId: null,
29755
+ access: "view"
29756
+ },
29480
29757
  "pipelineAnalytics.getKeyEvents": {
29481
29758
  capName: "pipeline-analytics",
29482
29759
  capScope: "device",
@@ -29561,6 +29838,12 @@ Object.freeze({
29561
29838
  addonId: null,
29562
29839
  access: "view"
29563
29840
  },
29841
+ "pipelineAnalytics.listGroups": {
29842
+ capName: "pipeline-analytics",
29843
+ capScope: "device",
29844
+ addonId: null,
29845
+ access: "view"
29846
+ },
29564
29847
  "pipelineAnalytics.listOpsLog": {
29565
29848
  capName: "pipeline-analytics",
29566
29849
  capScope: "device",
@@ -29573,6 +29856,12 @@ Object.freeze({
29573
29856
  addonId: null,
29574
29857
  access: "view"
29575
29858
  },
29859
+ "pipelineAnalytics.listRelocateMediaJobs": {
29860
+ capName: "pipeline-analytics",
29861
+ capScope: "device",
29862
+ addonId: null,
29863
+ access: "view"
29864
+ },
29576
29865
  "pipelineAnalytics.listRetrainAnnotations": {
29577
29866
  capName: "pipeline-analytics",
29578
29867
  capScope: "device",
@@ -29651,6 +29940,12 @@ Object.freeze({
29651
29940
  addonId: null,
29652
29941
  access: "create"
29653
29942
  },
29943
+ "pipelineAnalytics.relocateMedia": {
29944
+ capName: "pipeline-analytics",
29945
+ capScope: "device",
29946
+ addonId: null,
29947
+ access: "create"
29948
+ },
29654
29949
  "pipelineAnalytics.restageRetrainTrack": {
29655
29950
  capName: "pipeline-analytics",
29656
29951
  capScope: "device",
@@ -32342,6 +32637,11 @@ Object.freeze({
32342
32637
  form: "single",
32343
32638
  optional: false
32344
32639
  }],
32640
+ "deviceManager.getBindingsBatch": [{
32641
+ name: "deviceIds",
32642
+ form: "array",
32643
+ optional: false
32644
+ }],
32345
32645
  "deviceManager.getChildren": [{
32346
32646
  name: "parentDeviceId",
32347
32647
  form: "single",
@@ -32387,6 +32687,11 @@ Object.freeze({
32387
32687
  form: "single",
32388
32688
  optional: false
32389
32689
  }],
32690
+ "deviceManager.getLinkedDevicesBatch": [{
32691
+ name: "deviceIds",
32692
+ form: "array",
32693
+ optional: false
32694
+ }],
32390
32695
  "deviceManager.getSettingsSchema": [{
32391
32696
  name: "deviceId",
32392
32697
  form: "single",
@@ -32407,6 +32712,11 @@ Object.freeze({
32407
32712
  form: "single",
32408
32713
  optional: false
32409
32714
  }],
32715
+ "deviceManager.listAll": [{
32716
+ name: "deviceIds",
32717
+ form: "array",
32718
+ optional: true
32719
+ }],
32410
32720
  "deviceManager.loadConfig": [{
32411
32721
  name: "deviceId",
32412
32722
  form: "single",
@@ -32980,6 +33290,11 @@ Object.freeze({
32980
33290
  form: "single",
32981
33291
  optional: false
32982
33292
  }],
33293
+ "pipelineAnalytics.getGroup": [{
33294
+ name: "deviceId",
33295
+ form: "single",
33296
+ optional: false
33297
+ }],
32983
33298
  "pipelineAnalytics.getKeyEvents": [{
32984
33299
  name: "deviceId",
32985
33300
  form: "single",
@@ -33035,6 +33350,11 @@ Object.freeze({
33035
33350
  form: "array",
33036
33351
  optional: false
33037
33352
  }],
33353
+ "pipelineAnalytics.listGroups": [{
33354
+ name: "deviceIds",
33355
+ form: "array",
33356
+ optional: false
33357
+ }],
33038
33358
  "pipelineAnalytics.listOpsLog": [{
33039
33359
  name: "deviceId",
33040
33360
  form: "single",