@camstack/addon-smtp-nodemailer 1.2.26 → 1.2.28

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.
@@ -5838,6 +5838,13 @@ var BaseAddon = class {
5838
5838
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5839
5839
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5840
5840
  _registeredCapNames = [];
5841
+ /**
5842
+ * True only after `readAddonStore` actually answered. Constructor
5843
+ * defaults look like stored config when the store is down — a forked
5844
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5845
+ * mode, 2026-08-25) is not "the operator chose this".
5846
+ */
5847
+ settingsStoreReady = false;
5841
5848
  /** Default config values. Provided via constructor. */
5842
5849
  defaults;
5843
5850
  constructor(defaults) {
@@ -6238,7 +6245,9 @@ var BaseAddon = class {
6238
6245
  ];
6239
6246
  let lastErr;
6240
6247
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6241
- return await settings.readAddonStore() ?? {};
6248
+ const stored = await settings.readAddonStore() ?? {};
6249
+ this.settingsStoreReady = true;
6250
+ return stored;
6242
6251
  } catch (err) {
6243
6252
  lastErr = err;
6244
6253
  const msg = err instanceof Error ? err.message : String(err);
@@ -6246,6 +6255,7 @@ var BaseAddon = class {
6246
6255
  if (attempt === delaysMs.length) break;
6247
6256
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6248
6257
  }
6258
+ this.settingsStoreReady = false;
6249
6259
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6250
6260
  return {};
6251
6261
  }
@@ -6657,7 +6667,7 @@ function method(input, output, options) {
6657
6667
  input,
6658
6668
  output,
6659
6669
  kind: options?.kind ?? "query",
6660
- auth: options?.auth ?? "protected",
6670
+ ...options?.auth !== void 0 ? { auth: options.auth } : {},
6661
6671
  ...options?.access !== void 0 ? { access: options.access } : {},
6662
6672
  ...options?.caller !== void 0 ? { caller: options.caller } : {},
6663
6673
  timeoutMs: options?.timeoutMs
@@ -6677,7 +6687,7 @@ function systemMethod(input, output, options) {
6677
6687
  }
6678
6688
  var StaticDirOutputSchema$1 = object({ staticDir: string() });
6679
6689
  var VersionOutputSchema$1 = object({ version: string() });
6680
- method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6690
+ method(_void(), StaticDirOutputSchema$1, { auth: "admin" }), method(_void(), VersionOutputSchema$1, { auth: "admin" });
6681
6691
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6682
6692
  DeviceType["Camera"] = "camera";
6683
6693
  DeviceType["Hub"] = "hub";
@@ -6998,7 +7008,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
6998
7008
  }({});
6999
7009
  var StaticDirOutputSchema = object({ staticDir: string() });
7000
7010
  var VersionOutputSchema = object({ version: string() });
7001
- method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
7011
+ method(_void(), StaticDirOutputSchema, { auth: "admin" }), method(_void(), VersionOutputSchema, { auth: "admin" });
7002
7012
  /**
7003
7013
  * device-ops — device-scoped cap that unifies the per-IDevice operations
7004
7014
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -7612,24 +7622,6 @@ var RecordingRetentionSchema = object({
7612
7622
  maxSizeGb: number().min(0).optional()
7613
7623
  });
7614
7624
  /**
7615
- * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7616
- * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7617
- * previews at. Five graduated steps; absent on a config = `standard` (the
7618
- * shipped default, matching `sheet-geometry`/`sheet-composer`).
7619
- *
7620
- * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7621
- * Each window's index sidecar carries its own tile dims, so a camera whose
7622
- * preset changed over time renders every historical window at the dims it was
7623
- * written with.
7624
- */
7625
- var ScrubThumbnailPresetSchema = _enum([
7626
- "minimal",
7627
- "low",
7628
- "standard",
7629
- "high",
7630
- "max"
7631
- ]);
7632
- /**
7633
7625
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7634
7626
  *
7635
7627
  * `bands` is the ONLY authored recording intent: what to record, when, and on
@@ -7637,7 +7629,11 @@ var ScrubThumbnailPresetSchema = _enum([
7637
7629
  * other field is a storage knob (profiles, segment length, retention, scrub).
7638
7630
  *
7639
7631
  * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
7640
- * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
7632
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
7633
+ * and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
7634
+ * deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
7635
+ * (D62: a switch that writes a store nobody reads is worse than no switch).
7636
+ * Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
7641
7637
  * A stale caller must fail loudly — silently stripping its legacy intent would
7642
7638
  * persist a band-less config, i.e. silently stop recording the camera.
7643
7639
  */
@@ -7660,14 +7656,7 @@ var RecordingConfigSchema = object({
7660
7656
  * "off" is the absence of a covering band, never a band value.
7661
7657
  */
7662
7658
  bands: array(RecordingBandSchema).default([]),
7663
- retention: RecordingRetentionSchema.optional(),
7664
- /**
7665
- * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7666
- * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7667
- * windows only — existing sheets are immutable, and each window's index
7668
- * carries its own tile dims so mixed-preset history renders correctly.
7669
- */
7670
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7659
+ retention: RecordingRetentionSchema.optional()
7671
7660
  }).strict();
7672
7661
  /**
7673
7662
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
@@ -7743,10 +7732,11 @@ var RelocateFootageInputSchema = object({
7743
7732
  * `RecordingConfig.enabled` or camera wrapper bindings. */
7744
7733
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
7745
7734
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
7746
- var StorageMigrationMediaMoveInputSchema = object({
7735
+ var RelocateMediaInputSchema = object({
7747
7736
  toLocationId: string(),
7748
7737
  throttleMbps: number().min(1).max(1e3).optional()
7749
- }).extend({ leaseId: string().min(1) });
7738
+ });
7739
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
7750
7740
  /** The independently selectable logical storage classes. `recordings`
7751
7741
  * encompasses the high and mid segment profiles; `recordingsLow` is low
7752
7742
  * segments; `eventMedia` is post-analysis blobs. */
@@ -8041,7 +8031,26 @@ var LabelDefinitionSchema = object({
8041
8031
  description: string().optional(),
8042
8032
  icon: string().optional()
8043
8033
  });
8044
- var ClassMapDefinitionSchema = object({
8034
+ /**
8035
+ * Wire schema for a per-model CATALOG classMap override
8036
+ * (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
8037
+ * restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
8038
+ * detection pipeline executor actually routes.
8039
+ *
8040
+ * This is deliberately a DIFFERENT, narrower shape than the general-purpose
8041
+ * `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
8042
+ * and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
8043
+ * enum) — the two used to share the name `ClassMapDefinition`/
8044
+ * `ClassMapDefinitionSchema`, which made the schema-type-twin guard
8045
+ * (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
8046
+ * are not: it is two different concepts colliding on a name. Keep this type
8047
+ * under its own name rather than reusing `ClassMapDefinition` — reusing it
8048
+ * would either narrow every `ClassMapDefinition` consumer to the four
8049
+ * detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
8050
+ * schema exists for (see the "rejects a classMap whose target is not a
8051
+ * detection macro" test in `model-catalog-schema.test.ts`).
8052
+ */
8053
+ var DetectionCatalogClassMapSchema = object({
8045
8054
  mapping: record(string(), _enum([
8046
8055
  "person",
8047
8056
  "vehicle",
@@ -8133,6 +8142,12 @@ var ModelVariantGroupSchema = object({
8133
8142
  */
8134
8143
  resolution: number().int().positive().optional()
8135
8144
  });
8145
+ var ModelProviderIdSchema = _enum([
8146
+ "camstack",
8147
+ "frigate",
8148
+ "scrypted",
8149
+ "custom"
8150
+ ]);
8136
8151
  var ModelCatalogEntrySchema = object({
8137
8152
  id: string(),
8138
8153
  name: string(),
@@ -8230,11 +8245,17 @@ var ModelCatalogEntrySchema = object({
8230
8245
  */
8231
8246
  group: ModelVariantGroupSchema.optional(),
8232
8247
  /**
8248
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8249
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8250
+ * persisted before this field existed (`inferModelProvider` fills those).
8251
+ */
8252
+ provider: ModelProviderIdSchema.optional(),
8253
+ /**
8233
8254
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8234
8255
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8235
8256
  * labels already ARE the CamStack macros (Scrypted identity map).
8236
8257
  */
8237
- classMap: ClassMapDefinitionSchema.optional()
8258
+ classMap: DetectionCatalogClassMapSchema.optional()
8238
8259
  });
8239
8260
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8240
8261
  format: literal("openvino"),
@@ -8264,7 +8285,7 @@ var ModelConvertMetadataSchema = object({
8264
8285
  "segmentation"
8265
8286
  ]),
8266
8287
  faceAlignment: boolean().optional(),
8267
- classMap: ClassMapDefinitionSchema.optional()
8288
+ classMap: DetectionCatalogClassMapSchema.optional()
8268
8289
  });
8269
8290
  var ConvertResultSchema = object({
8270
8291
  entry: ModelCatalogEntrySchema,
@@ -9127,7 +9148,7 @@ var AddonPageDeclarationSchema = object({
9127
9148
  /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
9128
9149
  sectionLabel: string().optional()
9129
9150
  });
9130
- method(_void(), array(AddonPageDeclarationSchema).readonly());
9151
+ method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" });
9131
9152
  var AddonHttpRouteSchema = object({
9132
9153
  method: _enum([
9133
9154
  "GET",
@@ -9362,7 +9383,7 @@ var WidgetMetadataSchema = object({
9362
9383
  defaultColumns: number().int().min(1).max(12).default(6),
9363
9384
  defaultRows: number().int().min(1).max(12).default(1)
9364
9385
  });
9365
- method(_void(), array(WidgetMetadataSchema).readonly());
9386
+ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
9366
9387
  /**
9367
9388
  * `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
9368
9389
  * surface that admin-ui consumes through `useAddonWidgetsListWidgets()`.
@@ -10884,7 +10905,7 @@ var CustomModelDescriptorSchema = object({
10884
10905
  stepId: string(),
10885
10906
  entry: ModelCatalogEntrySchema
10886
10907
  });
10887
- method(_void(), array(CustomModelDescriptorSchema).readonly());
10908
+ method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" });
10888
10909
  /**
10889
10910
  * Query filter for settings-store collections.
10890
10911
  */
@@ -10971,7 +10992,8 @@ method(object({
10971
10992
  }), _void(), { kind: "mutation" }), method(object({
10972
10993
  namespace: string().optional(),
10973
10994
  collection: string(),
10974
- filter: QueryFilterSchema.optional()
10995
+ filter: QueryFilterSchema.optional(),
10996
+ columns: array(string()).readonly().optional()
10975
10997
  }), array(SettingsRecordSchema).readonly()), method(object({
10976
10998
  namespace: string().optional(),
10977
10999
  collection: string(),
@@ -11034,46 +11056,87 @@ var EngineInfoSchema = object({
11034
11056
  kind: _enum(["relational", "vector"]),
11035
11057
  displayName: string()
11036
11058
  });
11037
- method(_void(), EngineInfoSchema), method(object({
11059
+ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
11038
11060
  namespace: string().optional(),
11039
11061
  collection: string(),
11040
11062
  key: string()
11041
- }), unknown()), method(object({
11063
+ }), unknown(), { auth: "admin" }), method(object({
11042
11064
  namespace: string().optional(),
11043
11065
  collection: string(),
11044
11066
  key: string(),
11045
11067
  value: unknown()
11046
- }), _void(), { kind: "mutation" }), method(object({
11068
+ }), _void(), {
11069
+ kind: "mutation",
11070
+ auth: "admin"
11071
+ }), method(object({
11047
11072
  namespace: string().optional(),
11048
11073
  collection: string(),
11049
- filter: QueryFilterSchema.optional()
11050
- }), array(SettingsRecordSchema).readonly()), method(object({
11074
+ filter: QueryFilterSchema.optional(),
11075
+ /**
11076
+ * SQL-level column projection — MUST mirror `settings-store.query`.
11077
+ *
11078
+ * ⚠ An earlier version of this comment blamed Zod stripping, and that
11079
+ * was wrong — corrected 2026-08-26 after the hop map
11080
+ * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
11081
+ * There is **no Zod parse at all** between the door and the engine: the
11082
+ * dispatcher forwards the payload verbatim and UDS carries it whole. A
11083
+ * field declared here reaches `SqliteSettingsBackend` either way.
11084
+ *
11085
+ * What actually lost `columns` was the THIRD declaration of this shape:
11086
+ * `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
11087
+ * interface the engine destructures from. The field existed on both
11088
+ * schemas and the engine still never read it, because nothing checks a
11089
+ * registered provider against `InferProvider<cap>` —
11090
+ * `ProviderRegistration.provider` is typed `object`.
11091
+ *
11092
+ * It is declared here anyway, and must stay in step with
11093
+ * `settings-store.query`: a caller reading only the cap definitions has
11094
+ * to be able to see that this call carries a projection.
11095
+ * `data-door-schema-parity.spec.ts` keeps the two aligned.
11096
+ */
11097
+ columns: array(string()).readonly().optional()
11098
+ }), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
11051
11099
  namespace: string().optional(),
11052
11100
  collection: string(),
11053
11101
  record: SettingsRecordSchema
11054
- }), _void(), { kind: "mutation" }), method(object({
11102
+ }), _void(), {
11103
+ kind: "mutation",
11104
+ auth: "admin"
11105
+ }), method(object({
11055
11106
  namespace: string().optional(),
11056
11107
  collection: string(),
11057
11108
  id: string(),
11058
11109
  data: record(string(), unknown())
11059
- }), _void(), { kind: "mutation" }), method(object({
11110
+ }), _void(), {
11111
+ kind: "mutation",
11112
+ auth: "admin"
11113
+ }), method(object({
11060
11114
  namespace: string().optional(),
11061
11115
  collection: string(),
11062
11116
  key: string()
11063
- }), _void(), { kind: "mutation" }), method(object({
11117
+ }), _void(), {
11118
+ kind: "mutation",
11119
+ auth: "admin"
11120
+ }), method(object({
11064
11121
  namespace: string().optional(),
11065
11122
  collection: string(),
11066
11123
  filter: MutationFilterSchema
11067
- }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
11124
+ }), object({ deleted: number().int() }), {
11125
+ kind: "mutation",
11126
+ auth: "admin"
11127
+ }), method(object({
11068
11128
  namespace: string().optional(),
11069
11129
  collection: string(),
11070
11130
  filter: MutationFilterSchema,
11071
11131
  data: record(string(), unknown())
11072
- }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
11132
+ }), object({ updated: number().int() }), {
11133
+ kind: "mutation",
11134
+ auth: "admin"
11135
+ }), method(object({
11073
11136
  namespace: string().optional(),
11074
11137
  collection: string(),
11075
11138
  filter: QueryFilterSchema.optional()
11076
- }), number()), method(object({
11139
+ }), number(), { auth: "admin" }), method(object({
11077
11140
  namespace: string().optional(),
11078
11141
  collection: string(),
11079
11142
  field: string(),
@@ -11083,15 +11146,18 @@ method(_void(), EngineInfoSchema), method(object({
11083
11146
  }), array(object({
11084
11147
  bucket: number().int(),
11085
11148
  count: number().int()
11086
- })).readonly()), method(object({
11149
+ })).readonly(), { auth: "admin" }), method(object({
11087
11150
  namespace: string().optional(),
11088
11151
  collection: string()
11089
- }), boolean()), method(object({
11152
+ }), boolean(), { auth: "admin" }), method(object({
11090
11153
  namespace: string().optional(),
11091
11154
  collection: string(),
11092
11155
  columns: array(CollectionColumnSchema).readonly(),
11093
11156
  indexes: array(CollectionIndexSchema).readonly().optional()
11094
- }), _void(), { kind: "mutation" });
11157
+ }), _void(), {
11158
+ kind: "mutation",
11159
+ auth: "admin"
11160
+ });
11095
11161
  /**
11096
11162
  * shm ring usage stats for a `frameSink: 'shm'` decoder session —
11097
11163
  * exposed via `decoder.getShmStats` so downstream consumers can
@@ -11757,6 +11823,27 @@ var LinkedDeviceSchema = object({
11757
11823
  features: array(string()),
11758
11824
  producesTrackedEvents: boolean().optional()
11759
11825
  });
11826
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
11827
+ * The batch answer needs the tag; the single-device answer already has it
11828
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
11829
+ var LinkedDevicesForDeviceSchema = object({
11830
+ deviceId: number(),
11831
+ mode: LinkedDevicesModeSchema,
11832
+ devices: array(LinkedDeviceSchema)
11833
+ });
11834
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
11835
+ * `getAllBindings` all answer in. Declared once: three copies of the same
11836
+ * object literal is exactly how the three drift apart. */
11837
+ var DeviceBindingsForDeviceSchema = object({
11838
+ deviceId: number(),
11839
+ entries: array(object({
11840
+ capName: string(),
11841
+ kind: _enum(["native", "wrapped"]),
11842
+ providerAddonId: string(),
11843
+ providerNodeId: string(),
11844
+ nativeAddonId: string()
11845
+ }))
11846
+ });
11760
11847
  var SavedDeviceRowSchema = object({
11761
11848
  /** Numeric id reserved at allocateDeviceId time. */
11762
11849
  id: number(),
@@ -11982,11 +12069,25 @@ method(object({
11982
12069
  projection: _enum(["full", "slim"]).optional(),
11983
12070
  /** Return only camera devices. Filtering server-side instead of
11984
12071
  * shipping 293 rows to find 12. */
11985
- isCamera: boolean().optional()
12072
+ isCamera: boolean().optional(),
12073
+ /**
12074
+ * Return only these device ids. For the caller that already KNOWS the
12075
+ * handful it wants and needs a field the id-bearing answer does not
12076
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12077
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12078
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12079
+ * refetches on the reconcile interval, on a phone.
12080
+ *
12081
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12082
+ * keys rather than rejecting them (verified against the live hub
12083
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12084
+ * it answers today and the caller filters as it already does.
12085
+ */
12086
+ deviceIds: array(number()).optional()
11986
12087
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
11987
12088
  mode: LinkedDevicesModeSchema,
11988
12089
  devices: array(LinkedDeviceSchema)
11989
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12090
+ })), 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({
11990
12091
  deviceId: number(),
11991
12092
  values: record(string(), unknown())
11992
12093
  }), object({ success: literal(true) }), {
@@ -12013,25 +12114,7 @@ method(object({
12013
12114
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12014
12115
  kind: "mutation",
12015
12116
  auth: "admin"
12016
- }), method(object({ deviceId: number() }), object({
12017
- deviceId: number(),
12018
- entries: array(object({
12019
- capName: string(),
12020
- kind: _enum(["native", "wrapped"]),
12021
- providerAddonId: string(),
12022
- providerNodeId: string(),
12023
- nativeAddonId: string()
12024
- }))
12025
- })), method(object({}), array(object({
12026
- deviceId: number(),
12027
- entries: array(object({
12028
- capName: string(),
12029
- kind: _enum(["native", "wrapped"]),
12030
- providerAddonId: string(),
12031
- providerNodeId: string(),
12032
- nativeAddonId: string()
12033
- }))
12034
- }))), method(object({
12117
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12035
12118
  deviceId: number(),
12036
12119
  capName: string(),
12037
12120
  wrapperAddonId: string(),
@@ -12202,7 +12285,7 @@ method(object({
12202
12285
  crop: _instanceof(Uint8Array),
12203
12286
  width: number(),
12204
12287
  height: number()
12205
- }), EmbeddingResultSchema), method(object({ text: string() }), EmbeddingResultSchema), method(_void(), EmbeddingInfoSchema);
12288
+ }), EmbeddingResultSchema, { auth: "admin" }), method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }), method(_void(), EmbeddingInfoSchema, { auth: "admin" });
12206
12289
  /**
12207
12290
  * filesystem-browse — per-node capability for browsing the node's local
12208
12291
  * filesystem. Reads are unconfined (whole filesystem, from `/` down); WRITES
@@ -12495,19 +12578,22 @@ method(LlmGenerateBaseInputSchema.extend({
12495
12578
  runtime: ManagedRuntimeConfigSchema,
12496
12579
  /** The managed profile's timeout, threaded by the hub provider. */
12497
12580
  timeoutMs: number().int().positive().optional()
12498
- }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12581
+ }), LlmGenerateResultSchema, {
12582
+ kind: "mutation",
12583
+ auth: "admin"
12584
+ }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
12499
12585
  kind: "mutation",
12500
12586
  auth: "admin"
12501
12587
  }), method(object({}), _void(), {
12502
12588
  kind: "mutation",
12503
12589
  auth: "admin"
12504
- }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
12590
+ }), method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }), method(object({ model: ManagedModelRefSchema }), _void(), {
12505
12591
  kind: "mutation",
12506
12592
  auth: "admin"
12507
12593
  }), method(object({ file: string() }), _void(), {
12508
12594
  kind: "mutation",
12509
12595
  auth: "admin"
12510
- }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
12596
+ }), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" });
12511
12597
  /**
12512
12598
  * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
12513
12599
  * methods concat-fan across providers; single-row methods route to ONE
@@ -14403,12 +14489,15 @@ var NcOccupancyConditionSchema = object({
14403
14489
  * there is no second switch that can disagree with the first and every rule
14404
14490
  * authored before the decision migrates for free (`audioModeOf`):
14405
14491
  *
14406
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14407
- * classifier labels with one of them. No window, no percentage:
14408
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14409
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14410
- * the analyzer's (`classificationMinScore`, per device) a label only
14411
- * reaches this condition if the classifier was already confident enough.
14492
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14493
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14494
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14495
+ * frames is the wrong question for a classifier that labels 1–3 frames
14496
+ * per episode. The count window is the brake that drops a single-frame
14497
+ * false positive; the rule's own `throttle` cooldown is the other. The
14498
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14499
+ * per device) — a label only reaches this condition if the classifier was
14500
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14412
14501
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14413
14502
  * the condition: at least `hitPercent`% of the samples over
14414
14503
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14435,14 +14524,22 @@ var NcOccupancyConditionSchema = object({
14435
14524
  * an operator who typed `dog` mean the same thing.
14436
14525
  */
14437
14526
  var NcAudioConditionSchema = object({
14438
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14527
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14439
14528
  labels: array(string().min(1)).min(1).optional(),
14440
14529
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14441
14530
  dbThreshold: number().min(-96).max(0).optional(),
14442
14531
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14443
14532
  hitPercent: number().int().min(1).max(100).default(60),
14444
14533
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14445
- samplingSeconds: number().int().min(1).max(300).default(10)
14534
+ samplingSeconds: number().int().min(1).max(300).default(10),
14535
+ /**
14536
+ * LABEL MODE: how many labelled frames must land inside
14537
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14538
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14539
+ */
14540
+ confirmHits: number().int().min(1).max(20).optional(),
14541
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14542
+ confirmWindowSec: number().int().min(1).max(60).optional()
14446
14543
  });
14447
14544
  /**
14448
14545
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -15969,7 +16066,7 @@ var OauthIntegrationDescriptorSchema = object({
15969
16066
  */
15970
16067
  refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
15971
16068
  });
15972
- method(_void(), OauthIntegrationDescriptorSchema);
16069
+ method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
15973
16070
  /**
15974
16071
  * pipeline-analytics — device-scoped wrapper cap. Refines raw
15975
16072
  * per-frame detections emitted by the pipeline runner into tracked
@@ -16816,6 +16913,46 @@ var RecentTracksPageSchema = object({
16816
16913
  /** Cursor for the next page, or null when this page is the last. */
16817
16914
  nextCursor: string().nullable()
16818
16915
  });
16916
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
16917
+ var LIST_GROUPS_MAX_LIMIT = 100;
16918
+ var AnalyticsGroupRecordSchema = object({
16919
+ id: string(),
16920
+ deviceId: number().int(),
16921
+ openedAt: number().int(),
16922
+ closedAt: number().int(),
16923
+ timestamp: number().int(),
16924
+ memberCount: number().int(),
16925
+ memberTrackIds: array(string()).readonly(),
16926
+ className: string(),
16927
+ classes: array(string()).readonly(),
16928
+ /** Relative event-media path, or null when the group has no picture yet. */
16929
+ mediaUrl: string().nullable(),
16930
+ singleton: boolean()
16931
+ });
16932
+ var AnalyticsGroupMemberSchema = object({
16933
+ trackId: string(),
16934
+ deviceId: number().int(),
16935
+ className: string(),
16936
+ firstSeen: number().int(),
16937
+ lastSeen: number().int(),
16938
+ mediaUrl: string().nullable()
16939
+ });
16940
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
16941
+ var ListGroupsQueryInput = object({
16942
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
16943
+ deviceIds: array(number()),
16944
+ /** Window lower bound on `closedAt` (inclusive). */
16945
+ since: number().optional(),
16946
+ /** Window upper bound on `openedAt` (inclusive). */
16947
+ until: number().optional(),
16948
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
16949
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
16950
+ cursor: string().optional()
16951
+ });
16952
+ var ListGroupsPageSchema = object({
16953
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
16954
+ nextCursor: string().nullable()
16955
+ });
16819
16956
  var KeyEventQueryInput = object({
16820
16957
  deviceId: number(),
16821
16958
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16891,7 +17028,9 @@ var TrackCascadeCountsSchema = object({
16891
17028
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
16892
17029
  plates: number().int(),
16893
17030
  /** Per-track CLIP search vectors removed (best-effort). */
16894
- embeddings: number().int()
17031
+ embeddings: number().int(),
17032
+ /** Group membership + group rows removed with their last member (best-effort). */
17033
+ groups: number().int()
16895
17034
  });
16896
17035
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
16897
17036
  var DiskReconcileCountsSchema = object({
@@ -17037,7 +17176,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17037
17176
  * stationary registry). Default false: the timeline lists passages,
17038
17177
  * not parking records (operator decision, 2026-08-15). */
17039
17178
  includeStationary: boolean().optional()
17040
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17179
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17180
+ deviceId: number(),
17181
+ groupId: string().min(1)
17182
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17041
17183
  kind: "mutation",
17042
17184
  auth: "admin"
17043
17185
  }), 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({
@@ -17119,6 +17261,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17119
17261
  }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17120
17262
  kind: "mutation",
17121
17263
  auth: "admin"
17264
+ }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
17265
+ kind: "mutation",
17266
+ auth: "admin"
17267
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
17268
+ kind: "query",
17269
+ auth: "admin"
17270
+ }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
17271
+ kind: "mutation",
17272
+ auth: "admin"
17122
17273
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
17123
17274
  kind: "query",
17124
17275
  auth: "admin"
@@ -17273,6 +17424,11 @@ object({
17273
17424
  "jpeg"
17274
17425
  ])
17275
17426
  });
