@camstack/addon-provider-reolink 1.2.48 → 1.2.50

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.js CHANGED
@@ -5828,6 +5828,13 @@ var BaseAddon = class {
5828
5828
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5829
5829
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5830
5830
  _registeredCapNames = [];
5831
+ /**
5832
+ * True only after `readAddonStore` actually answered. Constructor
5833
+ * defaults look like stored config when the store is down — a forked
5834
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5835
+ * mode, 2026-08-25) is not "the operator chose this".
5836
+ */
5837
+ settingsStoreReady = false;
5831
5838
  /** Default config values. Provided via constructor. */
5832
5839
  defaults;
5833
5840
  constructor(defaults) {
@@ -6228,7 +6235,9 @@ var BaseAddon = class {
6228
6235
  ];
6229
6236
  let lastErr;
6230
6237
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6231
- return await settings.readAddonStore() ?? {};
6238
+ const stored = await settings.readAddonStore() ?? {};
6239
+ this.settingsStoreReady = true;
6240
+ return stored;
6232
6241
  } catch (err) {
6233
6242
  lastErr = err;
6234
6243
  const msg = err instanceof Error ? err.message : String(err);
@@ -6236,6 +6245,7 @@ var BaseAddon = class {
6236
6245
  if (attempt === delaysMs.length) break;
6237
6246
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6238
6247
  }
6248
+ this.settingsStoreReady = false;
6239
6249
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6240
6250
  return {};
6241
6251
  }
@@ -8234,6 +8244,15 @@ var LabelDefinitionSchema = object({
8234
8244
  description: string().optional(),
8235
8245
  icon: string().optional()
8236
8246
  });
8247
+ var ClassMapDefinitionSchema = object({
8248
+ mapping: record(string(), _enum([
8249
+ "person",
8250
+ "vehicle",
8251
+ "animal",
8252
+ "package"
8253
+ ])),
8254
+ preserveOriginal: boolean()
8255
+ });
8237
8256
  var MODEL_FORMATS = [
8238
8257
  "onnx",
8239
8258
  "coreml",
@@ -8317,6 +8336,12 @@ var ModelVariantGroupSchema = object({
8317
8336
  */
8318
8337
  resolution: number().int().positive().optional()
8319
8338
  });
8339
+ var ModelProviderIdSchema = _enum([
8340
+ "camstack",
8341
+ "frigate",
8342
+ "scrypted",
8343
+ "custom"
8344
+ ]);
8320
8345
  var ModelCatalogEntrySchema = object({
8321
8346
  id: string(),
8322
8347
  name: string(),
@@ -8412,7 +8437,19 @@ var ModelCatalogEntrySchema = object({
8412
8437
  * `id` stays the source of truth for resolution/download/persistence; grouping
8413
8438
  * is a presentation overlay resolved back to an `id`.
8414
8439
  */
8415
- group: ModelVariantGroupSchema.optional()
8440
+ group: ModelVariantGroupSchema.optional(),
8441
+ /**
8442
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8443
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8444
+ * persisted before this field existed (`inferModelProvider` fills those).
8445
+ */
8446
+ provider: ModelProviderIdSchema.optional(),
8447
+ /**
8448
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8449
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8450
+ * labels already ARE the CamStack macros (Scrypted identity map).
8451
+ */
8452
+ classMap: ClassMapDefinitionSchema.optional()
8416
8453
  });
8417
8454
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8418
8455
  format: literal("openvino"),
@@ -8441,7 +8478,8 @@ var ModelConvertMetadataSchema = object({
8441
8478
  "ocr",
8442
8479
  "segmentation"
8443
8480
  ]),
8444
- faceAlignment: boolean().optional()
8481
+ faceAlignment: boolean().optional(),
8482
+ classMap: ClassMapDefinitionSchema.optional()
8445
8483
  });
8446
8484
  var ConvertResultSchema = object({
8447
8485
  entry: ModelCatalogEntrySchema,
@@ -12210,6 +12248,27 @@ var LinkedDeviceSchema = object({
12210
12248
  features: array(string()),
12211
12249
  producesTrackedEvents: boolean().optional()
12212
12250
  });
12251
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12252
+ * The batch answer needs the tag; the single-device answer already has it
12253
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12254
+ var LinkedDevicesForDeviceSchema = object({
12255
+ deviceId: number(),
12256
+ mode: LinkedDevicesModeSchema,
12257
+ devices: array(LinkedDeviceSchema)
12258
+ });
12259
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12260
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12261
+ * object literal is exactly how the three drift apart. */
12262
+ var DeviceBindingsForDeviceSchema = object({
12263
+ deviceId: number(),
12264
+ entries: array(object({
12265
+ capName: string(),
12266
+ kind: _enum(["native", "wrapped"]),
12267
+ providerAddonId: string(),
12268
+ providerNodeId: string(),
12269
+ nativeAddonId: string()
12270
+ }))
12271
+ });
12213
12272
  var SavedDeviceRowSchema = object({
12214
12273
  /** Numeric id reserved at allocateDeviceId time. */
12215
12274
  id: number(),
@@ -12435,11 +12494,25 @@ method(object({
12435
12494
  projection: _enum(["full", "slim"]).optional(),
12436
12495
  /** Return only camera devices. Filtering server-side instead of
12437
12496
  * shipping 293 rows to find 12. */
12438
- isCamera: boolean().optional()
12497
+ isCamera: boolean().optional(),
12498
+ /**
12499
+ * Return only these device ids. For the caller that already KNOWS the
12500
+ * handful it wants and needs a field the id-bearing answer does not
12501
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12502
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12503
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12504
+ * refetches on the reconcile interval, on a phone.
12505
+ *
12506
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12507
+ * keys rather than rejecting them (verified against the live hub
12508
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12509
+ * it answers today and the caller filters as it already does.
12510
+ */
12511
+ deviceIds: array(number()).optional()
12439
12512
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12440
12513
  mode: LinkedDevicesModeSchema,
12441
12514
  devices: array(LinkedDeviceSchema)
12442
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12515
+ })), 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({
12443
12516
  deviceId: number(),
12444
12517
  values: record(string(), unknown())
12445
12518
  }), object({ success: literal(true) }), {
@@ -12466,25 +12539,7 @@ method(object({
12466
12539
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12467
12540
  kind: "mutation",
12468
12541
  auth: "admin"
12469
- }), method(object({ deviceId: number() }), object({
12470
- deviceId: number(),
12471
- entries: array(object({
12472
- capName: string(),
12473
- kind: _enum(["native", "wrapped"]),
12474
- providerAddonId: string(),
12475
- providerNodeId: string(),
12476
- nativeAddonId: string()
12477
- }))
12478
- })), method(object({}), array(object({
12479
- deviceId: number(),
12480
- entries: array(object({
12481
- capName: string(),
12482
- kind: _enum(["native", "wrapped"]),
12483
- providerAddonId: string(),
12484
- providerNodeId: string(),
12485
- nativeAddonId: string()
12486
- }))
12487
- }))), method(object({
12542
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12488
12543
  deviceId: number(),
12489
12544
  capName: string(),
12490
12545
  wrapperAddonId: string(),
@@ -14894,12 +14949,15 @@ var NcOccupancyConditionSchema = object({
14894
14949
  * there is no second switch that can disagree with the first and every rule
14895
14950
  * authored before the decision migrates for free (`audioModeOf`):
14896
14951
  *
14897
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14898
- * classifier labels with one of them. No window, no percentage:
14899
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14900
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14901
- * the analyzer's (`classificationMinScore`, per device) a label only
14902
- * reaches this condition if the classifier was already confident enough.
14952
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14953
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14954
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14955
+ * frames is the wrong question for a classifier that labels 1–3 frames
14956
+ * per episode. The count window is the brake that drops a single-frame
14957
+ * false positive; the rule's own `throttle` cooldown is the other. The
14958
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14959
+ * per device) — a label only reaches this condition if the classifier was
14960
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14903
14961
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14904
14962
  * the condition: at least `hitPercent`% of the samples over
14905
14963
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14926,14 +14984,22 @@ var NcOccupancyConditionSchema = object({
14926
14984
  * an operator who typed `dog` mean the same thing.
14927
14985
  */
14928
14986
  var NcAudioConditionSchema = object({
14929
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14987
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14930
14988
  labels: array(string().min(1)).min(1).optional(),
14931
14989
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14932
14990
  dbThreshold: number().min(-96).max(0).optional(),
14933
14991
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14934
14992
  hitPercent: number().int().min(1).max(100).default(60),
14935
14993
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14936
- samplingSeconds: number().int().min(1).max(300).default(10)
14994
+ samplingSeconds: number().int().min(1).max(300).default(10),
14995
+ /**
14996
+ * LABEL MODE: how many labelled frames must land inside
14997
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14998
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14999
+ */
15000
+ confirmHits: number().int().min(1).max(20).optional(),
15001
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
15002
+ confirmWindowSec: number().int().min(1).max(60).optional()
14937
15003
  });
14938
15004
  /**
14939
15005
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -17307,6 +17373,46 @@ var RecentTracksPageSchema = object({
17307
17373
  /** Cursor for the next page, or null when this page is the last. */
17308
17374
  nextCursor: string().nullable()
17309
17375
  });
17376
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17377
+ var LIST_GROUPS_MAX_LIMIT = 100;
17378
+ var AnalyticsGroupRecordSchema = object({
17379
+ id: string(),
17380
+ deviceId: number().int(),
17381
+ openedAt: number().int(),
17382
+ closedAt: number().int(),
17383
+ timestamp: number().int(),
17384
+ memberCount: number().int(),
17385
+ memberTrackIds: array(string()).readonly(),
17386
+ className: string(),
17387
+ classes: array(string()).readonly(),
17388
+ /** Relative event-media path, or null when the group has no picture yet. */
17389
+ mediaUrl: string().nullable(),
17390
+ singleton: boolean()
17391
+ });
17392
+ var AnalyticsGroupMemberSchema = object({
17393
+ trackId: string(),
17394
+ deviceId: number().int(),
17395
+ className: string(),
17396
+ firstSeen: number().int(),
17397
+ lastSeen: number().int(),
17398
+ mediaUrl: string().nullable()
17399
+ });
17400
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17401
+ var ListGroupsQueryInput = object({
17402
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17403
+ deviceIds: array(number()),
17404
+ /** Window lower bound on `closedAt` (inclusive). */
17405
+ since: number().optional(),
17406
+ /** Window upper bound on `openedAt` (inclusive). */
17407
+ until: number().optional(),
17408
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17409
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17410
+ cursor: string().optional()
17411
+ });
17412
+ var ListGroupsPageSchema = object({
17413
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17414
+ nextCursor: string().nullable()
17415
+ });
17310
17416
  var KeyEventQueryInput = object({
17311
17417
  deviceId: number(),
17312
17418
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17382,7 +17488,9 @@ var TrackCascadeCountsSchema = object({
17382
17488
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17383
17489
  plates: number().int(),
17384
17490
  /** Per-track CLIP search vectors removed (best-effort). */
17385
- embeddings: number().int()
17491
+ embeddings: number().int(),
17492
+ /** Group membership + group rows removed with their last member (best-effort). */
17493
+ groups: number().int()
17386
17494
  });
17387
17495
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17388
17496
  var DiskReconcileCountsSchema = object({
@@ -17528,7 +17636,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17528
17636
  * stationary registry). Default false: the timeline lists passages,
17529
17637
  * not parking records (operator decision, 2026-08-15). */
17530
17638
  includeStationary: boolean().optional()
17531
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17639
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17640
+ deviceId: number(),
17641
+ groupId: string().min(1)
17642
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17532
17643
  kind: "mutation",
17533
17644
  auth: "admin"
17534
17645
  }), 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({
@@ -17746,6 +17857,33 @@ var NativeCropRefSchema = object({
17746
17857
  h: number()
17747
17858
  })
17748
17859
  });
17860
+ object({
17861
+ crop: object({
17862
+ left: number(),
17863
+ top: number(),
17864
+ width: number().positive(),
17865
+ height: number().positive()
17866
+ }).optional(),
17867
+ content: object({
17868
+ width: number().int().positive(),
17869
+ height: number().int().positive()
17870
+ }),
17871
+ fit: _enum(["stretch", "contain"]),
17872
+ format: _enum([
17873
+ "rgb",
17874
+ "gray",
17875
+ "jpeg"
17876
+ ])
17877
+ });
17878
+ var FrameRefSchema = object({
17879
+ registryId: string().min(1),
17880
+ id: string().min(1),
17881
+ width: number().int().positive(),
17882
+ height: number().int().positive(),
17883
+ format: _enum(["rgb", "gray"]),
17884
+ timestamp: number(),
17885
+ capturedAt: number().optional()
17886
+ });
17749
17887
  var ModelFormatSchema$1 = _enum([
17750
17888
  "onnx",
17751
17889
  "coreml",
@@ -17811,7 +17949,8 @@ var PipelineModelOptionSchema = object({
17811
17949
  sizeMB: number()
17812
17950
  })),
17813
17951
  group: ModelVariantGroupSchema.optional(),
17814
- legacy: boolean().optional()
17952
+ legacy: boolean().optional(),
17953
+ provider: ModelProviderIdSchema.optional()
17815
17954
  });
17816
17955
  var ConfigFieldBridge = custom$2();
17817
17956
  var PipelineAddonSchemaSchema = object({
@@ -17990,6 +18129,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17990
18129
  steps: array(PipelineStepInputSchema).min(1),
17991
18130
  frame: FrameInputSchema.optional(),
17992
18131
  /**
18132
+ * Process-local lazy frame. Valid only when caller and provider resolve
18133
+ * in the same execution-group process; split/cross-node callers use
18134
+ * `frame`/`image` inline compatibility instead.
18135
+ */
18136
+ frameRef: FrameRefSchema.optional(),
18137
+ /**
17993
18138
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17994
18139
  * the decoded pixels live in. One more member of the one-of
17995
18140
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18285,7 +18430,10 @@ var NativeCropResultSchema = object({
18285
18430
  * Which source served this crop, so a quality-sensitive consumer (the native
18286
18431
  * `keyFrame`) can reject a degraded fallback:
18287
18432
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18288
- * quality path).
18433
+ * quality path). A subject-tile serve is also native-resolution and stays
18434
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18435
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18436
+ * internal crop result (`nativeHits` vs `tileHits`).
18289
18437
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18290
18438
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18291
18439
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18776,12 +18924,41 @@ var RunnerLocalLoadSchema = object({
18776
18924
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18777
18925
  * working unchanged when they switch to reading from the runner cap.
18778
18926
  */
18927
+ var FrameLazyCountersSchema = object({
18928
+ framesDecoded: number(),
18929
+ framesAdmitted: number(),
18930
+ framesDroppedPixelFree: number(),
18931
+ viewsMaterialized: number(),
18932
+ viewsSkipped: number(),
18933
+ workerToRunnerBytes: number(),
18934
+ runnerToPoolRawBytes: number(),
18935
+ runnerToPoolJpegBytes: number(),
18936
+ onDemandFullFrameRequests: number(),
18937
+ onDemandCropRequests: number(),
18938
+ nativeHits: number(),
18939
+ nativeMisses: number(),
18940
+ tileHits: number(),
18941
+ tileMisses: number(),
18942
+ fallbackHits: number(),
18943
+ fallbackMisses: number(),
18944
+ retainedWritesAvoided: number(),
18945
+ residentRefs: number(),
18946
+ residentBytes: number(),
18947
+ releases: number(),
18948
+ evictions: number(),
18949
+ staleMisses: number()
18950
+ });
18951
+ var FrameLazyMetricsSchema = object({
18952
+ node: FrameLazyCountersSchema,
18953
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18954
+ });
18779
18955
  var RunnerLocalMetricsSchema = object({
18780
18956
  nodeId: string(),
18781
18957
  activeCameras: number(),
18782
18958
  throttledCameras: number(),
18783
18959
  avgInferenceTimeMs: number(),
18784
- queueDepth: number()
18960
+ queueDepth: number(),
18961
+ frameLazy: FrameLazyMetricsSchema.optional()
18785
18962
  });
18786
18963
  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({
18787
18964
  handle: FrameHandleSchema,
@@ -20185,6 +20362,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20185
20362
  location: StorageLocationSchema,
20186
20363
  relativePath: string()
20187
20364
  }), _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" });
20365
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20366
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20367
+ var ProfileSettingsBagSchema = record(string(), unknown());
20188
20368
  /**
20189
20369
  * A live terminal session hosted by the provider addon. Output and input do
20190
20370
  * NOT flow through the capability — they use the addon data plane
@@ -20214,7 +20394,14 @@ var TerminalSessionInfoSchema = object({
20214
20394
  var TerminalProfileInfoSchema = object({
20215
20395
  profileId: string(),
20216
20396
  label: string(),
20217
- description: string().optional()
20397
+ description: string().optional(),
20398
+ /** Spawn defaults the instance form copies on create. */
20399
+ executable: string().optional(),
20400
+ args: array(string()).readonly().optional(),
20401
+ cwd: string().optional(),
20402
+ environment: array(string()).readonly().optional(),
20403
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20404
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20218
20405
  });
20219
20406
  /**
20220
20407
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20227,7 +20414,12 @@ var TerminalInstanceInfoSchema = object({
20227
20414
  profileId: string(),
20228
20415
  profileLabel: string(),
20229
20416
  name: string(),
20230
- enabled: boolean()
20417
+ enabled: boolean(),
20418
+ executable: string(),
20419
+ args: array(string()).readonly(),
20420
+ cwd: string(),
20421
+ environment: array(string()).readonly(),
20422
+ profileSettings: ProfileSettingsBagSchema
20231
20423
  });
20232
20424
  var TerminalLegacyCameraSchema = object({
20233
20425
  stableId: string(),
@@ -20257,7 +20449,23 @@ var TerminalOutputBatchSchema = object({
20257
20449
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20258
20450
  targetNodeId: string().min(1),
20259
20451
  profileId: string().min(1),
20260
- name: string().trim().min(1).max(160).optional()
20452
+ name: string().trim().min(1).max(160).optional(),
20453
+ executable: string().max(1024).optional(),
20454
+ args: array(string().max(2048)).max(64).optional(),
20455
+ cwd: string().max(1024).optional(),
20456
+ environment: array(string().max(4096)).max(64).optional(),
20457
+ profileSettings: ProfileSettingsBagSchema.optional()
20458
+ }), TerminalInstanceInfoSchema, {
20459
+ kind: "mutation",
20460
+ auth: "admin"
20461
+ }), method(object({
20462
+ instanceId: string().min(1),
20463
+ name: string().trim().min(1).max(160).optional(),
20464
+ executable: string().max(1024).optional(),
20465
+ args: array(string().max(2048)).max(64).optional(),
20466
+ cwd: string().max(1024).optional(),
20467
+ environment: array(string().max(4096)).max(64).optional(),
20468
+ profileSettings: ProfileSettingsBagSchema.optional()
20261
20469
  }), TerminalInstanceInfoSchema, {
20262
20470
  kind: "mutation",
20263
20471
  auth: "admin"
@@ -20279,7 +20487,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20279
20487
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20280
20488
  profileId: string(),
20281
20489
  cols: number().int().positive(),
20282
- rows: number().int().positive()
20490
+ rows: number().int().positive(),
20491
+ executable: string().max(1024).optional(),
20492
+ args: array(string().max(2048)).max(64).optional(),
20493
+ cwd: string().max(1024).optional(),
20494
+ environment: array(string().max(4096)).max(64).optional()
20283
20495
  }), TerminalSessionInfoSchema, {
20284
20496
  kind: "mutation",
20285
20497
  auth: "admin"
@@ -24154,10 +24366,10 @@ var lawnMowerControlCapability = {
24154
24366
  *
24155
24367
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24156
24368
  * to receive an ordered list of candidate base URLs it should race
24157
- * on connect — LAN IPv4 first (lowest latency when on same network),
24158
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24159
- * race them with short timeouts and stick with the winner for the
24160
- * session.
24369
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24370
+ * when on the same network), then public hostname (if a tunnel is
24371
+ * up). The SDK can race them with short timeouts and stick with the
24372
+ * winner for the session.
24161
24373
  *
24162
24374
  * Why hub-only: agents are not directly addressable by the operator's
24163
24375
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24312,6 +24524,17 @@ var NotificationEndpointSchema = object({
24312
24524
  /** What the ranking currently resolves to (null when nothing is reachable). */
24313
24525
  resolved: string().nullable()
24314
24526
  });
24527
+ /**
24528
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24529
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24530
+ * currently expands to, so the UI can show the effective set either way.
24531
+ */
24532
+ var ViewerEndpointsSchema = object({
24533
+ /** The operator's explicit race set, or empty for AUTO. */
24534
+ baseUrls: array(string()).readonly(),
24535
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24536
+ resolved: array(string()).readonly()
24537
+ });
24315
24538
  var AllowedAddressesSchema = object({
24316
24539
  /**
24317
24540
  * Allowlist of interface addresses operators have explicitly opted
@@ -24320,6 +24543,20 @@ var AllowedAddressesSchema = object({
24320
24543
  * Network Addresses admin page and persisted by the addon.
24321
24544
  */
24322
24545
  addresses: array(string()).readonly() });
24546
+ var TlsStatusSchema = object({
24547
+ mode: _enum([
24548
+ "generated",
24549
+ "uploaded",
24550
+ "disabled"
24551
+ ]),
24552
+ leafFingerprintSha256: string().nullable(),
24553
+ caFingerprintSha256: string().nullable(),
24554
+ validTo: string().nullable(),
24555
+ sans: array(string()),
24556
+ caCertPem: string().nullable(),
24557
+ reissueError: string().nullable(),
24558
+ restartRequired: boolean()
24559
+ });
24323
24560
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24324
24561
  /**
24325
24562
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24329,17 +24566,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24329
24566
  */
24330
24567
  port: number().int().min(1).max(65535).optional(),
24331
24568
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24332
- * candidate. Default `true`. */
24569
+ * candidate. Default `false` — loopback is not a client route. */
24333
24570
  includeLoopback: boolean().optional(),
24334
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24335
- * Default `false`. */
24571
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24572
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24573
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24336
24574
  ipv4Only: boolean().optional(),
24337
24575
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24338
24576
  * Pass `'https'` when the caller is itself loaded over HTTPS
24339
24577
  * to avoid mixed-content blocks in the browser. The public
24340
24578
  * tunnel always emits `https://` regardless. */
24341
24579
  scheme: _enum(["http", "https"]).optional()
24342
- }), 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" });
24580
+ }), 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, {
24581
+ kind: "mutation",
24582
+ auth: "admin"
24583
+ }), method(object({
24584
+ certPem: string().min(1),
24585
+ keyPem: string().min(1),
24586
+ caPem: string().optional()
24587
+ }), TlsStatusSchema, {
24588
+ kind: "mutation",
24589
+ auth: "admin"
24590
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24591
+ kind: "mutation",
24592
+ auth: "admin"
24593
+ });
24343
24594
  var LockControlStatusSchema = object({
24344
24595
  /** Lifecycle state of the lock. `jammed` means the motor reported
24345
24596
  * failure to reach the target — operator intervention required. */
@@ -25900,7 +26151,12 @@ var PlateInfoSchema = object({
25900
26151
  plateBbox: BoundingBoxSchema.optional(),
25901
26152
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25902
26153
  keyFrameMediaKey: string().optional(),
25903
- base64: string().optional()
26154
+ base64: string().optional(),
26155
+ /**
26156
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26157
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26158
+ */
26159
+ cropUrl: string().optional()
25904
26160
  });
25905
26161
  var MediaFileLiteSchema = object({
25906
26162
  key: string(),
@@ -31876,6 +32132,12 @@ Object.freeze({
31876
32132
  addonId: null,
31877
32133
  access: "view"
31878
32134
  },
32135
+ "deviceManager.getBindingsBatch": {
32136
+ capName: "device-manager",
32137
+ capScope: "system",
32138
+ addonId: null,
32139
+ access: "view"
32140
+ },
31879
32141
  "deviceManager.getChildren": {
31880
32142
  capName: "device-manager",
31881
32143
  capScope: "system",
@@ -31936,6 +32198,12 @@ Object.freeze({
31936
32198
  addonId: null,
31937
32199
  access: "view"
31938
32200
  },
32201
+ "deviceManager.getLinkedDevicesBatch": {
32202
+ capName: "device-manager",
32203
+ capScope: "system",
32204
+ addonId: null,
32205
+ access: "view"
32206
+ },
31939
32207
  "deviceManager.getRoleDisplayDefaults": {
31940
32208
  capName: "device-manager",
31941
32209
  capScope: "system",
@@ -32818,6 +33086,12 @@ Object.freeze({
32818
33086
  addonId: null,
32819
33087
  access: "create"
32820
33088
  },
33089
+ "localNetwork.downloadCa": {
33090
+ capName: "local-network",
33091
+ capScope: "system",
33092
+ addonId: null,
33093
+ access: "view"
33094
+ },
32821
33095
  "localNetwork.getAllowedAddresses": {
32822
33096
  capName: "local-network",
32823
33097
  capScope: "system",
@@ -32842,18 +33116,42 @@ Object.freeze({
32842
33116
  addonId: null,
32843
33117
  access: "view"
32844
33118
  },
33119
+ "localNetwork.getTlsStatus": {
33120
+ capName: "local-network",
33121
+ capScope: "system",
33122
+ addonId: null,
33123
+ access: "view"
33124
+ },
33125
+ "localNetwork.getViewerEndpoints": {
33126
+ capName: "local-network",
33127
+ capScope: "system",
33128
+ addonId: null,
33129
+ access: "view"
33130
+ },
32845
33131
  "localNetwork.list": {
32846
33132
  capName: "local-network",
32847
33133
  capScope: "system",
32848
33134
  addonId: null,
32849
33135
  access: "view"
32850
33136
  },
33137
+ "localNetwork.regenerateCertificate": {
33138
+ capName: "local-network",
33139
+ capScope: "system",
33140
+ addonId: null,
33141
+ access: "create"
33142
+ },
32851
33143
  "localNetwork.resetAllowlistToBestMatch": {
32852
33144
  capName: "local-network",
32853
33145
  capScope: "system",
32854
33146
  addonId: null,
32855
33147
  access: "delete"
32856
33148
  },
33149
+ "localNetwork.revertToGeneratedCertificate": {
33150
+ capName: "local-network",
33151
+ capScope: "system",
33152
+ addonId: null,
33153
+ access: "create"
33154
+ },
32857
33155
  "localNetwork.setAllowedAddresses": {
32858
33156
  capName: "local-network",
32859
33157
  capScope: "system",
@@ -32866,6 +33164,18 @@ Object.freeze({
32866
33164
  addonId: null,
32867
33165
  access: "create"
32868
33166
  },
33167
+ "localNetwork.setViewerEndpoints": {
33168
+ capName: "local-network",
33169
+ capScope: "system",
33170
+ addonId: null,
33171
+ access: "create"
33172
+ },
33173
+ "localNetwork.uploadCertificate": {
33174
+ capName: "local-network",
33175
+ capScope: "system",
33176
+ addonId: null,
33177
+ access: "create"
33178
+ },
32869
33179
  "lockControl.lock": {
32870
33180
  capName: "lock-control",
32871
33181
  capScope: "device",
@@ -33664,6 +33974,12 @@ Object.freeze({
33664
33974
  addonId: null,
33665
33975
  access: "view"
33666
33976
  },
33977
+ "pipelineAnalytics.getGroup": {
33978
+ capName: "pipeline-analytics",
33979
+ capScope: "device",
33980
+ addonId: null,
33981
+ access: "view"
33982
+ },
33667
33983
  "pipelineAnalytics.getKeyEvents": {
33668
33984
  capName: "pipeline-analytics",
33669
33985
  capScope: "device",
@@ -33748,6 +34064,12 @@ Object.freeze({
33748
34064
  addonId: null,
33749
34065
  access: "view"
33750
34066
  },
34067
+ "pipelineAnalytics.listGroups": {
34068
+ capName: "pipeline-analytics",
34069
+ capScope: "device",
34070
+ addonId: null,
34071
+ access: "view"
34072
+ },
33751
34073
  "pipelineAnalytics.listOpsLog": {
33752
34074
  capName: "pipeline-analytics",
33753
34075
  capScope: "device",
@@ -35746,6 +36068,12 @@ Object.freeze({
35746
36068
  addonId: null,
35747
36069
  access: "create"
35748
36070
  },
36071
+ "terminalSession.updateInstance": {
36072
+ capName: "terminal-session",
36073
+ capScope: "system",
36074
+ addonId: null,
36075
+ access: "create"
36076
+ },
35749
36077
  "terminalSession.writeInput": {
35750
36078
  capName: "terminal-session",
35751
36079
  capScope: "system",
@@ -36523,6 +36851,11 @@ Object.freeze({
36523
36851
  form: "single",
36524
36852
  optional: false
36525
36853
  }],
36854
+ "deviceManager.getBindingsBatch": [{
36855
+ name: "deviceIds",
36856
+ form: "array",
36857
+ optional: false
36858
+ }],
36526
36859
  "deviceManager.getChildren": [{
36527
36860
  name: "parentDeviceId",
36528
36861
  form: "single",
@@ -36568,6 +36901,11 @@ Object.freeze({
36568
36901
  form: "single",
36569
36902
  optional: false
36570
36903
  }],
36904
+ "deviceManager.getLinkedDevicesBatch": [{
36905
+ name: "deviceIds",
36906
+ form: "array",
36907
+ optional: false
36908
+ }],
36571
36909
  "deviceManager.getSettingsSchema": [{
36572
36910
  name: "deviceId",
36573
36911
  form: "single",
@@ -36588,6 +36926,11 @@ Object.freeze({
36588
36926
  form: "single",
36589
36927
  optional: false
36590
36928
  }],
36929
+ "deviceManager.listAll": [{
36930
+ name: "deviceIds",
36931
+ form: "array",
36932
+ optional: true
36933
+ }],
36591
36934
  "deviceManager.loadConfig": [{
36592
36935
  name: "deviceId",
36593
36936
  form: "single",
@@ -37161,6 +37504,11 @@ Object.freeze({
37161
37504
  form: "single",
37162
37505
  optional: false
37163
37506
  }],
37507
+ "pipelineAnalytics.getGroup": [{
37508
+ name: "deviceId",
37509
+ form: "single",
37510
+ optional: false
37511
+ }],
37164
37512
  "pipelineAnalytics.getKeyEvents": [{
37165
37513
  name: "deviceId",
37166
37514
  form: "single",
@@ -37216,6 +37564,11 @@ Object.freeze({
37216
37564
  form: "array",
37217
37565
  optional: false
37218
37566
  }],
37567
+ "pipelineAnalytics.listGroups": [{
37568
+ name: "deviceIds",
37569
+ form: "array",
37570
+ optional: false
37571
+ }],
37219
37572
  "pipelineAnalytics.listOpsLog": [{
37220
37573
  name: "deviceId",
37221
37574
  form: "single",
@@ -38233,6 +38586,35 @@ Object.freeze(Object.fromEntries([{
38233
38586
  }]
38234
38587
  }].map((s) => [s.stepId, s.defaultModelId])));
38235
38588
  string().min(1);
38589
+ var CLUSTER_STEP_SETTING_FIELDS = [{
38590
+ stepId: "face-embedding",
38591
+ key: "minLandmarkFaceSize",
38592
+ label: "Min face size for recognition (detection px)",
38593
+ 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.",
38594
+ type: "slider",
38595
+ min: 0,
38596
+ max: 64,
38597
+ step: 2,
38598
+ default: 24
38599
+ }];
38600
+ function clusterStepSettingKey(stepId, fieldKey) {
38601
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
38602
+ }
38603
+ var ClusterSettingNumberSchema = number().finite();
38604
+ function readClusterStepSettings(config) {
38605
+ const out = {};
38606
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
38607
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
38608
+ const value = parsed.success ? parsed.data : field.default;
38609
+ const existing = out[field.stepId] ?? {};
38610
+ out[field.stepId] = {
38611
+ ...existing,
38612
+ [field.key]: value
38613
+ };
38614
+ }
38615
+ return out;
38616
+ }
38617
+ readClusterStepSettings({});
38236
38618
  object({
38237
38619
  /**
38238
38620
  * Fraction of the box's own size added on EACH side before cutting.