@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.mjs CHANGED
@@ -5823,6 +5823,13 @@ var BaseAddon = class {
5823
5823
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5824
5824
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5825
5825
  _registeredCapNames = [];
5826
+ /**
5827
+ * True only after `readAddonStore` actually answered. Constructor
5828
+ * defaults look like stored config when the store is down — a forked
5829
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5830
+ * mode, 2026-08-25) is not "the operator chose this".
5831
+ */
5832
+ settingsStoreReady = false;
5826
5833
  /** Default config values. Provided via constructor. */
5827
5834
  defaults;
5828
5835
  constructor(defaults) {
@@ -6223,7 +6230,9 @@ var BaseAddon = class {
6223
6230
  ];
6224
6231
  let lastErr;
6225
6232
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6226
- return await settings.readAddonStore() ?? {};
6233
+ const stored = await settings.readAddonStore() ?? {};
6234
+ this.settingsStoreReady = true;
6235
+ return stored;
6227
6236
  } catch (err) {
6228
6237
  lastErr = err;
6229
6238
  const msg = err instanceof Error ? err.message : String(err);
@@ -6231,6 +6240,7 @@ var BaseAddon = class {
6231
6240
  if (attempt === delaysMs.length) break;
6232
6241
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6233
6242
  }
6243
+ this.settingsStoreReady = false;
6234
6244
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6235
6245
  return {};
6236
6246
  }
@@ -8229,6 +8239,15 @@ var LabelDefinitionSchema = object({
8229
8239
  description: string().optional(),
8230
8240
  icon: string().optional()
8231
8241
  });
8242
+ var ClassMapDefinitionSchema = object({
8243
+ mapping: record(string(), _enum([
8244
+ "person",
8245
+ "vehicle",
8246
+ "animal",
8247
+ "package"
8248
+ ])),
8249
+ preserveOriginal: boolean()
8250
+ });
8232
8251
  var MODEL_FORMATS = [
8233
8252
  "onnx",
8234
8253
  "coreml",
@@ -8312,6 +8331,12 @@ var ModelVariantGroupSchema = object({
8312
8331
  */
8313
8332
  resolution: number().int().positive().optional()
8314
8333
  });
8334
+ var ModelProviderIdSchema = _enum([
8335
+ "camstack",
8336
+ "frigate",
8337
+ "scrypted",
8338
+ "custom"
8339
+ ]);
8315
8340
  var ModelCatalogEntrySchema = object({
8316
8341
  id: string(),
8317
8342
  name: string(),
@@ -8407,7 +8432,19 @@ var ModelCatalogEntrySchema = object({
8407
8432
  * `id` stays the source of truth for resolution/download/persistence; grouping
8408
8433
  * is a presentation overlay resolved back to an `id`.
8409
8434
  */
8410
- group: ModelVariantGroupSchema.optional()
8435
+ group: ModelVariantGroupSchema.optional(),
8436
+ /**
8437
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8438
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8439
+ * persisted before this field existed (`inferModelProvider` fills those).
8440
+ */
8441
+ provider: ModelProviderIdSchema.optional(),
8442
+ /**
8443
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8444
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8445
+ * labels already ARE the CamStack macros (Scrypted identity map).
8446
+ */
8447
+ classMap: ClassMapDefinitionSchema.optional()
8411
8448
  });
8412
8449
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8413
8450
  format: literal("openvino"),
@@ -8436,7 +8473,8 @@ var ModelConvertMetadataSchema = object({
8436
8473
  "ocr",
8437
8474
  "segmentation"
8438
8475
  ]),
8439
- faceAlignment: boolean().optional()
8476
+ faceAlignment: boolean().optional(),
8477
+ classMap: ClassMapDefinitionSchema.optional()
8440
8478
  });
8441
8479
  var ConvertResultSchema = object({
8442
8480
  entry: ModelCatalogEntrySchema,
@@ -12205,6 +12243,27 @@ var LinkedDeviceSchema = object({
12205
12243
  features: array(string()),
12206
12244
  producesTrackedEvents: boolean().optional()
12207
12245
  });
12246
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12247
+ * The batch answer needs the tag; the single-device answer already has it
12248
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12249
+ var LinkedDevicesForDeviceSchema = object({
12250
+ deviceId: number(),
12251
+ mode: LinkedDevicesModeSchema,
12252
+ devices: array(LinkedDeviceSchema)
12253
+ });
12254
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12255
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12256
+ * object literal is exactly how the three drift apart. */
12257
+ var DeviceBindingsForDeviceSchema = object({
12258
+ deviceId: number(),
12259
+ entries: array(object({
12260
+ capName: string(),
12261
+ kind: _enum(["native", "wrapped"]),
12262
+ providerAddonId: string(),
12263
+ providerNodeId: string(),
12264
+ nativeAddonId: string()
12265
+ }))
12266
+ });
12208
12267
  var SavedDeviceRowSchema = object({
12209
12268
  /** Numeric id reserved at allocateDeviceId time. */
12210
12269
  id: number(),
@@ -12430,11 +12489,25 @@ method(object({
12430
12489
  projection: _enum(["full", "slim"]).optional(),
12431
12490
  /** Return only camera devices. Filtering server-side instead of
12432
12491
  * shipping 293 rows to find 12. */
12433
- isCamera: boolean().optional()
12492
+ isCamera: boolean().optional(),
12493
+ /**
12494
+ * Return only these device ids. For the caller that already KNOWS the
12495
+ * handful it wants and needs a field the id-bearing answer does not
12496
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12497
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12498
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12499
+ * refetches on the reconcile interval, on a phone.
12500
+ *
12501
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12502
+ * keys rather than rejecting them (verified against the live hub
12503
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12504
+ * it answers today and the caller filters as it already does.
12505
+ */
12506
+ deviceIds: array(number()).optional()
12434
12507
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12435
12508
  mode: LinkedDevicesModeSchema,
12436
12509
  devices: array(LinkedDeviceSchema)
12437
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12510
+ })), 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({
12438
12511
  deviceId: number(),
12439
12512
  values: record(string(), unknown())
12440
12513
  }), object({ success: literal(true) }), {
@@ -12461,25 +12534,7 @@ method(object({
12461
12534
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12462
12535
  kind: "mutation",
12463
12536
  auth: "admin"
12464
- }), method(object({ deviceId: number() }), object({
12465
- deviceId: number(),
12466
- entries: array(object({
12467
- capName: string(),
12468
- kind: _enum(["native", "wrapped"]),
12469
- providerAddonId: string(),
12470
- providerNodeId: string(),
12471
- nativeAddonId: string()
12472
- }))
12473
- })), method(object({}), array(object({
12474
- deviceId: number(),
12475
- entries: array(object({
12476
- capName: string(),
12477
- kind: _enum(["native", "wrapped"]),
12478
- providerAddonId: string(),
12479
- providerNodeId: string(),
12480
- nativeAddonId: string()
12481
- }))
12482
- }))), method(object({
12537
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12483
12538
  deviceId: number(),
12484
12539
  capName: string(),
12485
12540
  wrapperAddonId: string(),
@@ -14889,12 +14944,15 @@ var NcOccupancyConditionSchema = object({
14889
14944
  * there is no second switch that can disagree with the first and every rule
14890
14945
  * authored before the decision migrates for free (`audioModeOf`):
14891
14946
  *
14892
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14893
- * classifier labels with one of them. No window, no percentage:
14894
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14895
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14896
- * the analyzer's (`classificationMinScore`, per device) a label only
14897
- * reaches this condition if the classifier was already confident enough.
14947
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14948
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14949
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14950
+ * frames is the wrong question for a classifier that labels 1–3 frames
14951
+ * per episode. The count window is the brake that drops a single-frame
14952
+ * false positive; the rule's own `throttle` cooldown is the other. The
14953
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14954
+ * per device) — a label only reaches this condition if the classifier was
14955
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14898
14956
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14899
14957
  * the condition: at least `hitPercent`% of the samples over
14900
14958
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14921,14 +14979,22 @@ var NcOccupancyConditionSchema = object({
14921
14979
  * an operator who typed `dog` mean the same thing.
14922
14980
  */
14923
14981
  var NcAudioConditionSchema = object({
14924
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14982
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14925
14983
  labels: array(string().min(1)).min(1).optional(),
14926
14984
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14927
14985
  dbThreshold: number().min(-96).max(0).optional(),
14928
14986
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14929
14987
  hitPercent: number().int().min(1).max(100).default(60),
14930
14988
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14931
- samplingSeconds: number().int().min(1).max(300).default(10)
14989
+ samplingSeconds: number().int().min(1).max(300).default(10),
14990
+ /**
14991
+ * LABEL MODE: how many labelled frames must land inside
14992
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14993
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14994
+ */
14995
+ confirmHits: number().int().min(1).max(20).optional(),
14996
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14997
+ confirmWindowSec: number().int().min(1).max(60).optional()
14932
14998
  });
14933
14999
  /**
14934
15000
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -17302,6 +17368,46 @@ var RecentTracksPageSchema = object({
17302
17368
  /** Cursor for the next page, or null when this page is the last. */
17303
17369
  nextCursor: string().nullable()
17304
17370
  });
17371
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17372
+ var LIST_GROUPS_MAX_LIMIT = 100;
17373
+ var AnalyticsGroupRecordSchema = object({
17374
+ id: string(),
17375
+ deviceId: number().int(),
17376
+ openedAt: number().int(),
17377
+ closedAt: number().int(),
17378
+ timestamp: number().int(),
17379
+ memberCount: number().int(),
17380
+ memberTrackIds: array(string()).readonly(),
17381
+ className: string(),
17382
+ classes: array(string()).readonly(),
17383
+ /** Relative event-media path, or null when the group has no picture yet. */
17384
+ mediaUrl: string().nullable(),
17385
+ singleton: boolean()
17386
+ });
17387
+ var AnalyticsGroupMemberSchema = object({
17388
+ trackId: string(),
17389
+ deviceId: number().int(),
17390
+ className: string(),
17391
+ firstSeen: number().int(),
17392
+ lastSeen: number().int(),
17393
+ mediaUrl: string().nullable()
17394
+ });
17395
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17396
+ var ListGroupsQueryInput = object({
17397
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17398
+ deviceIds: array(number()),
17399
+ /** Window lower bound on `closedAt` (inclusive). */
17400
+ since: number().optional(),
17401
+ /** Window upper bound on `openedAt` (inclusive). */
17402
+ until: number().optional(),
17403
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17404
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17405
+ cursor: string().optional()
17406
+ });
17407
+ var ListGroupsPageSchema = object({
17408
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17409
+ nextCursor: string().nullable()
17410
+ });
17305
17411
  var KeyEventQueryInput = object({
17306
17412
  deviceId: number(),
17307
17413
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17377,7 +17483,9 @@ var TrackCascadeCountsSchema = object({
17377
17483
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17378
17484
  plates: number().int(),
17379
17485
  /** Per-track CLIP search vectors removed (best-effort). */
17380
- embeddings: number().int()
17486
+ embeddings: number().int(),
17487
+ /** Group membership + group rows removed with their last member (best-effort). */
17488
+ groups: number().int()
17381
17489
  });
17382
17490
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17383
17491
  var DiskReconcileCountsSchema = object({
@@ -17523,7 +17631,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17523
17631
  * stationary registry). Default false: the timeline lists passages,
17524
17632
  * not parking records (operator decision, 2026-08-15). */
17525
17633
  includeStationary: boolean().optional()
17526
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17634
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17635
+ deviceId: number(),
17636
+ groupId: string().min(1)
17637
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17527
17638
  kind: "mutation",
17528
17639
  auth: "admin"
17529
17640
  }), 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({
@@ -17741,6 +17852,33 @@ var NativeCropRefSchema = object({
17741
17852
  h: number()
17742
17853
  })
17743
17854
  });
17855
+ object({
17856
+ crop: object({
17857
+ left: number(),
17858
+ top: number(),
17859
+ width: number().positive(),
17860
+ height: number().positive()
17861
+ }).optional(),
17862
+ content: object({
17863
+ width: number().int().positive(),
17864
+ height: number().int().positive()
17865
+ }),
17866
+ fit: _enum(["stretch", "contain"]),
17867
+ format: _enum([
17868
+ "rgb",
17869
+ "gray",
17870
+ "jpeg"
17871
+ ])
17872
+ });
17873
+ var FrameRefSchema = object({
17874
+ registryId: string().min(1),
17875
+ id: string().min(1),
17876
+ width: number().int().positive(),
17877
+ height: number().int().positive(),
17878
+ format: _enum(["rgb", "gray"]),
17879
+ timestamp: number(),
17880
+ capturedAt: number().optional()
17881
+ });
17744
17882
  var ModelFormatSchema$1 = _enum([
17745
17883
  "onnx",
17746
17884
  "coreml",
@@ -17806,7 +17944,8 @@ var PipelineModelOptionSchema = object({
17806
17944
  sizeMB: number()
17807
17945
  })),
17808
17946
  group: ModelVariantGroupSchema.optional(),
17809
- legacy: boolean().optional()
17947
+ legacy: boolean().optional(),
17948
+ provider: ModelProviderIdSchema.optional()
17810
17949
  });
17811
17950
  var ConfigFieldBridge = custom$2();
17812
17951
  var PipelineAddonSchemaSchema = object({
@@ -17985,6 +18124,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17985
18124
  steps: array(PipelineStepInputSchema).min(1),
17986
18125
  frame: FrameInputSchema.optional(),
17987
18126
  /**
18127
+ * Process-local lazy frame. Valid only when caller and provider resolve
18128
+ * in the same execution-group process; split/cross-node callers use
18129
+ * `frame`/`image` inline compatibility instead.
18130
+ */
18131
+ frameRef: FrameRefSchema.optional(),
18132
+ /**
17988
18133
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17989
18134
  * the decoded pixels live in. One more member of the one-of
17990
18135
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18280,7 +18425,10 @@ var NativeCropResultSchema = object({
18280
18425
  * Which source served this crop, so a quality-sensitive consumer (the native
18281
18426
  * `keyFrame`) can reject a degraded fallback:
18282
18427
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18283
- * quality path).
18428
+ * quality path). A subject-tile serve is also native-resolution and stays
18429
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18430
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18431
+ * internal crop result (`nativeHits` vs `tileHits`).
18284
18432
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18285
18433
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18286
18434
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18771,12 +18919,41 @@ var RunnerLocalLoadSchema = object({
18771
18919
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18772
18920
  * working unchanged when they switch to reading from the runner cap.
18773
18921
  */
18922
+ var FrameLazyCountersSchema = object({
18923
+ framesDecoded: number(),
18924
+ framesAdmitted: number(),
18925
+ framesDroppedPixelFree: number(),
18926
+ viewsMaterialized: number(),
18927
+ viewsSkipped: number(),
18928
+ workerToRunnerBytes: number(),
18929
+ runnerToPoolRawBytes: number(),
18930
+ runnerToPoolJpegBytes: number(),
18931
+ onDemandFullFrameRequests: number(),
18932
+ onDemandCropRequests: number(),
18933
+ nativeHits: number(),
18934
+ nativeMisses: number(),
18935
+ tileHits: number(),
18936
+ tileMisses: number(),
18937
+ fallbackHits: number(),
18938
+ fallbackMisses: number(),
18939
+ retainedWritesAvoided: number(),
18940
+ residentRefs: number(),
18941
+ residentBytes: number(),
18942
+ releases: number(),
18943
+ evictions: number(),
18944
+ staleMisses: number()
18945
+ });
18946
+ var FrameLazyMetricsSchema = object({
18947
+ node: FrameLazyCountersSchema,
18948
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18949
+ });
18774
18950
  var RunnerLocalMetricsSchema = object({
18775
18951
  nodeId: string(),
18776
18952
  activeCameras: number(),
18777
18953
  throttledCameras: number(),
18778
18954
  avgInferenceTimeMs: number(),
18779
- queueDepth: number()
18955
+ queueDepth: number(),
18956
+ frameLazy: FrameLazyMetricsSchema.optional()
18780
18957
  });
18781
18958
  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({
18782
18959
  handle: FrameHandleSchema,
@@ -20180,6 +20357,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20180
20357
  location: StorageLocationSchema,
20181
20358
  relativePath: string()
20182
20359
  }), _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" });
20360
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20361
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20362
+ var ProfileSettingsBagSchema = record(string(), unknown());
20183
20363
  /**
20184
20364
  * A live terminal session hosted by the provider addon. Output and input do
20185
20365
  * NOT flow through the capability — they use the addon data plane
@@ -20209,7 +20389,14 @@ var TerminalSessionInfoSchema = object({
20209
20389
  var TerminalProfileInfoSchema = object({
20210
20390
  profileId: string(),
20211
20391
  label: string(),
20212
- description: string().optional()
20392
+ description: string().optional(),
20393
+ /** Spawn defaults the instance form copies on create. */
20394
+ executable: string().optional(),
20395
+ args: array(string()).readonly().optional(),
20396
+ cwd: string().optional(),
20397
+ environment: array(string()).readonly().optional(),
20398
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20399
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20213
20400
  });
20214
20401
  /**
20215
20402
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20222,7 +20409,12 @@ var TerminalInstanceInfoSchema = object({
20222
20409
  profileId: string(),
20223
20410
  profileLabel: string(),
20224
20411
  name: string(),
20225
- enabled: boolean()
20412
+ enabled: boolean(),
20413
+ executable: string(),
20414
+ args: array(string()).readonly(),
20415
+ cwd: string(),
20416
+ environment: array(string()).readonly(),
20417
+ profileSettings: ProfileSettingsBagSchema
20226
20418
  });
20227
20419
  var TerminalLegacyCameraSchema = object({
20228
20420
  stableId: string(),
@@ -20252,7 +20444,23 @@ var TerminalOutputBatchSchema = object({
20252
20444
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20253
20445
  targetNodeId: string().min(1),
20254
20446
  profileId: string().min(1),
20255
- name: string().trim().min(1).max(160).optional()
20447
+ name: string().trim().min(1).max(160).optional(),
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(),
20452
+ profileSettings: ProfileSettingsBagSchema.optional()
20453
+ }), TerminalInstanceInfoSchema, {
20454
+ kind: "mutation",
20455
+ auth: "admin"
20456
+ }), method(object({
20457
+ instanceId: string().min(1),
20458
+ name: string().trim().min(1).max(160).optional(),
20459
+ executable: string().max(1024).optional(),
20460
+ args: array(string().max(2048)).max(64).optional(),
20461
+ cwd: string().max(1024).optional(),
20462
+ environment: array(string().max(4096)).max(64).optional(),
20463
+ profileSettings: ProfileSettingsBagSchema.optional()
20256
20464
  }), TerminalInstanceInfoSchema, {
20257
20465
  kind: "mutation",
20258
20466
  auth: "admin"
@@ -20274,7 +20482,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20274
20482
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20275
20483
  profileId: string(),
20276
20484
  cols: number().int().positive(),
20277
- rows: number().int().positive()
20485
+ rows: number().int().positive(),
20486
+ executable: string().max(1024).optional(),
20487
+ args: array(string().max(2048)).max(64).optional(),
20488
+ cwd: string().max(1024).optional(),
20489
+ environment: array(string().max(4096)).max(64).optional()
20278
20490
  }), TerminalSessionInfoSchema, {
20279
20491
  kind: "mutation",
20280
20492
  auth: "admin"
@@ -24149,10 +24361,10 @@ var lawnMowerControlCapability = {
24149
24361
  *
24150
24362
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24151
24363
  * to receive an ordered list of candidate base URLs it should race
24152
- * on connect — LAN IPv4 first (lowest latency when on same network),
24153
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24154
- * race them with short timeouts and stick with the winner for the
24155
- * session.
24364
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24365
+ * when on the same network), then public hostname (if a tunnel is
24366
+ * up). The SDK can race them with short timeouts and stick with the
24367
+ * winner for the session.
24156
24368
  *
24157
24369
  * Why hub-only: agents are not directly addressable by the operator's
24158
24370
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24307,6 +24519,17 @@ var NotificationEndpointSchema = object({
24307
24519
  /** What the ranking currently resolves to (null when nothing is reachable). */
24308
24520
  resolved: string().nullable()
24309
24521
  });
24522
+ /**
24523
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24524
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24525
+ * currently expands to, so the UI can show the effective set either way.
24526
+ */
24527
+ var ViewerEndpointsSchema = object({
24528
+ /** The operator's explicit race set, or empty for AUTO. */
24529
+ baseUrls: array(string()).readonly(),
24530
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24531
+ resolved: array(string()).readonly()
24532
+ });
24310
24533
  var AllowedAddressesSchema = object({
24311
24534
  /**
24312
24535
  * Allowlist of interface addresses operators have explicitly opted
@@ -24315,6 +24538,20 @@ var AllowedAddressesSchema = object({
24315
24538
  * Network Addresses admin page and persisted by the addon.
24316
24539
  */
24317
24540
  addresses: array(string()).readonly() });
24541
+ var TlsStatusSchema = object({
24542
+ mode: _enum([
24543
+ "generated",
24544
+ "uploaded",
24545
+ "disabled"
24546
+ ]),
24547
+ leafFingerprintSha256: string().nullable(),
24548
+ caFingerprintSha256: string().nullable(),
24549
+ validTo: string().nullable(),
24550
+ sans: array(string()),
24551
+ caCertPem: string().nullable(),
24552
+ reissueError: string().nullable(),
24553
+ restartRequired: boolean()
24554
+ });
24318
24555
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24319
24556
  /**
24320
24557
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24324,17 +24561,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24324
24561
  */
24325
24562
  port: number().int().min(1).max(65535).optional(),
24326
24563
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24327
- * candidate. Default `true`. */
24564
+ * candidate. Default `false` — loopback is not a client route. */
24328
24565
  includeLoopback: boolean().optional(),
24329
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24330
- * Default `false`. */
24566
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24567
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24568
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24331
24569
  ipv4Only: boolean().optional(),
24332
24570
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24333
24571
  * Pass `'https'` when the caller is itself loaded over HTTPS
24334
24572
  * to avoid mixed-content blocks in the browser. The public
24335
24573
  * tunnel always emits `https://` regardless. */
24336
24574
  scheme: _enum(["http", "https"]).optional()
24337
- }), 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" });
24575
+ }), 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, {
24576
+ kind: "mutation",
24577
+ auth: "admin"
24578
+ }), method(object({
24579
+ certPem: string().min(1),
24580
+ keyPem: string().min(1),
24581
+ caPem: string().optional()
24582
+ }), TlsStatusSchema, {
24583
+ kind: "mutation",
24584
+ auth: "admin"
24585
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24586
+ kind: "mutation",
24587
+ auth: "admin"
24588
+ });
24338
24589
  var LockControlStatusSchema = object({
24339
24590
  /** Lifecycle state of the lock. `jammed` means the motor reported
24340
24591
  * failure to reach the target — operator intervention required. */
@@ -25895,7 +26146,12 @@ var PlateInfoSchema = object({
25895
26146
  plateBbox: BoundingBoxSchema.optional(),
25896
26147
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25897
26148
  keyFrameMediaKey: string().optional(),
25898
- base64: string().optional()
26149
+ base64: string().optional(),
26150
+ /**
26151
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26152
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26153
+ */
26154
+ cropUrl: string().optional()
25899
26155
  });
25900
26156
  var MediaFileLiteSchema = object({
25901
26157
  key: string(),
@@ -31871,6 +32127,12 @@ Object.freeze({
31871
32127
  addonId: null,
31872
32128
  access: "view"
31873
32129
  },
32130
+ "deviceManager.getBindingsBatch": {
32131
+ capName: "device-manager",
32132
+ capScope: "system",
32133
+ addonId: null,
32134
+ access: "view"
32135
+ },
31874
32136
  "deviceManager.getChildren": {
31875
32137
  capName: "device-manager",
31876
32138
  capScope: "system",
@@ -31931,6 +32193,12 @@ Object.freeze({
31931
32193
  addonId: null,
31932
32194
  access: "view"
31933
32195
  },
32196
+ "deviceManager.getLinkedDevicesBatch": {
32197
+ capName: "device-manager",
32198
+ capScope: "system",
32199
+ addonId: null,
32200
+ access: "view"
32201
+ },
31934
32202
  "deviceManager.getRoleDisplayDefaults": {
31935
32203
  capName: "device-manager",
31936
32204
  capScope: "system",
@@ -32813,6 +33081,12 @@ Object.freeze({
32813
33081
  addonId: null,
32814
33082
  access: "create"
32815
33083
  },
33084
+ "localNetwork.downloadCa": {
33085
+ capName: "local-network",
33086
+ capScope: "system",
33087
+ addonId: null,
33088
+ access: "view"
33089
+ },
32816
33090
  "localNetwork.getAllowedAddresses": {
32817
33091
  capName: "local-network",
32818
33092
  capScope: "system",
@@ -32837,18 +33111,42 @@ Object.freeze({
32837
33111
  addonId: null,
32838
33112
  access: "view"
32839
33113
  },
33114
+ "localNetwork.getTlsStatus": {
33115
+ capName: "local-network",
33116
+ capScope: "system",
33117
+ addonId: null,
33118
+ access: "view"
33119
+ },
33120
+ "localNetwork.getViewerEndpoints": {
33121
+ capName: "local-network",
33122
+ capScope: "system",
33123
+ addonId: null,
33124
+ access: "view"
33125
+ },
32840
33126
  "localNetwork.list": {
32841
33127
  capName: "local-network",
32842
33128
  capScope: "system",
32843
33129
  addonId: null,
32844
33130
  access: "view"
32845
33131
  },
33132
+ "localNetwork.regenerateCertificate": {
33133
+ capName: "local-network",
33134
+ capScope: "system",
33135
+ addonId: null,
33136
+ access: "create"
33137
+ },
32846
33138
  "localNetwork.resetAllowlistToBestMatch": {
32847
33139
  capName: "local-network",
32848
33140
  capScope: "system",
32849
33141
  addonId: null,
32850
33142
  access: "delete"
32851
33143
  },
33144
+ "localNetwork.revertToGeneratedCertificate": {
33145
+ capName: "local-network",
33146
+ capScope: "system",
33147
+ addonId: null,
33148
+ access: "create"
33149
+ },
32852
33150
  "localNetwork.setAllowedAddresses": {
32853
33151
  capName: "local-network",
32854
33152
  capScope: "system",
@@ -32861,6 +33159,18 @@ Object.freeze({
32861
33159
  addonId: null,
32862
33160
  access: "create"
32863
33161
  },
33162
+ "localNetwork.setViewerEndpoints": {
33163
+ capName: "local-network",
33164
+ capScope: "system",
33165
+ addonId: null,
33166
+ access: "create"
33167
+ },
33168
+ "localNetwork.uploadCertificate": {
33169
+ capName: "local-network",
33170
+ capScope: "system",
33171
+ addonId: null,
33172
+ access: "create"
33173
+ },
32864
33174
  "lockControl.lock": {
32865
33175
  capName: "lock-control",
32866
33176
  capScope: "device",
@@ -33659,6 +33969,12 @@ Object.freeze({
33659
33969
  addonId: null,
33660
33970
  access: "view"
33661
33971
  },
33972
+ "pipelineAnalytics.getGroup": {
33973
+ capName: "pipeline-analytics",
33974
+ capScope: "device",
33975
+ addonId: null,
33976
+ access: "view"
33977
+ },
33662
33978
  "pipelineAnalytics.getKeyEvents": {
33663
33979
  capName: "pipeline-analytics",
33664
33980
  capScope: "device",
@@ -33743,6 +34059,12 @@ Object.freeze({
33743
34059
  addonId: null,
33744
34060
  access: "view"
33745
34061
  },
34062
+ "pipelineAnalytics.listGroups": {
34063
+ capName: "pipeline-analytics",
34064
+ capScope: "device",
34065
+ addonId: null,
34066
+ access: "view"
34067
+ },
33746
34068
  "pipelineAnalytics.listOpsLog": {
33747
34069
  capName: "pipeline-analytics",
33748
34070
  capScope: "device",
@@ -35741,6 +36063,12 @@ Object.freeze({
35741
36063
  addonId: null,
35742
36064
  access: "create"
35743
36065
  },
36066
+ "terminalSession.updateInstance": {
36067
+ capName: "terminal-session",
36068
+ capScope: "system",
36069
+ addonId: null,
36070
+ access: "create"
36071
+ },
35744
36072
  "terminalSession.writeInput": {
35745
36073
  capName: "terminal-session",
35746
36074
  capScope: "system",
@@ -36518,6 +36846,11 @@ Object.freeze({
36518
36846
  form: "single",
36519
36847
  optional: false
36520
36848
  }],
36849
+ "deviceManager.getBindingsBatch": [{
36850
+ name: "deviceIds",
36851
+ form: "array",
36852
+ optional: false
36853
+ }],
36521
36854
  "deviceManager.getChildren": [{
36522
36855
  name: "parentDeviceId",
36523
36856
  form: "single",
@@ -36563,6 +36896,11 @@ Object.freeze({
36563
36896
  form: "single",
36564
36897
  optional: false
36565
36898
  }],
36899
+ "deviceManager.getLinkedDevicesBatch": [{
36900
+ name: "deviceIds",
36901
+ form: "array",
36902
+ optional: false
36903
+ }],
36566
36904
  "deviceManager.getSettingsSchema": [{
36567
36905
  name: "deviceId",
36568
36906
  form: "single",
@@ -36583,6 +36921,11 @@ Object.freeze({
36583
36921
  form: "single",
36584
36922
  optional: false
36585
36923
  }],
36924
+ "deviceManager.listAll": [{
36925
+ name: "deviceIds",
36926
+ form: "array",
36927
+ optional: true
36928
+ }],
36586
36929
  "deviceManager.loadConfig": [{
36587
36930
  name: "deviceId",
36588
36931
  form: "single",
@@ -37156,6 +37499,11 @@ Object.freeze({
37156
37499
  form: "single",
37157
37500
  optional: false
37158
37501
  }],
37502
+ "pipelineAnalytics.getGroup": [{
37503
+ name: "deviceId",
37504
+ form: "single",
37505
+ optional: false
37506
+ }],
37159
37507
  "pipelineAnalytics.getKeyEvents": [{
37160
37508
  name: "deviceId",
37161
37509
  form: "single",
@@ -37211,6 +37559,11 @@ Object.freeze({
37211
37559
  form: "array",
37212
37560
  optional: false
37213
37561
  }],
37562
+ "pipelineAnalytics.listGroups": [{
37563
+ name: "deviceIds",
37564
+ form: "array",
37565
+ optional: false
37566
+ }],
37214
37567
  "pipelineAnalytics.listOpsLog": [{
37215
37568
  name: "deviceId",
37216
37569
  form: "single",
@@ -38228,6 +38581,35 @@ Object.freeze(Object.fromEntries([{
38228
38581
  }]
38229
38582
  }].map((s) => [s.stepId, s.defaultModelId])));
38230
38583
  string().min(1);
38584
+ var CLUSTER_STEP_SETTING_FIELDS = [{
38585
+ stepId: "face-embedding",
38586
+ key: "minLandmarkFaceSize",
38587
+ label: "Min face size for recognition (detection px)",
38588
+ 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.",
38589
+ type: "slider",
38590
+ min: 0,
38591
+ max: 64,
38592
+ step: 2,
38593
+ default: 24
38594
+ }];
38595
+ function clusterStepSettingKey(stepId, fieldKey) {
38596
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
38597
+ }
38598
+ var ClusterSettingNumberSchema = number().finite();
38599
+ function readClusterStepSettings(config) {
38600
+ const out = {};
38601
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
38602
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
38603
+ const value = parsed.success ? parsed.data : field.default;
38604
+ const existing = out[field.stepId] ?? {};
38605
+ out[field.stepId] = {
38606
+ ...existing,
38607
+ [field.key]: value
38608
+ };
38609
+ }
38610
+ return out;
38611
+ }
38612
+ readClusterStepSettings({});
38231
38613
  object({
38232
38614
  /**
38233
38615
  * Fraction of the box's own size added on EACH side before cutting.