17427
+ /**
17428
+ * Process-local frame identity. It is serializable so it can ride an in-process
17429
+ * capability call, but `registryId` deliberately prevents resolution in any
17430
+ * other process or execution group.
17431
+ */
17276
17432
  var FrameRefSchema = object({
17277
17433
  registryId: string().min(1),
17278
17434
  id: string().min(1),
@@ -17347,7 +17503,8 @@ var PipelineModelOptionSchema = object({
17347
17503
  sizeMB: number()
17348
17504
  })),
17349
17505
  group: ModelVariantGroupSchema.optional(),
17350
- legacy: boolean().optional()
17506
+ legacy: boolean().optional(),
17507
+ provider: ModelProviderIdSchema.optional()
17351
17508
  });
17352
17509
  var ConfigFieldBridge = custom();
17353
17510
  var PipelineAddonSchemaSchema = object({
@@ -19450,7 +19607,7 @@ method(object({
19450
19607
  * linking rather than produce an eternal token.
19451
19608
  */
19452
19609
  ttlSec: union([number().int().positive(), literal("never")]).optional()
19453
- }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19610
+ }), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
19454
19611
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19455
19612
  providerId: string().min(1),
19456
19613
  displayName: string().min(1),
@@ -19545,10 +19702,13 @@ var EvictResultSchema = object({
19545
19702
  /** True when the provider has nothing left it is willing to drop on this location. */
19546
19703
  exhausted: boolean()
19547
19704
  });
19548
- method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19705
+ method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }), method(object({
19549
19706
  locationId: string(),
19550
19707
  targetBytes: number().int().positive()
19551
- }), EvictResultSchema, { kind: "mutation" });
19708
+ }), EvictResultSchema, {
19709
+ kind: "mutation",
19710
+ auth: "admin"
19711
+ });
19552
19712
  method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19553
