@camstack/addon-provider-hikvision 1.2.33 → 1.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +432 -50
  2. package/dist/addon.mjs +432 -50
  3. package/package.json +1 -1
package/dist/addon.mjs CHANGED
@@ -5809,6 +5809,13 @@ var BaseAddon = class {
5809
5809
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5810
5810
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5811
5811
  _registeredCapNames = [];
5812
+ /**
5813
+ * True only after `readAddonStore` actually answered. Constructor
5814
+ * defaults look like stored config when the store is down — a forked
5815
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5816
+ * mode, 2026-08-25) is not "the operator chose this".
5817
+ */
5818
+ settingsStoreReady = false;
5812
5819
  /** Default config values. Provided via constructor. */
5813
5820
  defaults;
5814
5821
  constructor(defaults) {
@@ -6209,7 +6216,9 @@ var BaseAddon = class {
6209
6216
  ];
6210
6217
  let lastErr;
6211
6218
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6212
- return await settings.readAddonStore() ?? {};
6219
+ const stored = await settings.readAddonStore() ?? {};
6220
+ this.settingsStoreReady = true;
6221
+ return stored;
6213
6222
  } catch (err) {
6214
6223
  lastErr = err;
6215
6224
  const msg = err instanceof Error ? err.message : String(err);
@@ -6217,6 +6226,7 @@ var BaseAddon = class {
6217
6226
  if (attempt === delaysMs.length) break;
6218
6227
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6219
6228
  }
6229
+ this.settingsStoreReady = false;
6220
6230
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6221
6231
  return {};
6222
6232
  }
@@ -8191,6 +8201,15 @@ var LabelDefinitionSchema = object({
8191
8201
  description: string().optional(),
8192
8202
  icon: string().optional()
8193
8203
  });
8204
+ var ClassMapDefinitionSchema = object({
8205
+ mapping: record(string(), _enum([
8206
+ "person",
8207
+ "vehicle",
8208
+ "animal",
8209
+ "package"
8210
+ ])),
8211
+ preserveOriginal: boolean()
8212
+ });
8194
8213
  var MODEL_FORMATS = [
8195
8214
  "onnx",
8196
8215
  "coreml",
@@ -8274,6 +8293,12 @@ var ModelVariantGroupSchema = object({
8274
8293
  */
8275
8294
  resolution: number().int().positive().optional()
8276
8295
  });
8296
+ var ModelProviderIdSchema = _enum([
8297
+ "camstack",
8298
+ "frigate",
8299
+ "scrypted",
8300
+ "custom"
8301
+ ]);
8277
8302
  var ModelCatalogEntrySchema = object({
8278
8303
  id: string(),
8279
8304
  name: string(),
@@ -8369,7 +8394,19 @@ var ModelCatalogEntrySchema = object({
8369
8394
  * `id` stays the source of truth for resolution/download/persistence; grouping
8370
8395
  * is a presentation overlay resolved back to an `id`.
8371
8396
  */
8372
- group: ModelVariantGroupSchema.optional()
8397
+ group: ModelVariantGroupSchema.optional(),
8398
+ /**
8399
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8400
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8401
+ * persisted before this field existed (`inferModelProvider` fills those).
8402
+ */
8403
+ provider: ModelProviderIdSchema.optional(),
8404
+ /**
8405
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8406
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8407
+ * labels already ARE the CamStack macros (Scrypted identity map).
8408
+ */
8409
+ classMap: ClassMapDefinitionSchema.optional()
8373
8410
  });
8374
8411
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8375
8412
  format: literal("openvino"),
@@ -8398,7 +8435,8 @@ var ModelConvertMetadataSchema = object({
8398
8435
  "ocr",
8399
8436
  "segmentation"
8400
8437
  ]),
8401
- faceAlignment: boolean().optional()
8438
+ faceAlignment: boolean().optional(),
8439
+ classMap: ClassMapDefinitionSchema.optional()
8402
8440
  });
8403
8441
  var ConvertResultSchema = object({
8404
8442
  entry: ModelCatalogEntrySchema,
@@ -12167,6 +12205,27 @@ var LinkedDeviceSchema = object({
12167
12205
  features: array(string()),
12168
12206
  producesTrackedEvents: boolean().optional()
12169
12207
  });
12208
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12209
+ * The batch answer needs the tag; the single-device answer already has it
12210
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12211
+ var LinkedDevicesForDeviceSchema = object({
12212
+ deviceId: number(),
12213
+ mode: LinkedDevicesModeSchema,
12214
+ devices: array(LinkedDeviceSchema)
12215
+ });
12216
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12217
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12218
+ * object literal is exactly how the three drift apart. */
12219
+ var DeviceBindingsForDeviceSchema = object({
12220
+ deviceId: number(),
12221
+ entries: array(object({
12222
+ capName: string(),
12223
+ kind: _enum(["native", "wrapped"]),
12224
+ providerAddonId: string(),
12225
+ providerNodeId: string(),
12226
+ nativeAddonId: string()
12227
+ }))
12228
+ });
12170
12229
  var SavedDeviceRowSchema = object({
12171
12230
  /** Numeric id reserved at allocateDeviceId time. */
12172
12231
  id: number(),
@@ -12392,11 +12451,25 @@ method(object({
12392
12451
  projection: _enum(["full", "slim"]).optional(),
12393
12452
  /** Return only camera devices. Filtering server-side instead of
12394
12453
  * shipping 293 rows to find 12. */
12395
- isCamera: boolean().optional()
12454
+ isCamera: boolean().optional(),
12455
+ /**
12456
+ * Return only these device ids. For the caller that already KNOWS the
12457
+ * handful it wants and needs a field the id-bearing answer does not
12458
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12459
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12460
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12461
+ * refetches on the reconcile interval, on a phone.
12462
+ *
12463
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12464
+ * keys rather than rejecting them (verified against the live hub
12465
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12466
+ * it answers today and the caller filters as it already does.
12467
+ */
12468
+ deviceIds: array(number()).optional()
12396
12469
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12397
12470
  mode: LinkedDevicesModeSchema,
12398
12471
  devices: array(LinkedDeviceSchema)
12399
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12472
+ })), 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({
12400
12473
  deviceId: number(),
12401
12474
  values: record(string(), unknown())
12402
12475
  }), object({ success: literal(true) }), {
@@ -12423,25 +12496,7 @@ method(object({
12423
12496
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12424
12497
  kind: "mutation",
12425
12498
  auth: "admin"
12426
- }), method(object({ deviceId: number() }), object({
12427
- deviceId: number(),
12428
- entries: array(object({
12429
- capName: string(),
12430
- kind: _enum(["native", "wrapped"]),
12431
- providerAddonId: string(),
12432
- providerNodeId: string(),
12433
- nativeAddonId: string()
12434
- }))
12435
- })), method(object({}), array(object({
12436
- deviceId: number(),
12437
- entries: array(object({
12438
- capName: string(),
12439
- kind: _enum(["native", "wrapped"]),
12440
- providerAddonId: string(),
12441
- providerNodeId: string(),
12442
- nativeAddonId: string()
12443
- }))
12444
- }))), method(object({
12499
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12445
12500
  deviceId: number(),
12446
12501
  capName: string(),
12447
12502
  wrapperAddonId: string(),
@@ -14851,12 +14906,15 @@ var NcOccupancyConditionSchema = object({
14851
14906
  * there is no second switch that can disagree with the first and every rule
14852
14907
  * authored before the decision migrates for free (`audioModeOf`):
14853
14908
  *
14854
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14855
- * classifier labels with one of them. No window, no percentage:
14856
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14857
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14858
- * the analyzer's (`classificationMinScore`, per device) a label only
14859
- * reaches this condition if the classifier was already confident enough.
14909
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14910
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14911
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14912
+ * frames is the wrong question for a classifier that labels 1–3 frames
14913
+ * per episode. The count window is the brake that drops a single-frame
14914
+ * false positive; the rule's own `throttle` cooldown is the other. The
14915
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14916
+ * per device) — a label only reaches this condition if the classifier was
14917
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14860
14918
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14861
14919
  * the condition: at least `hitPercent`% of the samples over
14862
14920
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14883,14 +14941,22 @@ var NcOccupancyConditionSchema = object({
14883
14941
  * an operator who typed `dog` mean the same thing.
14884
14942
  */
14885
14943
  var NcAudioConditionSchema = object({
14886
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14944
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14887
14945
  labels: array(string().min(1)).min(1).optional(),
14888
14946
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14889
14947
  dbThreshold: number().min(-96).max(0).optional(),
14890
14948
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14891
14949
  hitPercent: number().int().min(1).max(100).default(60),
14892
14950
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14893
- samplingSeconds: number().int().min(1).max(300).default(10)
14951
+ samplingSeconds: number().int().min(1).max(300).default(10),
14952
+ /**
14953
+ * LABEL MODE: how many labelled frames must land inside
14954
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14955
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14956
+ */
14957
+ confirmHits: number().int().min(1).max(20).optional(),
14958
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14959
+ confirmWindowSec: number().int().min(1).max(60).optional()
14894
14960
  });
14895
14961
  /**
14896
14962
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -17264,6 +17330,46 @@ var RecentTracksPageSchema = object({
17264
17330
  /** Cursor for the next page, or null when this page is the last. */
17265
17331
  nextCursor: string().nullable()
17266
17332
  });
17333
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17334
+ var LIST_GROUPS_MAX_LIMIT = 100;
17335
+ var AnalyticsGroupRecordSchema = object({
17336
+ id: string(),
17337
+ deviceId: number().int(),
17338
+ openedAt: number().int(),
17339
+ closedAt: number().int(),
17340
+ timestamp: number().int(),
17341
+ memberCount: number().int(),
17342
+ memberTrackIds: array(string()).readonly(),
17343
+ className: string(),
17344
+ classes: array(string()).readonly(),
17345
+ /** Relative event-media path, or null when the group has no picture yet. */
17346
+ mediaUrl: string().nullable(),
17347
+ singleton: boolean()
17348
+ });
17349
+ var AnalyticsGroupMemberSchema = object({
17350
+ trackId: string(),
17351
+ deviceId: number().int(),
17352
+ className: string(),
17353
+ firstSeen: number().int(),
17354
+ lastSeen: number().int(),
17355
+ mediaUrl: string().nullable()
17356
+ });
17357
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17358
+ var ListGroupsQueryInput = object({
17359
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17360
+ deviceIds: array(number()),
17361
+ /** Window lower bound on `closedAt` (inclusive). */
17362
+ since: number().optional(),
17363
+ /** Window upper bound on `openedAt` (inclusive). */
17364
+ until: number().optional(),
17365
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17366
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17367
+ cursor: string().optional()
17368
+ });
17369
+ var ListGroupsPageSchema = object({
17370
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17371
+ nextCursor: string().nullable()
17372
+ });
17267
17373
  var KeyEventQueryInput = object({
17268
17374
  deviceId: number(),
17269
17375
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17339,7 +17445,9 @@ var TrackCascadeCountsSchema = object({
17339
17445
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17340
17446
  plates: number().int(),
17341
17447
  /** Per-track CLIP search vectors removed (best-effort). */
17342
- embeddings: number().int()
17448
+ embeddings: number().int(),
17449
+ /** Group membership + group rows removed with their last member (best-effort). */
17450
+ groups: number().int()
17343
17451
  });
17344
17452
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17345
17453
  var DiskReconcileCountsSchema = object({
@@ -17485,7 +17593,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17485
17593
  * stationary registry). Default false: the timeline lists passages,
17486
17594
  * not parking records (operator decision, 2026-08-15). */
17487
17595
  includeStationary: boolean().optional()
17488
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17596
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17597
+ deviceId: number(),
17598
+ groupId: string().min(1)
17599
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17489
17600
  kind: "mutation",
17490
17601
  auth: "admin"
17491
17602
  }), 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({
@@ -17703,6 +17814,33 @@ var NativeCropRefSchema = object({
17703
17814
  h: number()
17704
17815
  })
17705
17816
  });
17817
+ object({
17818
+ crop: object({
17819
+ left: number(),
17820
+ top: number(),
17821
+ width: number().positive(),
17822
+ height: number().positive()
17823
+ }).optional(),
17824
+ content: object({
17825
+ width: number().int().positive(),
17826
+ height: number().int().positive()
17827
+ }),
17828
+ fit: _enum(["stretch", "contain"]),
17829
+ format: _enum([
17830
+ "rgb",
17831
+ "gray",
17832
+ "jpeg"
17833
+ ])
17834
+ });
17835
+ var FrameRefSchema = object({
17836
+ registryId: string().min(1),
17837
+ id: string().min(1),
17838
+ width: number().int().positive(),
17839
+ height: number().int().positive(),
17840
+ format: _enum(["rgb", "gray"]),
17841
+ timestamp: number(),
17842
+ capturedAt: number().optional()
17843
+ });
17706
17844
  var ModelFormatSchema$1 = _enum([
17707
17845
  "onnx",
17708
17846
  "coreml",
@@ -17768,7 +17906,8 @@ var PipelineModelOptionSchema = object({
17768
17906
  sizeMB: number()
17769
17907
  })),
17770
17908
  group: ModelVariantGroupSchema.optional(),
17771
- legacy: boolean().optional()
17909
+ legacy: boolean().optional(),
17910
+ provider: ModelProviderIdSchema.optional()
17772
17911
  });
17773
17912
  var ConfigFieldBridge = custom();
17774
17913
  var PipelineAddonSchemaSchema = object({
@@ -17947,6 +18086,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17947
18086
  steps: array(PipelineStepInputSchema).min(1),
17948
18087
  frame: FrameInputSchema.optional(),
17949
18088
  /**
18089
+ * Process-local lazy frame. Valid only when caller and provider resolve
18090
+ * in the same execution-group process; split/cross-node callers use
18091
+ * `frame`/`image` inline compatibility instead.
18092
+ */
18093
+ frameRef: FrameRefSchema.optional(),
18094
+ /**
17950
18095
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17951
18096
  * the decoded pixels live in. One more member of the one-of
17952
18097
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18242,7 +18387,10 @@ var NativeCropResultSchema = object({
18242
18387
  * Which source served this crop, so a quality-sensitive consumer (the native
18243
18388
  * `keyFrame`) can reject a degraded fallback:
18244
18389
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18245
- * quality path).
18390
+ * quality path). A subject-tile serve is also native-resolution and stays
18391
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18392
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18393
+ * internal crop result (`nativeHits` vs `tileHits`).
18246
18394
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18247
18395
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18248
18396
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18733,12 +18881,41 @@ var RunnerLocalLoadSchema = object({
18733
18881
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18734
18882
  * working unchanged when they switch to reading from the runner cap.
18735
18883
  */
18884
+ var FrameLazyCountersSchema = object({
18885
+ framesDecoded: number(),
18886
+ framesAdmitted: number(),
18887
+ framesDroppedPixelFree: number(),
18888
+ viewsMaterialized: number(),
18889
+ viewsSkipped: number(),
18890
+ workerToRunnerBytes: number(),
18891
+ runnerToPoolRawBytes: number(),
18892
+ runnerToPoolJpegBytes: number(),
18893
+ onDemandFullFrameRequests: number(),
18894
+ onDemandCropRequests: number(),
18895
+ nativeHits: number(),
18896
+ nativeMisses: number(),
18897
+ tileHits: number(),
18898
+ tileMisses: number(),
18899
+ fallbackHits: number(),
18900
+ fallbackMisses: number(),
18901
+ retainedWritesAvoided: number(),
18902
+ residentRefs: number(),
18903
+ residentBytes: number(),
18904
+ releases: number(),
18905
+ evictions: number(),
18906
+ staleMisses: number()
18907
+ });
18908
+ var FrameLazyMetricsSchema = object({
18909
+ node: FrameLazyCountersSchema,
18910
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18911
+ });
18736
18912
  var RunnerLocalMetricsSchema = object({
18737
18913
  nodeId: string(),
18738
18914
  activeCameras: number(),
18739
18915
  throttledCameras: number(),
18740
18916
  avgInferenceTimeMs: number(),
18741
- queueDepth: number()
18917
+ queueDepth: number(),
18918
+ frameLazy: FrameLazyMetricsSchema.optional()
18742
18919
  });
18743
18920
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
18744
18921
  handle: FrameHandleSchema,
@@ -20142,6 +20319,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20142
20319
  location: StorageLocationSchema,
20143
20320
  relativePath: string()
20144
20321
  }), _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" });
20322
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20323
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20324
+ var ProfileSettingsBagSchema = record(string(), unknown());
20145
20325
  /**
20146
20326
  * A live terminal session hosted by the provider addon. Output and input do
20147
20327
  * NOT flow through the capability — they use the addon data plane
@@ -20171,7 +20351,14 @@ var TerminalSessionInfoSchema = object({
20171
20351
  var TerminalProfileInfoSchema = object({
20172
20352
  profileId: string(),
20173
20353
  label: string(),
20174
- description: string().optional()
20354
+ description: string().optional(),
20355
+ /** Spawn defaults the instance form copies on create. */
20356
+ executable: string().optional(),
20357
+ args: array(string()).readonly().optional(),
20358
+ cwd: string().optional(),
20359
+ environment: array(string()).readonly().optional(),
20360
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20361
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20175
20362
  });
20176
20363
  /**
20177
20364
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20184,7 +20371,12 @@ var TerminalInstanceInfoSchema = object({
20184
20371
  profileId: string(),
20185
20372
  profileLabel: string(),
20186
20373
  name: string(),
20187
- enabled: boolean()
20374
+ enabled: boolean(),
20375
+ executable: string(),
20376
+ args: array(string()).readonly(),
20377
+ cwd: string(),
20378
+ environment: array(string()).readonly(),
20379
+ profileSettings: ProfileSettingsBagSchema
20188
20380
  });
20189
20381
  var TerminalLegacyCameraSchema = object({
20190
20382
  stableId: string(),
@@ -20214,7 +20406,23 @@ var TerminalOutputBatchSchema = object({
20214
20406
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20215
20407
  targetNodeId: string().min(1),
20216
20408
  profileId: string().min(1),
20217
- name: string().trim().min(1).max(160).optional()
20409
+ name: string().trim().min(1).max(160).optional(),
20410
+ executable: string().max(1024).optional(),
20411
+ args: array(string().max(2048)).max(64).optional(),
20412
+ cwd: string().max(1024).optional(),
20413
+ environment: array(string().max(4096)).max(64).optional(),
20414
+ profileSettings: ProfileSettingsBagSchema.optional()
20415
+ }), TerminalInstanceInfoSchema, {
20416
+ kind: "mutation",
20417
+ auth: "admin"
20418
+ }), method(object({
20419
+ instanceId: string().min(1),
20420
+ name: string().trim().min(1).max(160).optional(),
20421
+ executable: string().max(1024).optional(),
20422
+ args: array(string().max(2048)).max(64).optional(),
20423
+ cwd: string().max(1024).optional(),
20424
+ environment: array(string().max(4096)).max(64).optional(),
20425
+ profileSettings: ProfileSettingsBagSchema.optional()
20218
20426
  }), TerminalInstanceInfoSchema, {
20219
20427
  kind: "mutation",
20220
20428
  auth: "admin"
@@ -20236,7 +20444,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20236
20444
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20237
20445
  profileId: string(),
20238
20446
  cols: number().int().positive(),
20239
- rows: number().int().positive()
20447
+ rows: number().int().positive(),
20448
+ executable: string().max(1024).optional(),
20449
+ args: array(string().max(2048)).max(64).optional(),
20450
+ cwd: string().max(1024).optional(),
20451
+ environment: array(string().max(4096)).max(64).optional()
20240
20452
  }), TerminalSessionInfoSchema, {
20241
20453
  kind: "mutation",
20242
20454
  auth: "admin"
@@ -24111,10 +24323,10 @@ var lawnMowerControlCapability = {
24111
24323
  *
24112
24324
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24113
24325
  * to receive an ordered list of candidate base URLs it should race
24114
- * on connect — LAN IPv4 first (lowest latency when on same network),
24115
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24116
- * race them with short timeouts and stick with the winner for the
24117
- * session.
24326
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24327
+ * when on the same network), then public hostname (if a tunnel is
24328
+ * up). The SDK can race them with short timeouts and stick with the
24329
+ * winner for the session.
24118
24330
  *
24119
24331
  * Why hub-only: agents are not directly addressable by the operator's
24120
24332
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24269,6 +24481,17 @@ var NotificationEndpointSchema = object({
24269
24481
  /** What the ranking currently resolves to (null when nothing is reachable). */
24270
24482
  resolved: string().nullable()
24271
24483
  });
24484
+ /**
24485
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24486
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24487
+ * currently expands to, so the UI can show the effective set either way.
24488
+ */
24489
+ var ViewerEndpointsSchema = object({
24490
+ /** The operator's explicit race set, or empty for AUTO. */
24491
+ baseUrls: array(string()).readonly(),
24492
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24493
+ resolved: array(string()).readonly()
24494
+ });
24272
24495
  var AllowedAddressesSchema = object({
24273
24496
  /**
24274
24497
  * Allowlist of interface addresses operators have explicitly opted
@@ -24277,6 +24500,20 @@ var AllowedAddressesSchema = object({
24277
24500
  * Network Addresses admin page and persisted by the addon.
24278
24501
  */
24279
24502
  addresses: array(string()).readonly() });
24503
+ var TlsStatusSchema = object({
24504
+ mode: _enum([
24505
+ "generated",
24506
+ "uploaded",
24507
+ "disabled"
24508
+ ]),
24509
+ leafFingerprintSha256: string().nullable(),
24510
+ caFingerprintSha256: string().nullable(),
24511
+ validTo: string().nullable(),
24512
+ sans: array(string()),
24513
+ caCertPem: string().nullable(),
24514
+ reissueError: string().nullable(),
24515
+ restartRequired: boolean()
24516
+ });
24280
24517
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24281
24518
  /**
24282
24519
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24286,17 +24523,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24286
24523
  */
24287
24524
  port: number().int().min(1).max(65535).optional(),
24288
24525
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24289
- * candidate. Default `true`. */
24526
+ * candidate. Default `false` — loopback is not a client route. */
24290
24527
  includeLoopback: boolean().optional(),
24291
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24292
- * Default `false`. */
24528
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24529
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24530
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24293
24531
  ipv4Only: boolean().optional(),
24294
24532
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24295
24533
  * Pass `'https'` when the caller is itself loaded over HTTPS
24296
24534
  * to avoid mixed-content blocks in the browser. The public
24297
24535
  * tunnel always emits `https://` regardless. */
24298
24536
  scheme: _enum(["http", "https"]).optional()
24299
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
24537
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
24538
+ kind: "mutation",
24539
+ auth: "admin"
24540
+ }), method(object({
24541
+ certPem: string().min(1),
24542
+ keyPem: string().min(1),
24543
+ caPem: string().optional()
24544
+ }), TlsStatusSchema, {
24545
+ kind: "mutation",
24546
+ auth: "admin"
24547
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24548
+ kind: "mutation",
24549
+ auth: "admin"
24550
+ });
24300
24551
  var LockControlStatusSchema = object({
24301
24552
  /** Lifecycle state of the lock. `jammed` means the motor reported
24302
24553
  * failure to reach the target — operator intervention required. */
@@ -25903,7 +26154,12 @@ var PlateInfoSchema = object({
25903
26154
  plateBbox: BoundingBoxSchema.optional(),
25904
26155
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25905
26156
  keyFrameMediaKey: string().optional(),
25906
- base64: string().optional()
26157
+ base64: string().optional(),
26158
+ /**
26159
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26160
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26161
+ */
26162
+ cropUrl: string().optional()
25907
26163
  });
25908
26164
  var MediaFileLiteSchema = object({
25909
26165
  key: string(),
@@ -31945,6 +32201,12 @@ Object.freeze({
31945
32201
  addonId: null,
31946
32202
  access: "view"
31947
32203
  },
32204
+ "deviceManager.getBindingsBatch": {
32205
+ capName: "device-manager",
32206
+ capScope: "system",
32207
+ addonId: null,
32208
+ access: "view"
32209
+ },
31948
32210
  "deviceManager.getChildren": {
31949
32211
  capName: "device-manager",
31950
32212
  capScope: "system",
@@ -32005,6 +32267,12 @@ Object.freeze({
32005
32267
  addonId: null,
32006
32268
  access: "view"
32007
32269
  },
32270
+ "deviceManager.getLinkedDevicesBatch": {
32271
+ capName: "device-manager",
32272
+ capScope: "system",
32273
+ addonId: null,
32274
+ access: "view"
32275
+ },
32008
32276
  "deviceManager.getRoleDisplayDefaults": {
32009
32277
  capName: "device-manager",
32010
32278
  capScope: "system",
@@ -32887,6 +33155,12 @@ Object.freeze({
32887
33155
  addonId: null,
32888
33156
  access: "create"
32889
33157
  },
33158
+ "localNetwork.downloadCa": {
33159
+ capName: "local-network",
33160
+ capScope: "system",
33161
+ addonId: null,
33162
+ access: "view"
33163
+ },
32890
33164
  "localNetwork.getAllowedAddresses": {
32891
33165
  capName: "local-network",
32892
33166
  capScope: "system",
@@ -32911,18 +33185,42 @@ Object.freeze({
32911
33185
  addonId: null,
32912
33186
  access: "view"
32913
33187
  },
33188
+ "localNetwork.getTlsStatus": {
33189
+ capName: "local-network",
33190
+ capScope: "system",
33191
+ addonId: null,
33192
+ access: "view"
33193
+ },
33194
+ "localNetwork.getViewerEndpoints": {
33195
+ capName: "local-network",
33196
+ capScope: "system",
33197
+ addonId: null,
33198
+ access: "view"
33199
+ },
32914
33200
  "localNetwork.list": {
32915
33201
  capName: "local-network",
32916
33202
  capScope: "system",
32917
33203
  addonId: null,
32918
33204
  access: "view"
32919
33205
  },
33206
+ "localNetwork.regenerateCertificate": {
33207
+ capName: "local-network",
33208
+ capScope: "system",
33209
+ addonId: null,
33210
+ access: "create"
33211
+ },
32920
33212
  "localNetwork.resetAllowlistToBestMatch": {
32921
33213
  capName: "local-network",
32922
33214
  capScope: "system",
32923
33215
  addonId: null,
32924
33216
  access: "delete"
32925
33217
  },
33218
+ "localNetwork.revertToGeneratedCertificate": {
33219
+ capName: "local-network",
33220
+ capScope: "system",
33221
+ addonId: null,
33222
+ access: "create"
33223
+ },
32926
33224
  "localNetwork.setAllowedAddresses": {
32927
33225
  capName: "local-network",
32928
33226
  capScope: "system",
@@ -32935,6 +33233,18 @@ Object.freeze({
32935
33233
  addonId: null,
32936
33234
  access: "create"
32937
33235
  },
33236
+ "localNetwork.setViewerEndpoints": {
33237
+ capName: "local-network",
33238
+ capScope: "system",
33239
+ addonId: null,
33240
+ access: "create"
33241
+ },
33242
+ "localNetwork.uploadCertificate": {
33243
+ capName: "local-network",
33244
+ capScope: "system",
33245
+ addonId: null,
33246
+ access: "create"
33247
+ },
32938
33248
  "lockControl.lock": {
32939
33249
  capName: "lock-control",
32940
33250
  capScope: "device",
@@ -33733,6 +34043,12 @@ Object.freeze({
33733
34043
  addonId: null,
33734
34044
  access: "view"
33735
34045
  },
34046
+ "pipelineAnalytics.getGroup": {
34047
+ capName: "pipeline-analytics",
34048
+ capScope: "device",
34049
+ addonId: null,
34050
+ access: "view"
34051
+ },
33736
34052
  "pipelineAnalytics.getKeyEvents": {
33737
34053
  capName: "pipeline-analytics",
33738
34054
  capScope: "device",
@@ -33817,6 +34133,12 @@ Object.freeze({
33817
34133
  addonId: null,
33818
34134
  access: "view"
33819
34135
  },
34136
+ "pipelineAnalytics.listGroups": {
34137
+ capName: "pipeline-analytics",
34138
+ capScope: "device",
34139
+ addonId: null,
34140
+ access: "view"
34141
+ },
33820
34142
  "pipelineAnalytics.listOpsLog": {
33821
34143
  capName: "pipeline-analytics",
33822
34144
  capScope: "device",
@@ -35815,6 +36137,12 @@ Object.freeze({
35815
36137
  addonId: null,
35816
36138
  access: "create"
35817
36139
  },
36140
+ "terminalSession.updateInstance": {
36141
+ capName: "terminal-session",
36142
+ capScope: "system",
36143
+ addonId: null,
36144
+ access: "create"
36145
+ },
35818
36146
  "terminalSession.writeInput": {
35819
36147
  capName: "terminal-session",
35820
36148
  capScope: "system",
@@ -36592,6 +36920,11 @@ Object.freeze({
36592
36920
  form: "single",
36593
36921
  optional: false
36594
36922
  }],
36923
+ "deviceManager.getBindingsBatch": [{
36924
+ name: "deviceIds",
36925
+ form: "array",
36926
+ optional: false
36927
+ }],
36595
36928
  "deviceManager.getChildren": [{
36596
36929
  name: "parentDeviceId",
36597
36930
  form: "single",
@@ -36637,6 +36970,11 @@ Object.freeze({
36637
36970
  form: "single",
36638
36971
  optional: false
36639
36972
  }],
36973
+ "deviceManager.getLinkedDevicesBatch": [{
36974
+ name: "deviceIds",
36975
+ form: "array",
36976
+ optional: false
36977
+ }],
36640
36978
  "deviceManager.getSettingsSchema": [{
36641
36979
  name: "deviceId",
36642
36980
  form: "single",
@@ -36657,6 +36995,11 @@ Object.freeze({
36657
36995
  form: "single",
36658
36996
  optional: false
36659
36997
  }],
36998
+ "deviceManager.listAll": [{
36999
+ name: "deviceIds",
37000
+ form: "array",
37001
+ optional: true
37002
+ }],
36660
37003
  "deviceManager.loadConfig": [{
36661
37004
  name: "deviceId",
36662
37005
  form: "single",
@@ -37230,6 +37573,11 @@ Object.freeze({
37230
37573
  form: "single",
37231
37574
  optional: false
37232
37575
  }],
37576
+ "pipelineAnalytics.getGroup": [{
37577
+ name: "deviceId",
37578
+ form: "single",
37579
+ optional: false
37580
+ }],
37233
37581
  "pipelineAnalytics.getKeyEvents": [{
37234
37582
  name: "deviceId",
37235
37583
  form: "single",
@@ -37285,6 +37633,11 @@ Object.freeze({
37285
37633
  form: "array",
37286
37634
  optional: false
37287
37635
  }],
37636
+ "pipelineAnalytics.listGroups": [{
37637
+ name: "deviceIds",
37638
+ form: "array",
37639
+ optional: false
37640
+ }],
37288
37641
  "pipelineAnalytics.listOpsLog": [{
37289
37642
  name: "deviceId",
37290
37643
  form: "single",
@@ -38302,6 +38655,35 @@ Object.freeze(Object.fromEntries([{
38302
38655
  }]
38303
38656
  }].map((s) => [s.stepId, s.defaultModelId])));
38304
38657
  string().min(1);
38658
+ var CLUSTER_STEP_SETTING_FIELDS = [{
38659
+ stepId: "face-embedding",
38660
+ key: "minLandmarkFaceSize",
38661
+ label: "Min face size for recognition (detection px)",
38662
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
38663
+ type: "slider",
38664
+ min: 0,
38665
+ max: 64,
38666
+ step: 2,
38667
+ default: 24
38668
+ }];
38669
+ function clusterStepSettingKey(stepId, fieldKey) {
38670
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
38671
+ }
38672
+ var ClusterSettingNumberSchema = number().finite();
38673
+ function readClusterStepSettings(config) {
38674
+ const out = {};
38675
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
38676
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
38677
+ const value = parsed.success ? parsed.data : field.default;
38678
+ const existing = out[field.stepId] ?? {};
38679
+ out[field.stepId] = {
38680
+ ...existing,
38681
+ [field.key]: value
38682
+ };
38683
+ }
38684
+ return out;
38685
+ }
38686
+ readClusterStepSettings({});
38305
38687
  object({
38306
38688
  /**
38307
38689
  * Fraction of the box's own size added on EACH side before cutting.