@camstack/addon-provider-wyze 0.2.30 → 0.2.32

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
@@ -5812,6 +5812,13 @@ var BaseAddon = class {
5812
5812
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5813
5813
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5814
5814
  _registeredCapNames = [];
5815
+ /**
5816
+ * True only after `readAddonStore` actually answered. Constructor
5817
+ * defaults look like stored config when the store is down — a forked
5818
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5819
+ * mode, 2026-08-25) is not "the operator chose this".
5820
+ */
5821
+ settingsStoreReady = false;
5815
5822
  /** Default config values. Provided via constructor. */
5816
5823
  defaults;
5817
5824
  constructor(defaults) {
@@ -6212,7 +6219,9 @@ var BaseAddon = class {
6212
6219
  ];
6213
6220
  let lastErr;
6214
6221
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6215
- return await settings.readAddonStore() ?? {};
6222
+ const stored = await settings.readAddonStore() ?? {};
6223
+ this.settingsStoreReady = true;
6224
+ return stored;
6216
6225
  } catch (err) {
6217
6226
  lastErr = err;
6218
6227
  const msg = err instanceof Error ? err.message : String(err);
@@ -6220,6 +6229,7 @@ var BaseAddon = class {
6220
6229
  if (attempt === delaysMs.length) break;
6221
6230
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6222
6231
  }
6232
+ this.settingsStoreReady = false;
6223
6233
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6224
6234
  return {};
6225
6235
  }
@@ -8031,6 +8041,15 @@ var LabelDefinitionSchema = object({
8031
8041
  description: string().optional(),
8032
8042
  icon: string().optional()
8033
8043
  });
8044
+ var ClassMapDefinitionSchema = object({
8045
+ mapping: record(string(), _enum([
8046
+ "person",
8047
+ "vehicle",
8048
+ "animal",
8049
+ "package"
8050
+ ])),
8051
+ preserveOriginal: boolean()
8052
+ });
8034
8053
  var MODEL_FORMATS = [
8035
8054
  "onnx",
8036
8055
  "coreml",
@@ -8114,6 +8133,12 @@ var ModelVariantGroupSchema = object({
8114
8133
  */
8115
8134
  resolution: number().int().positive().optional()
8116
8135
  });
8136
+ var ModelProviderIdSchema = _enum([
8137
+ "camstack",
8138
+ "frigate",
8139
+ "scrypted",
8140
+ "custom"
8141
+ ]);
8117
8142
  var ModelCatalogEntrySchema = object({
8118
8143
  id: string(),
8119
8144
  name: string(),
@@ -8209,7 +8234,19 @@ var ModelCatalogEntrySchema = object({
8209
8234
  * `id` stays the source of truth for resolution/download/persistence; grouping
8210
8235
  * is a presentation overlay resolved back to an `id`.
8211
8236
  */
8212
- group: ModelVariantGroupSchema.optional()
8237
+ group: ModelVariantGroupSchema.optional(),
8238
+ /**
8239
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8240
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8241
+ * persisted before this field existed (`inferModelProvider` fills those).
8242
+ */
8243
+ provider: ModelProviderIdSchema.optional(),
8244
+ /**
8245
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8246
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8247
+ * labels already ARE the CamStack macros (Scrypted identity map).
8248
+ */
8249
+ classMap: ClassMapDefinitionSchema.optional()
8213
8250
  });
8214
8251
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8215
8252
  format: literal("openvino"),
@@ -8238,7 +8275,8 @@ var ModelConvertMetadataSchema = object({
8238
8275
  "ocr",
8239
8276
  "segmentation"
8240
8277
  ]),
8241
- faceAlignment: boolean().optional()
8278
+ faceAlignment: boolean().optional(),
8279
+ classMap: ClassMapDefinitionSchema.optional()
8242
8280
  });
8243
8281
  var ConvertResultSchema = object({
8244
8282
  entry: ModelCatalogEntrySchema,
@@ -12012,6 +12050,27 @@ var LinkedDeviceSchema = object({
12012
12050
  features: array(string()),
12013
12051
  producesTrackedEvents: boolean().optional()
12014
12052
  });
12053
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
12054
+ * The batch answer needs the tag; the single-device answer already has it
12055
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
12056
+ var LinkedDevicesForDeviceSchema = object({
12057
+ deviceId: number(),
12058
+ mode: LinkedDevicesModeSchema,
12059
+ devices: array(LinkedDeviceSchema)
12060
+ });
12061
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
12062
+ * `getAllBindings` all answer in. Declared once: three copies of the same
12063
+ * object literal is exactly how the three drift apart. */
12064
+ var DeviceBindingsForDeviceSchema = object({
12065
+ deviceId: number(),
12066
+ entries: array(object({
12067
+ capName: string(),
12068
+ kind: _enum(["native", "wrapped"]),
12069
+ providerAddonId: string(),
12070
+ providerNodeId: string(),
12071
+ nativeAddonId: string()
12072
+ }))
12073
+ });
12015
12074
  var SavedDeviceRowSchema = object({
12016
12075
  /** Numeric id reserved at allocateDeviceId time. */
12017
12076
  id: number(),
@@ -12237,11 +12296,25 @@ method(object({
12237
12296
  projection: _enum(["full", "slim"]).optional(),
12238
12297
  /** Return only camera devices. Filtering server-side instead of
12239
12298
  * shipping 293 rows to find 12. */
12240
- isCamera: boolean().optional()
12299
+ isCamera: boolean().optional(),
12300
+ /**
12301
+ * Return only these device ids. For the caller that already KNOWS the
12302
+ * handful it wants and needs a field the id-bearing answer does not
12303
+ * carry — the viewer's linked-devices panel joins `type` and `online`
12304
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
12305
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
12306
+ * refetches on the reconcile interval, on a phone.
12307
+ *
12308
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
12309
+ * keys rather than rejecting them (verified against the live hub
12310
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
12311
+ * it answers today and the caller filters as it already does.
12312
+ */
12313
+ deviceIds: array(number()).optional()
12241
12314
  }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
12242
12315
  mode: LinkedDevicesModeSchema,
12243
12316
  devices: array(LinkedDeviceSchema)
12244
- })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
12317
+ })), 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({
12245
12318
  deviceId: number(),
12246
12319
  values: record(string(), unknown())
12247
12320
  }), object({ success: literal(true) }), {
@@ -12268,25 +12341,7 @@ method(object({
12268
12341
  }), method(object({ deviceId: number() }), array(StreamProbeResultSchema), {
12269
12342
  kind: "mutation",
12270
12343
  auth: "admin"
12271
- }), method(object({ deviceId: number() }), object({
12272
- deviceId: number(),
12273
- entries: array(object({
12274
- capName: string(),
12275
- kind: _enum(["native", "wrapped"]),
12276
- providerAddonId: string(),
12277
- providerNodeId: string(),
12278
- nativeAddonId: string()
12279
- }))
12280
- })), method(object({}), array(object({
12281
- deviceId: number(),
12282
- entries: array(object({
12283
- capName: string(),
12284
- kind: _enum(["native", "wrapped"]),
12285
- providerAddonId: string(),
12286
- providerNodeId: string(),
12287
- nativeAddonId: string()
12288
- }))
12289
- }))), method(object({
12344
+ }), method(object({ deviceId: number() }), DeviceBindingsForDeviceSchema), method(object({ deviceIds: array(number()) }), array(DeviceBindingsForDeviceSchema)), method(object({}), array(DeviceBindingsForDeviceSchema)), method(object({
12290
12345
  deviceId: number(),
12291
12346
  capName: string(),
12292
12347
  wrapperAddonId: string(),
@@ -14696,12 +14751,15 @@ var NcOccupancyConditionSchema = object({
14696
14751
  * there is no second switch that can disagree with the first and every rule
14697
14752
  * authored before the decision migrates for free (`audioModeOf`):
14698
14753
  *
14699
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14700
- * classifier labels with one of them. No window, no percentage:
14701
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14702
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14703
- * the analyzer's (`classificationMinScore`, per device) a label only
14704
- * reaches this condition if the classifier was already confident enough.
14754
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14755
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14756
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14757
+ * frames is the wrong question for a classifier that labels 1–3 frames
14758
+ * per episode. The count window is the brake that drops a single-frame
14759
+ * false positive; the rule's own `throttle` cooldown is the other. The
14760
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14761
+ * per device) — a label only reaches this condition if the classifier was
14762
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14705
14763
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14706
14764
  * the condition: at least `hitPercent`% of the samples over
14707
14765
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14728,14 +14786,22 @@ var NcOccupancyConditionSchema = object({
14728
14786
  * an operator who typed `dog` mean the same thing.
14729
14787
  */
14730
14788
  var NcAudioConditionSchema = object({
14731
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14789
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14732
14790
  labels: array(string().min(1)).min(1).optional(),
14733
14791
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14734
14792
  dbThreshold: number().min(-96).max(0).optional(),
14735
14793
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14736
14794
  hitPercent: number().int().min(1).max(100).default(60),
14737
14795
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14738
- samplingSeconds: number().int().min(1).max(300).default(10)
14796
+ samplingSeconds: number().int().min(1).max(300).default(10),
14797
+ /**
14798
+ * LABEL MODE: how many labelled frames must land inside
14799
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14800
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14801
+ */
14802
+ confirmHits: number().int().min(1).max(20).optional(),
14803
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14804
+ confirmWindowSec: number().int().min(1).max(60).optional()
14739
14805
  });
14740
14806
  /**
14741
14807
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -17109,6 +17175,46 @@ var RecentTracksPageSchema = object({
17109
17175
  /** Cursor for the next page, or null when this page is the last. */
17110
17176
  nextCursor: string().nullable()
17111
17177
  });
17178
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
17179
+ var LIST_GROUPS_MAX_LIMIT = 100;
17180
+ var AnalyticsGroupRecordSchema = object({
17181
+ id: string(),
17182
+ deviceId: number().int(),
17183
+ openedAt: number().int(),
17184
+ closedAt: number().int(),
17185
+ timestamp: number().int(),
17186
+ memberCount: number().int(),
17187
+ memberTrackIds: array(string()).readonly(),
17188
+ className: string(),
17189
+ classes: array(string()).readonly(),
17190
+ /** Relative event-media path, or null when the group has no picture yet. */
17191
+ mediaUrl: string().nullable(),
17192
+ singleton: boolean()
17193
+ });
17194
+ var AnalyticsGroupMemberSchema = object({
17195
+ trackId: string(),
17196
+ deviceId: number().int(),
17197
+ className: string(),
17198
+ firstSeen: number().int(),
17199
+ lastSeen: number().int(),
17200
+ mediaUrl: string().nullable()
17201
+ });
17202
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
17203
+ var ListGroupsQueryInput = object({
17204
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
17205
+ deviceIds: array(number()),
17206
+ /** Window lower bound on `closedAt` (inclusive). */
17207
+ since: number().optional(),
17208
+ /** Window upper bound on `openedAt` (inclusive). */
17209
+ until: number().optional(),
17210
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
17211
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
17212
+ cursor: string().optional()
17213
+ });
17214
+ var ListGroupsPageSchema = object({
17215
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
17216
+ nextCursor: string().nullable()
17217
+ });
17112
17218
  var KeyEventQueryInput = object({
17113
17219
  deviceId: number(),
17114
17220
  /** Window lower bound (track firstSeen ≥ since). */
@@ -17184,7 +17290,9 @@ var TrackCascadeCountsSchema = object({
17184
17290
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
17185
17291
  plates: number().int(),
17186
17292
  /** Per-track CLIP search vectors removed (best-effort). */
17187
- embeddings: number().int()
17293
+ embeddings: number().int(),
17294
+ /** Group membership + group rows removed with their last member (best-effort). */
17295
+ groups: number().int()
17188
17296
  });
17189
17297
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17190
17298
  var DiskReconcileCountsSchema = object({
@@ -17330,7 +17438,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17330
17438
  * stationary registry). Default false: the timeline lists passages,
17331
17439
  * not parking records (operator decision, 2026-08-15). */
17332
17440
  includeStationary: boolean().optional()
17333
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17441
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17442
+ deviceId: number(),
17443
+ groupId: string().min(1)
17444
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17334
17445
  kind: "mutation",
17335
17446
  auth: "admin"
17336
17447
  }), 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({
@@ -17548,6 +17659,33 @@ var NativeCropRefSchema = object({
17548
17659
  h: number()
17549
17660
  })
17550
17661
  });
17662
+ object({
17663
+ crop: object({
17664
+ left: number(),
17665
+ top: number(),
17666
+ width: number().positive(),
17667
+ height: number().positive()
17668
+ }).optional(),
17669
+ content: object({
17670
+ width: number().int().positive(),
17671
+ height: number().int().positive()
17672
+ }),
17673
+ fit: _enum(["stretch", "contain"]),
17674
+ format: _enum([
17675
+ "rgb",
17676
+ "gray",
17677
+ "jpeg"
17678
+ ])
17679
+ });
17680
+ var FrameRefSchema = object({
17681
+ registryId: string().min(1),
17682
+ id: string().min(1),
17683
+ width: number().int().positive(),
17684
+ height: number().int().positive(),
17685
+ format: _enum(["rgb", "gray"]),
17686
+ timestamp: number(),
17687
+ capturedAt: number().optional()
17688
+ });
17551
17689
  var ModelFormatSchema$1 = _enum([
17552
17690
  "onnx",
17553
17691
  "coreml",
@@ -17613,7 +17751,8 @@ var PipelineModelOptionSchema = object({
17613
17751
  sizeMB: number()
17614
17752
  })),
17615
17753
  group: ModelVariantGroupSchema.optional(),
17616
- legacy: boolean().optional()
17754
+ legacy: boolean().optional(),
17755
+ provider: ModelProviderIdSchema.optional()
17617
17756
  });
17618
17757
  var ConfigFieldBridge = custom();
17619
17758
  var PipelineAddonSchemaSchema = object({
@@ -17792,6 +17931,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17792
17931
  steps: array(PipelineStepInputSchema).min(1),
17793
17932
  frame: FrameInputSchema.optional(),
17794
17933
  /**
17934
+ * Process-local lazy frame. Valid only when caller and provider resolve
17935
+ * in the same execution-group process; split/cross-node callers use
17936
+ * `frame`/`image` inline compatibility instead.
17937
+ */
17938
+ frameRef: FrameRefSchema.optional(),
17939
+ /**
17795
17940
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17796
17941
  * the decoded pixels live in. One more member of the one-of
17797
17942
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18087,7 +18232,10 @@ var NativeCropResultSchema = object({
18087
18232
  * Which source served this crop, so a quality-sensitive consumer (the native
18088
18233
  * `keyFrame`) can reject a degraded fallback:
18089
18234
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18090
- * quality path).
18235
+ * quality path). A subject-tile serve is also native-resolution and stays
18236
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18237
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18238
+ * internal crop result (`nativeHits` vs `tileHits`).
18091
18239
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18092
18240
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18093
18241
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18578,12 +18726,41 @@ var RunnerLocalLoadSchema = object({
18578
18726
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18579
18727
  * working unchanged when they switch to reading from the runner cap.
18580
18728
  */
18729
+ var FrameLazyCountersSchema = object({
18730
+ framesDecoded: number(),
18731
+ framesAdmitted: number(),
18732
+ framesDroppedPixelFree: number(),
18733
+ viewsMaterialized: number(),
18734
+ viewsSkipped: number(),
18735
+ workerToRunnerBytes: number(),
18736
+ runnerToPoolRawBytes: number(),
18737
+ runnerToPoolJpegBytes: number(),
18738
+ onDemandFullFrameRequests: number(),
18739
+ onDemandCropRequests: number(),
18740
+ nativeHits: number(),
18741
+ nativeMisses: number(),
18742
+ tileHits: number(),
18743
+ tileMisses: number(),
18744
+ fallbackHits: number(),
18745
+ fallbackMisses: number(),
18746
+ retainedWritesAvoided: number(),
18747
+ residentRefs: number(),
18748
+ residentBytes: number(),
18749
+ releases: number(),
18750
+ evictions: number(),
18751
+ staleMisses: number()
18752
+ });
18753
+ var FrameLazyMetricsSchema = object({
18754
+ node: FrameLazyCountersSchema,
18755
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18756
+ });
18581
18757
  var RunnerLocalMetricsSchema = object({
18582
18758
  nodeId: string(),
18583
18759
  activeCameras: number(),
18584
18760
  throttledCameras: number(),
18585
18761
  avgInferenceTimeMs: number(),
18586
- queueDepth: number()
18762
+ queueDepth: number(),
18763
+ frameLazy: FrameLazyMetricsSchema.optional()
18587
18764
  });
18588
18765
  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({
18589
18766
  handle: FrameHandleSchema,
@@ -19987,6 +20164,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19987
20164
  location: StorageLocationSchema,
19988
20165
  relativePath: string()
19989
20166
  }), _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" });
20167
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20168
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20169
+ var ProfileSettingsBagSchema = record(string(), unknown());
19990
20170
  /**
19991
20171
  * A live terminal session hosted by the provider addon. Output and input do
19992
20172
  * NOT flow through the capability — they use the addon data plane
@@ -20016,7 +20196,14 @@ var TerminalSessionInfoSchema = object({
20016
20196
  var TerminalProfileInfoSchema = object({
20017
20197
  profileId: string(),
20018
20198
  label: string(),
20019
- description: string().optional()
20199
+ description: string().optional(),
20200
+ /** Spawn defaults the instance form copies on create. */
20201
+ executable: string().optional(),
20202
+ args: array(string()).readonly().optional(),
20203
+ cwd: string().optional(),
20204
+ environment: array(string()).readonly().optional(),
20205
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20206
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20020
20207
  });
20021
20208
  /**
20022
20209
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20029,7 +20216,12 @@ var TerminalInstanceInfoSchema = object({
20029
20216
  profileId: string(),
20030
20217
  profileLabel: string(),
20031
20218
  name: string(),
20032
- enabled: boolean()
20219
+ enabled: boolean(),
20220
+ executable: string(),
20221
+ args: array(string()).readonly(),
20222
+ cwd: string(),
20223
+ environment: array(string()).readonly(),
20224
+ profileSettings: ProfileSettingsBagSchema
20033
20225
  });
20034
20226
  var TerminalLegacyCameraSchema = object({
20035
20227
  stableId: string(),
@@ -20059,7 +20251,23 @@ var TerminalOutputBatchSchema = object({
20059
20251
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20060
20252
  targetNodeId: string().min(1),
20061
20253
  profileId: string().min(1),
20062
- name: string().trim().min(1).max(160).optional()
20254
+ name: string().trim().min(1).max(160).optional(),
20255
+ executable: string().max(1024).optional(),
20256
+ args: array(string().max(2048)).max(64).optional(),
20257
+ cwd: string().max(1024).optional(),
20258
+ environment: array(string().max(4096)).max(64).optional(),
20259
+ profileSettings: ProfileSettingsBagSchema.optional()
20260
+ }), TerminalInstanceInfoSchema, {
20261
+ kind: "mutation",
20262
+ auth: "admin"
20263
+ }), method(object({
20264
+ instanceId: string().min(1),
20265
+ name: string().trim().min(1).max(160).optional(),
20266
+ executable: string().max(1024).optional(),
20267
+ args: array(string().max(2048)).max(64).optional(),
20268
+ cwd: string().max(1024).optional(),
20269
+ environment: array(string().max(4096)).max(64).optional(),
20270
+ profileSettings: ProfileSettingsBagSchema.optional()
20063
20271
  }), TerminalInstanceInfoSchema, {
20064
20272
  kind: "mutation",
20065
20273
  auth: "admin"
@@ -20081,7 +20289,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20081
20289
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20082
20290
  profileId: string(),
20083
20291
  cols: number().int().positive(),
20084
- rows: number().int().positive()
20292
+ rows: number().int().positive(),
20293
+ executable: string().max(1024).optional(),
20294
+ args: array(string().max(2048)).max(64).optional(),
20295
+ cwd: string().max(1024).optional(),
20296
+ environment: array(string().max(4096)).max(64).optional()
20085
20297
  }), TerminalSessionInfoSchema, {
20086
20298
  kind: "mutation",
20087
20299
  auth: "admin"
@@ -23964,10 +24176,10 @@ var lawnMowerControlCapability = {
23964
24176
  *
23965
24177
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
23966
24178
  * to receive an ordered list of candidate base URLs it should race
23967
- * on connect — LAN IPv4 first (lowest latency when on same network),
23968
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
23969
- * race them with short timeouts and stick with the winner for the
23970
- * session.
24179
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24180
+ * when on the same network), then public hostname (if a tunnel is
24181
+ * up). The SDK can race them with short timeouts and stick with the
24182
+ * winner for the session.
23971
24183
  *
23972
24184
  * Why hub-only: agents are not directly addressable by the operator's
23973
24185
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24122,6 +24334,17 @@ var NotificationEndpointSchema = object({
24122
24334
  /** What the ranking currently resolves to (null when nothing is reachable). */
24123
24335
  resolved: string().nullable()
24124
24336
  });
24337
+ /**
24338
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24339
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24340
+ * currently expands to, so the UI can show the effective set either way.
24341
+ */
24342
+ var ViewerEndpointsSchema = object({
24343
+ /** The operator's explicit race set, or empty for AUTO. */
24344
+ baseUrls: array(string()).readonly(),
24345
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24346
+ resolved: array(string()).readonly()
24347
+ });
24125
24348
  var AllowedAddressesSchema = object({
24126
24349
  /**
24127
24350
  * Allowlist of interface addresses operators have explicitly opted
@@ -24130,6 +24353,20 @@ var AllowedAddressesSchema = object({
24130
24353
  * Network Addresses admin page and persisted by the addon.
24131
24354
  */
24132
24355
  addresses: array(string()).readonly() });
24356
+ var TlsStatusSchema = object({
24357
+ mode: _enum([
24358
+ "generated",
24359
+ "uploaded",
24360
+ "disabled"
24361
+ ]),
24362
+ leafFingerprintSha256: string().nullable(),
24363
+ caFingerprintSha256: string().nullable(),
24364
+ validTo: string().nullable(),
24365
+ sans: array(string()),
24366
+ caCertPem: string().nullable(),
24367
+ reissueError: string().nullable(),
24368
+ restartRequired: boolean()
24369
+ });
24133
24370
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24134
24371
  /**
24135
24372
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24139,17 +24376,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24139
24376
  */
24140
24377
  port: number().int().min(1).max(65535).optional(),
24141
24378
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24142
- * candidate. Default `true`. */
24379
+ * candidate. Default `false` — loopback is not a client route. */
24143
24380
  includeLoopback: boolean().optional(),
24144
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24145
- * Default `false`. */
24381
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24382
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24383
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24146
24384
  ipv4Only: boolean().optional(),
24147
24385
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24148
24386
  * Pass `'https'` when the caller is itself loaded over HTTPS
24149
24387
  * to avoid mixed-content blocks in the browser. The public
24150
24388
  * tunnel always emits `https://` regardless. */
24151
24389
  scheme: _enum(["http", "https"]).optional()
24152
- }), 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" });
24390
+ }), 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, {
24391
+ kind: "mutation",
24392
+ auth: "admin"
24393
+ }), method(object({
24394
+ certPem: string().min(1),
24395
+ keyPem: string().min(1),
24396
+ caPem: string().optional()
24397
+ }), TlsStatusSchema, {
24398
+ kind: "mutation",
24399
+ auth: "admin"
24400
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24401
+ kind: "mutation",
24402
+ auth: "admin"
24403
+ });
24153
24404
  var LockControlStatusSchema = object({
24154
24405
  /** Lifecycle state of the lock. `jammed` means the motor reported
24155
24406
  * failure to reach the target — operator intervention required. */
@@ -25710,7 +25961,12 @@ var PlateInfoSchema = object({
25710
25961
  plateBbox: BoundingBoxSchema.optional(),
25711
25962
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
25712
25963
  keyFrameMediaKey: string().optional(),
25713
- base64: string().optional()
25964
+ base64: string().optional(),
25965
+ /**
25966
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
25967
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
25968
+ */
25969
+ cropUrl: string().optional()
25714
25970
  });
25715
25971
  var MediaFileLiteSchema = object({
25716
25972
  key: string(),
@@ -31234,6 +31490,12 @@ Object.freeze({
31234
31490
  addonId: null,
31235
31491
  access: "view"
31236
31492
  },
31493
+ "deviceManager.getBindingsBatch": {
31494
+ capName: "device-manager",
31495
+ capScope: "system",
31496
+ addonId: null,
31497
+ access: "view"
31498
+ },
31237
31499
  "deviceManager.getChildren": {
31238
31500
  capName: "device-manager",
31239
31501
  capScope: "system",
@@ -31294,6 +31556,12 @@ Object.freeze({
31294
31556
  addonId: null,
31295
31557
  access: "view"
31296
31558
  },
31559
+ "deviceManager.getLinkedDevicesBatch": {
31560
+ capName: "device-manager",
31561
+ capScope: "system",
31562
+ addonId: null,
31563
+ access: "view"
31564
+ },
31297
31565
  "deviceManager.getRoleDisplayDefaults": {
31298
31566
  capName: "device-manager",
31299
31567
  capScope: "system",
@@ -32176,6 +32444,12 @@ Object.freeze({
32176
32444
  addonId: null,
32177
32445
  access: "create"
32178
32446
  },
32447
+ "localNetwork.downloadCa": {
32448
+ capName: "local-network",
32449
+ capScope: "system",
32450
+ addonId: null,
32451
+ access: "view"
32452
+ },
32179
32453
  "localNetwork.getAllowedAddresses": {
32180
32454
  capName: "local-network",
32181
32455
  capScope: "system",
@@ -32200,18 +32474,42 @@ Object.freeze({
32200
32474
  addonId: null,
32201
32475
  access: "view"
32202
32476
  },
32477
+ "localNetwork.getTlsStatus": {
32478
+ capName: "local-network",
32479
+ capScope: "system",
32480
+ addonId: null,
32481
+ access: "view"
32482
+ },
32483
+ "localNetwork.getViewerEndpoints": {
32484
+ capName: "local-network",
32485
+ capScope: "system",
32486
+ addonId: null,
32487
+ access: "view"
32488
+ },
32203
32489
  "localNetwork.list": {
32204
32490
  capName: "local-network",
32205
32491
  capScope: "system",
32206
32492
  addonId: null,
32207
32493
  access: "view"
32208
32494
  },
32495
+ "localNetwork.regenerateCertificate": {
32496
+ capName: "local-network",
32497
+ capScope: "system",
32498
+ addonId: null,
32499
+ access: "create"
32500
+ },
32209
32501
  "localNetwork.resetAllowlistToBestMatch": {
32210
32502
  capName: "local-network",
32211
32503
  capScope: "system",
32212
32504
  addonId: null,
32213
32505
  access: "delete"
32214
32506
  },
32507
+ "localNetwork.revertToGeneratedCertificate": {
32508
+ capName: "local-network",
32509
+ capScope: "system",
32510
+ addonId: null,
32511
+ access: "create"
32512
+ },
32215
32513
  "localNetwork.setAllowedAddresses": {
32216
32514
  capName: "local-network",
32217
32515
  capScope: "system",
@@ -32224,6 +32522,18 @@ Object.freeze({
32224
32522
  addonId: null,
32225
32523
  access: "create"
32226
32524
  },
32525
+ "localNetwork.setViewerEndpoints": {
32526
+ capName: "local-network",
32527
+ capScope: "system",
32528
+ addonId: null,
32529
+ access: "create"
32530
+ },
32531
+ "localNetwork.uploadCertificate": {
32532
+ capName: "local-network",
32533
+ capScope: "system",
32534
+ addonId: null,
32535
+ access: "create"
32536
+ },
32227
32537
  "lockControl.lock": {
32228
32538
  capName: "lock-control",
32229
32539
  capScope: "device",
@@ -33022,6 +33332,12 @@ Object.freeze({
33022
33332
  addonId: null,
33023
33333
  access: "view"
33024
33334
  },
33335
+ "pipelineAnalytics.getGroup": {
33336
+ capName: "pipeline-analytics",
33337
+ capScope: "device",
33338
+ addonId: null,
33339
+ access: "view"
33340
+ },
33025
33341
  "pipelineAnalytics.getKeyEvents": {
33026
33342
  capName: "pipeline-analytics",
33027
33343
  capScope: "device",
@@ -33106,6 +33422,12 @@ Object.freeze({
33106
33422
  addonId: null,
33107
33423
  access: "view"
33108
33424
  },
33425
+ "pipelineAnalytics.listGroups": {
33426
+ capName: "pipeline-analytics",
33427
+ capScope: "device",
33428
+ addonId: null,
33429
+ access: "view"
33430
+ },
33109
33431
  "pipelineAnalytics.listOpsLog": {
33110
33432
  capName: "pipeline-analytics",
33111
33433
  capScope: "device",
@@ -35104,6 +35426,12 @@ Object.freeze({
35104
35426
  addonId: null,
35105
35427
  access: "create"
35106
35428
  },
35429
+ "terminalSession.updateInstance": {
35430
+ capName: "terminal-session",
35431
+ capScope: "system",
35432
+ addonId: null,
35433
+ access: "create"
35434
+ },
35107
35435
  "terminalSession.writeInput": {
35108
35436
  capName: "terminal-session",
35109
35437
  capScope: "system",
@@ -35881,6 +36209,11 @@ Object.freeze({
35881
36209
  form: "single",
35882
36210
  optional: false
35883
36211
  }],
36212
+ "deviceManager.getBindingsBatch": [{
36213
+ name: "deviceIds",
36214
+ form: "array",
36215
+ optional: false
36216
+ }],
35884
36217
  "deviceManager.getChildren": [{
35885
36218
  name: "parentDeviceId",
35886
36219
  form: "single",
@@ -35926,6 +36259,11 @@ Object.freeze({
35926
36259
  form: "single",
35927
36260
  optional: false
35928
36261
  }],
36262
+ "deviceManager.getLinkedDevicesBatch": [{
36263
+ name: "deviceIds",
36264
+ form: "array",
36265
+ optional: false
36266
+ }],
35929
36267
  "deviceManager.getSettingsSchema": [{
35930
36268
  name: "deviceId",
35931
36269
  form: "single",
@@ -35946,6 +36284,11 @@ Object.freeze({
35946
36284
  form: "single",
35947
36285
  optional: false
35948
36286
  }],
36287
+ "deviceManager.listAll": [{
36288
+ name: "deviceIds",
36289
+ form: "array",
36290
+ optional: true
36291
+ }],
35949
36292
  "deviceManager.loadConfig": [{
35950
36293
  name: "deviceId",
35951
36294
  form: "single",
@@ -36519,6 +36862,11 @@ Object.freeze({
36519
36862
  form: "single",
36520
36863
  optional: false
36521
36864
  }],
36865
+ "pipelineAnalytics.getGroup": [{
36866
+ name: "deviceId",
36867
+ form: "single",
36868
+ optional: false
36869
+ }],
36522
36870
  "pipelineAnalytics.getKeyEvents": [{
36523
36871
  name: "deviceId",
36524
36872
  form: "single",
@@ -36574,6 +36922,11 @@ Object.freeze({
36574
36922
  form: "array",
36575
36923
  optional: false
36576
36924
  }],
36925
+ "pipelineAnalytics.listGroups": [{
36926
+ name: "deviceIds",
36927
+ form: "array",
36928
+ optional: false
36929
+ }],
36577
36930
  "pipelineAnalytics.listOpsLog": [{
36578
36931
  name: "deviceId",
36579
36932
  form: "single",
@@ -37591,6 +37944,35 @@ Object.freeze(Object.fromEntries([{
37591
37944
  }]
37592
37945
  }].map((s) => [s.stepId, s.defaultModelId])));
37593
37946
  string().min(1);
37947
+ var CLUSTER_STEP_SETTING_FIELDS = [{
37948
+ stepId: "face-embedding",
37949
+ key: "minLandmarkFaceSize",
37950
+ label: "Min face size for recognition (detection px)",
37951
+ 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.",
37952
+ type: "slider",
37953
+ min: 0,
37954
+ max: 64,
37955
+ step: 2,
37956
+ default: 24
37957
+ }];
37958
+ function clusterStepSettingKey(stepId, fieldKey) {
37959
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
37960
+ }
37961
+ var ClusterSettingNumberSchema = number().finite();
37962
+ function readClusterStepSettings(config) {
37963
+ const out = {};
37964
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
37965
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
37966
+ const value = parsed.success ? parsed.data : field.default;
37967
+ const existing = out[field.stepId] ?? {};
37968
+ out[field.stepId] = {
37969
+ ...existing,
37970
+ [field.key]: value
37971
+ };
37972
+ }
37973
+ return out;
37974
+ }
37975
+ readClusterStepSettings({});
37594
37976
  object({
37595
37977
  /**
37596
37978
  * Fraction of the box's own size added on EACH side before cutting.