19713
  kind: "mutation",
19554
19714
  auth: "admin"
@@ -19608,26 +19768,50 @@ var ReadChunkInputSchema = object({
19608
19768
  length: number()
19609
19769
  });
19610
19770
  var EndDownloadInputSchema = object({ downloadId: string() });
19611
- method(_void(), ProviderInfoSchema), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19771
+ method(_void(), ProviderInfoSchema, { auth: "admin" }), method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }), method(object({
19612
19772
  location: StorageLocationSchema,
19613
19773
  relativePath: string()
19614
- }), string()), method(object({
19774
+ }), string(), { auth: "admin" }), method(object({
19615
19775
  location: StorageLocationSchema,
19616
19776
  relativePath: string(),
19617
19777
  data: _instanceof(Uint8Array)
19618
- }), _void(), { kind: "mutation" }), method(object({
19778
+ }), _void(), {
19779
+ kind: "mutation",
19780
+ auth: "admin"
19781
+ }), method(object({
19619
19782
  location: StorageLocationSchema,
19620
19783
  relativePath: string()
19621
- }), _instanceof(Uint8Array)), method(object({
19784
+ }), _instanceof(Uint8Array), { auth: "admin" }), method(object({
19622
19785
  location: StorageLocationSchema,
19623
19786
  relativePath: string()
19624
- }), boolean()), method(object({
19787
+ }), boolean(), { auth: "admin" }), method(object({
19625
19788
  location: StorageLocationSchema,
19626
19789
  prefix: string().optional()
19627
- }), array(string()).readonly()), method(object({
19790
+ }), array(string()).readonly(), { auth: "admin" }), method(object({
19628
19791
  location: StorageLocationSchema,
19629
19792
  relativePath: string()
19630
- }), _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" });
19793
+ }), _void(), {
19794
+ kind: "mutation",
19795
+ auth: "admin"
19796
+ }), method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }), method(BeginUploadInputSchema, BeginUploadResultSchema, {
19797
+ kind: "mutation",
19798
+ auth: "admin"
19799
+ }), method(WriteChunkInputSchema, _void(), {
19800
+ kind: "mutation",
19801
+ auth: "admin"
19802
+ }), method(FinalizeUploadInputSchema, _void(), {
19803
+ kind: "mutation",
19804
+ auth: "admin"
19805
+ }), method(AbortUploadInputSchema, _void(), {
19806
+ kind: "mutation",
19807
+ auth: "admin"
19808
+ }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
19809
+ kind: "mutation",
19810
+ auth: "admin"
19811
+ }), method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }), method(EndDownloadInputSchema, _void(), {
19812
+ kind: "mutation",
19813
+ auth: "admin"
19814
+ });
19631
19815
  /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19632
19816
  var ProfileSettingsSchemaBridge = unknown().nullable();
19633
19817
  var ProfileSettingsBagSchema = record(string(), unknown());
@@ -19885,7 +20069,8 @@ method(object({
19885
20069
  access: "create"
19886
20070
  }), method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
19887
20071
  kind: "mutation",
19888
- access: "view"
20072
+ access: "view",
20073
+ auth: "admin"
19889
20074
  }), method(object({
19890
20075
  /** Required — the user the assertion belongs to (verified). */
19891
20076
  userId: string(),
@@ -19893,10 +20078,12 @@ method(object({
19893
20078
  response: record(string(), unknown())
19894
20079
  }), object({ verified: boolean() }), {
19895
20080
  kind: "mutation",
19896
- access: "view"
20081
+ access: "view",
20082
+ auth: "admin"
19897
20083
  }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19898
20084
  kind: "mutation",
19899
- access: "view"
20085
+ access: "view",
20086
+ auth: "admin"
19900
20087
  }), method(object({
19901
20088
  /** AuthenticationResponseJSON from the browser. */
19902
20089
  response: record(string(), unknown()) }), object({
@@ -19904,7 +20091,8 @@ response: record(string(), unknown()) }), object({
19904
20091
  userId: string().nullable()
19905
20092
  }), {
19906
20093
  kind: "mutation",
19907
- access: "view"
20094
+ access: "view",
20095
+ auth: "admin"
19908
20096
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19909
20097
  userId: string(),
19910
20098
  credentialId: string()
@@ -20076,7 +20264,19 @@ var VectorStatsResultSchema = object({
20076
20264
  /** False when the backend ranks approximately. */
20077
20265
  exact: boolean()
20078
20266
  });
20079
- 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);
20267
+ method(VectorDeclareIndexInputSchema, _void(), {
20268
+ kind: "mutation",
20269
+ auth: "admin"
20270
+ }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
20271
+ kind: "mutation",
20272
+ auth: "admin"
20273
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
20274
+ kind: "mutation",
20275
+ auth: "admin"
20276
+ }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
20277
+ kind: "mutation",
20278
+ auth: "admin"
20279
+ }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
20080
20280
  var ClipSchema = object({
20081
20281
  /** Opaque, provider-namespaced id. The default provider encodes the time
20082
20282
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21799,7 +21999,27 @@ var MediaFileLiteSchema$1 = object({
21799
21999
  sizeBytes: number(),
21800
22000
  timestamp: number()
21801
22001
  });
21802
- method(_void(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
22002
+ method(object({
22003
+ /**
22004
+ * Inline {@link IdentitySchema.coverBase64} on every row.
22005
+ *
22006
+ * Default `false`, the same inversion `listRecentFaces` and
22007
+ * `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
22008
+ * why the burden belongs on the caller that WANTS the bytes). Measured
22009
+ * on the live hub the same day: four identities cost 40,979 B with the
22010
+ * covers inline, ~10 KB of base64 per row, on a query this UI mounts
22011
+ * four times and the viewer holds at `staleTime: 30_000`.
22012
+ *
22013
+ * Nothing loses its avatar: `coverMediaKey` is already on every row and
22014
+ * the `event-media` plane serves that key `immutable` with an ETag.
22015
+ *
22016
+ * **This is an INPUT field, so it does not reach the addon until the
22017
+ * next train** — the hub router validates cap inputs against its own
22018
+ * compiled Zod and strips a key it does not know. Until then the
22019
+ * provider sees `undefined`, which resolves to `false`: the cheap shape
22020
+ * is what ships, and the opt-in becomes reachable when the train lands.
22021
+ */
22022
+ includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
21803
22023
  kind: "mutation",
21804
22024
  auth: "admin"
21805
22025
  }), method(object({
@@ -23944,7 +24164,14 @@ var PlateInfoSchema = object({
23944
24164
  plateBbox: BoundingBoxSchema.optional(),
23945
24165
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
23946
24166
  keyFrameMediaKey: string().optional(),
23947
- base64: string().optional()
24167
+ base64: string().optional(),
24168
+ /**
24169
+ * Same crop as a data-plane URL, always present when the plate has a stored
24170
+ * crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
24171
+ * and `searchPlates` inline the crop only when their `includeCrops` input is
24172
+ * left at its `true` default.
24173
+ */
24174
+ cropUrl: string().optional()
23948
24175
  });
23949
24176
  var MediaFileLiteSchema = object({
23950
24177
  key: string(),
@@ -23962,14 +24189,34 @@ var PlateClusterSchema = object({
23962
24189
  });
23963
24190
  method(object({
23964
24191
  deviceId: number().int().optional(),
23965
- limit: number().int().positive().optional()
24192
+ limit: number().int().positive().optional(),
24193
+ /**
24194
+ * Inline the base64 crop on every row. Default `true` — the existing
24195
+ * behaviour, kept so no caller breaks.
24196
+ *
24197
+ * Set `false` once the caller renders {@link PlateInfo.cropUrl}.
24198
+ * Measured on the live hub at the 500 rows the Plates view asks for:
24199
+ * 879,403 B and 27.7 s with the crops inline, against a few KiB of
24200
+ * metadata without them — and the browser then caches the images.
24201
+ *
24202
+ * This is the plate twin of `faceGallery.listRecentFaces`'s option;
24203
+ * plates were the one gallery list left without it.
24204
+ *
24205
+ * **This is an INPUT field, so it does not reach the addon until the
24206
+ * next train.** The hub router validates cap inputs against its own
24207
+ * compiled Zod and strips a key it does not know. Until the train
24208
+ * ships, sending `false` is harmless and keeps the crops inline.
24209
+ */
24210
+ includeCrops: boolean().optional()
23966
24211
  }).optional(), array(PlateInfoSchema).readonly()), method(object({
23967
24212
  deviceId: number().int(),
23968
24213
  trackId: string()
23969
24214
  }), PlateInfoSchema.nullable()), method(object({ plateId: string() }), array(MediaFileLiteSchema).readonly()), method(object({
23970
24215
  text: string().min(1),
23971
24216
  maxDistance: number().int().min(0).optional(),
23972
- limit: number().int().positive().optional()
24217
+ limit: number().int().positive().optional(),
24218
+ /** See `listPlates.includeCrops`. Default `true`. */
24219
+ includeCrops: boolean().optional()
23973
24220
  }), array(PlateInfoSchema).readonly()), method(object({
23974
24221
  maxDistance: number().int().min(0).optional(),
23975
24222
  minClusterSize: number().int().min(2).optional(),
@@ -23983,7 +24230,13 @@ method(object({
23983
24230
  }), method(object({ plateId: string() }), _void(), {
23984
24231
  kind: "mutation",
23985
24232
  auth: "admin"
23986
- }), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
24233
+ }), method(object({
24234
+ /** Inline {@link VehicleSchema.coverBase64} on every row. Default
24235
+ * `false` — the vehicle twin of `faceGallery.listIdentities`'s
24236
+ * option; `coverMediaKey` + the `event-media` plane carry the picture.
24237
+ * INPUT field: stripped by the hub router until the train ships, which
24238
+ * resolves to `false` and is exactly the intended default. */
24239
+ includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
23987
24240
  kind: "mutation",
23988
24241
  auth: "admin"
23989
24242
  }), method(object({
@@ -27584,6 +27837,12 @@ Object.freeze({
27584
27837
  addonId: null,
27585
27838
  access: "view"
27586
27839
  },
27840
+ "deviceManager.getBindingsBatch": {
27841
+ capName: "device-manager",
27842
+ capScope: "system",
27843
+ addonId: null,
27844
+ access: "view"
27845
+ },
27587
27846
  "deviceManager.getChildren": {
27588
27847
  capName: "device-manager",
27589
27848
  capScope: "system",
@@ -27644,6 +27903,12 @@ Object.freeze({
27644
27903
  addonId: null,
27645
27904
  access: "view"
27646
27905
  },
27906
+ "deviceManager.getLinkedDevicesBatch": {
27907
+ capName: "device-manager",
27908
+ capScope: "system",
27909
+ addonId: null,
27910
+ access: "view"
27911
+ },
27647
27912
  "deviceManager.getRoleDisplayDefaults": {
27648
27913
  capName: "device-manager",
27649
27914
  capScope: "system",
@@ -29348,6 +29613,12 @@ Object.freeze({
29348
29613
  addonId: null,
29349
29614
  access: "create"
29350
29615
  },
29616
+ "pipelineAnalytics.cancelRelocateMedia": {
29617
+ capName: "pipeline-analytics",
29618
+ capScope: "device",
29619
+ addonId: null,
29620
+ access: "create"
29621
+ },
29351
29622
  "pipelineAnalytics.cancelStorageMigrationMove": {
29352
29623
  capName: "pipeline-analytics",
29353
29624
  capScope: "device",
@@ -29414,6 +29685,12 @@ Object.freeze({
29414
29685
  addonId: null,
29415
29686
  access: "view"
29416
29687
  },
29688
+ "pipelineAnalytics.getGroup": {
29689
+ capName: "pipeline-analytics",
29690
+ capScope: "device",
29691
+ addonId: null,
29692
+ access: "view"
29693
+ },
29417
29694
  "pipelineAnalytics.getKeyEvents": {
29418
29695
  capName: "pipeline-analytics",
29419
29696
  capScope: "device",
@@ -29498,6 +29775,12 @@ Object.freeze({
29498
29775
  addonId: null,
29499
29776
  access: "view"
29500
29777
  },
29778
+ "pipelineAnalytics.listGroups": {
29779
+ capName: "pipeline-analytics",
29780
+ capScope: "device",
29781
+ addonId: null,
29782
+ access: "view"
29783
+ },
29501
29784
  "pipelineAnalytics.listOpsLog": {
29502
29785
  capName: "pipeline-analytics",
29503
29786
  capScope: "device",
@@ -29510,6 +29793,12 @@ Object.freeze({
29510
29793
  addonId: null,
29511
29794
  access: "view"
29512
29795
  },
29796
+ "pipelineAnalytics.listRelocateMediaJobs": {
29797
+ capName: "pipeline-analytics",
29798
+ capScope: "device",
29799
+ addonId: null,
29800
+ access: "view"
29801
+ },
29513
29802
  "pipelineAnalytics.listRetrainAnnotations": {
29514
29803
  capName: "pipeline-analytics",
29515
29804
  capScope: "device",
@@ -29588,6 +29877,12 @@ Object.freeze({
29588
29877
  addonId: null,
29589
29878
  access: "create"
29590
29879
  },
29880
+ "pipelineAnalytics.relocateMedia": {
29881
+ capName: "pipeline-analytics",
29882
+ capScope: "device",
29883
+ addonId: null,
29884
+ access: "create"
29885
+ },
29591
29886
  "pipelineAnalytics.restageRetrainTrack": {
29592
29887
  capName: "pipeline-analytics",
29593
29888
  capScope: "device",
@@ -32279,6 +32574,11 @@ Object.freeze({
32279
32574
  form: "single",
32280
32575
  optional: false
32281
32576
  }],
32577
+ "deviceManager.getBindingsBatch": [{
32578
+ name: "deviceIds",
32579
+ form: "array",
32580
+ optional: false
32581
+ }],
32282
32582
  "deviceManager.getChildren": [{
32283
32583
  name: "parentDeviceId",
32284
32584
  form: "single",
@@ -32324,6 +32624,11 @@ Object.freeze({
32324
32624
  form: "single",
32325
32625
  optional: false
32326
32626
  }],
32627
+ "deviceManager.getLinkedDevicesBatch": [{
32628
+ name: "deviceIds",
32629
+ form: "array",
32630
+ optional: false
32631
+ }],
32327
32632
  "deviceManager.getSettingsSchema": [{
32328
32633
  name: "deviceId",
32329
32634
  form: "single",
@@ -32344,6 +32649,11 @@ Object.freeze({
32344
32649
  form: "single",
32345
32650
  optional: false
32346
32651
  }],
32652
+ "deviceManager.listAll": [{
32653
+ name: "deviceIds",
32654
+ form: "array",
32655
+ optional: true
32656
+ }],
32347
32657
  "deviceManager.loadConfig": [{
32348
32658
  name: "deviceId",
32349
32659
  form: "single",
@@ -32917,6 +33227,11 @@ Object.freeze({
32917
33227
  form: "single",
32918
33228
  optional: false
32919
33229
  }],
33230
+ "pipelineAnalytics.getGroup": [{
33231
+ name: "deviceId",
33232
+ form: "single",
33233
+ optional: false
33234
+ }],
32920
33235
  "pipelineAnalytics.getKeyEvents": [{
32921
33236
  name: "deviceId",
32922
33237
  form: "single",
@@ -32972,6 +33287,11 @@ Object.freeze({
32972
33287
  form: "array",
32973
33288
  optional: false
32974
33289
  }],
33290
+ "pipelineAnalytics.listGroups": [{
33291
+ name: "deviceIds",
33292
+ form: "array",
33293
+ optional: false
33294
+ }],
32975
33295
  "pipelineAnalytics.listOpsLog": [{
32976
33296
  name: "deviceId",
32977
33297
  form: "single",