@camstack/addon-cloudflare 1.2.25 → 1.2.27

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.
@@ -5800,6 +5800,13 @@ var BaseAddon = class {
5800
5800
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
5801
5801
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
5802
5802
  _registeredCapNames = [];
5803
+ /**
5804
+ * True only after `readAddonStore` actually answered. Constructor
5805
+ * defaults look like stored config when the store is down — a forked
5806
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
5807
+ * mode, 2026-08-25) is not "the operator chose this".
5808
+ */
5809
+ settingsStoreReady = false;
5803
5810
  /** Default config values. Provided via constructor. */
5804
5811
  defaults;
5805
5812
  constructor(defaults) {
@@ -6200,7 +6207,9 @@ var BaseAddon = class {
6200
6207
  ];
6201
6208
  let lastErr;
6202
6209
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
6203
- return await settings.readAddonStore() ?? {};
6210
+ const stored = await settings.readAddonStore() ?? {};
6211
+ this.settingsStoreReady = true;
6212
+ return stored;
6204
6213
  } catch (err) {
6205
6214
  lastErr = err;
6206
6215
  const msg = err instanceof Error ? err.message : String(err);
@@ -6208,6 +6217,7 @@ var BaseAddon = class {
6208
6217
  if (attempt === delaysMs.length) break;
6209
6218
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
6210
6219
  }
6220
+ this.settingsStoreReady = false;
6211
6221
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries — using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
6212
6222
  return {};
6213
6223
  }
@@ -8003,6 +8013,15 @@ var LabelDefinitionSchema = object({
8003
8013
  description: string().optional(),
8004
8014
  icon: string().optional()
8005
8015
  });
8016
+ var ClassMapDefinitionSchema = object({
8017
+ mapping: record(string(), _enum([
8018
+ "person",
8019
+ "vehicle",
8020
+ "animal",
8021
+ "package"
8022
+ ])),
8023
+ preserveOriginal: boolean()
8024
+ });
8006
8025
  var MODEL_FORMATS = [
8007
8026
  "onnx",
8008
8027
  "coreml",
@@ -8086,6 +8105,12 @@ var ModelVariantGroupSchema = object({
8086
8105
  */
8087
8106
  resolution: number().int().positive().optional()
8088
8107
  });
8108
+ var ModelProviderIdSchema = _enum([
8109
+ "camstack",
8110
+ "frigate",
8111
+ "scrypted",
8112
+ "custom"
8113
+ ]);
8089
8114
  var ModelCatalogEntrySchema = object({
8090
8115
  id: string(),
8091
8116
  name: string(),
@@ -8181,7 +8206,19 @@ var ModelCatalogEntrySchema = object({
8181
8206
  * `id` stays the source of truth for resolution/download/persistence; grouping
8182
8207
  * is a presentation overlay resolved back to an `id`.
8183
8208
  */
8184
- group: ModelVariantGroupSchema.optional()
8209
+ group: ModelVariantGroupSchema.optional(),
8210
+ /**
8211
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
8212
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
8213
+ * persisted before this field existed (`inferModelProvider` fills those).
8214
+ */
8215
+ provider: ModelProviderIdSchema.optional(),
8216
+ /**
8217
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8218
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8219
+ * labels already ARE the CamStack macros (Scrypted identity map).
8220
+ */
8221
+ classMap: ClassMapDefinitionSchema.optional()
8185
8222
  });
8186
8223
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8187
8224
  format: literal("openvino"),
@@ -8210,7 +8247,8 @@ var ModelConvertMetadataSchema = object({
8210
8247
  "ocr",
8211
8248
  "segmentation"
8212
8249
  ]),
8213
- faceAlignment: boolean().optional()
8250
+ faceAlignment: boolean().optional(),
8251
+ classMap: ClassMapDefinitionSchema.optional()
8214
8252
  });
8215
8253
  var ConvertResultSchema = object({
8216
8254
  entry: ModelCatalogEntrySchema,
@@ -14388,12 +14426,15 @@ var NcOccupancyConditionSchema = object({
14388
14426
  * there is no second switch that can disagree with the first and every rule
14389
14427
  * authored before the decision migrates for free (`audioModeOf`):
14390
14428
  *
14391
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
14392
- * classifier labels with one of them. No window, no percentage:
14393
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
14394
- * `throttle` cooldown is the only brake. The per-label confidence floor is
14395
- * the analyzer's (`classificationMinScore`, per device) a label only
14396
- * reaches this condition if the classifier was already confident enough.
14429
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
14430
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
14431
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
14432
+ * frames is the wrong question for a classifier that labels 1–3 frames
14433
+ * per episode. The count window is the brake that drops a single-frame
14434
+ * false positive; the rule's own `throttle` cooldown is the other. The
14435
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
14436
+ * per device) — a label only reaches this condition if the classifier was
14437
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
14397
14438
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
14398
14439
  * the condition: at least `hitPercent`% of the samples over
14399
14440
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -14420,14 +14461,22 @@ var NcOccupancyConditionSchema = object({
14420
14461
  * an operator who typed `dog` mean the same thing.
14421
14462
  */
14422
14463
  var NcAudioConditionSchema = object({
14423
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
14464
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
14424
14465
  labels: array(string().min(1)).min(1).optional(),
14425
14466
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
14426
14467
  dbThreshold: number().min(-96).max(0).optional(),
14427
14468
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
14428
14469
  hitPercent: number().int().min(1).max(100).default(60),
14429
14470
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
14430
- samplingSeconds: number().int().min(1).max(300).default(10)
14471
+ samplingSeconds: number().int().min(1).max(300).default(10),
14472
+ /**
14473
+ * LABEL MODE: how many labelled frames must land inside
14474
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
14475
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
14476
+ */
14477
+ confirmHits: number().int().min(1).max(20).optional(),
14478
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
14479
+ confirmWindowSec: number().int().min(1).max(60).optional()
14431
14480
  });
14432
14481
  /**
14433
14482
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -16801,6 +16850,46 @@ var RecentTracksPageSchema = object({
16801
16850
  /** Cursor for the next page, or null when this page is the last. */
16802
16851
  nextCursor: string().nullable()
16803
16852
  });
16853
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
16854
+ var LIST_GROUPS_MAX_LIMIT = 100;
16855
+ var AnalyticsGroupRecordSchema = object({
16856
+ id: string(),
16857
+ deviceId: number().int(),
16858
+ openedAt: number().int(),
16859
+ closedAt: number().int(),
16860
+ timestamp: number().int(),
16861
+ memberCount: number().int(),
16862
+ memberTrackIds: array(string()).readonly(),
16863
+ className: string(),
16864
+ classes: array(string()).readonly(),
16865
+ /** Relative event-media path, or null when the group has no picture yet. */
16866
+ mediaUrl: string().nullable(),
16867
+ singleton: boolean()
16868
+ });
16869
+ var AnalyticsGroupMemberSchema = object({
16870
+ trackId: string(),
16871
+ deviceId: number().int(),
16872
+ className: string(),
16873
+ firstSeen: number().int(),
16874
+ lastSeen: number().int(),
16875
+ mediaUrl: string().nullable()
16876
+ });
16877
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
16878
+ var ListGroupsQueryInput = object({
16879
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
16880
+ deviceIds: array(number()),
16881
+ /** Window lower bound on `closedAt` (inclusive). */
16882
+ since: number().optional(),
16883
+ /** Window upper bound on `openedAt` (inclusive). */
16884
+ until: number().optional(),
16885
+ limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
16886
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
16887
+ cursor: string().optional()
16888
+ });
16889
+ var ListGroupsPageSchema = object({
16890
+ groups: array(AnalyticsGroupRecordSchema).readonly(),
16891
+ nextCursor: string().nullable()
16892
+ });
16804
16893
  var KeyEventQueryInput = object({
16805
16894
  deviceId: number(),
16806
16895
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16876,7 +16965,9 @@ var TrackCascadeCountsSchema = object({
16876
16965
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
16877
16966
  plates: number().int(),
16878
16967
  /** Per-track CLIP search vectors removed (best-effort). */
16879
- embeddings: number().int()
16968
+ embeddings: number().int(),
16969
+ /** Group membership + group rows removed with their last member (best-effort). */
16970
+ groups: number().int()
16880
16971
  });
16881
16972
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
16882
16973
  var DiskReconcileCountsSchema = object({
@@ -17022,7 +17113,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17022
17113
  * stationary registry). Default false: the timeline lists passages,
17023
17114
  * not parking records (operator decision, 2026-08-15). */
17024
17115
  includeStationary: boolean().optional()
17025
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
17116
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
17117
+ deviceId: number(),
17118
+ groupId: string().min(1)
17119
+ }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
17026
17120
  kind: "mutation",
17027
17121
  auth: "admin"
17028
17122
  }), 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({
@@ -17240,6 +17334,33 @@ var NativeCropRefSchema = object({
17240
17334
  h: number()
17241
17335
  })
17242
17336
  });
17337
+ object({
17338
+ crop: object({
17339
+ left: number(),
17340
+ top: number(),
17341
+ width: number().positive(),
17342
+ height: number().positive()
17343
+ }).optional(),
17344
+ content: object({
17345
+ width: number().int().positive(),
17346
+ height: number().int().positive()
17347
+ }),
17348
+ fit: _enum(["stretch", "contain"]),
17349
+ format: _enum([
17350
+ "rgb",
17351
+ "gray",
17352
+ "jpeg"
17353
+ ])
17354
+ });
17355
+ var FrameRefSchema = object({
17356
+ registryId: string().min(1),
17357
+ id: string().min(1),
17358
+ width: number().int().positive(),
17359
+ height: number().int().positive(),
17360
+ format: _enum(["rgb", "gray"]),
17361
+ timestamp: number(),
17362
+ capturedAt: number().optional()
17363
+ });
17243
17364
  var ModelFormatSchema$1 = _enum([
17244
17365
  "onnx",
17245
17366
  "coreml",
@@ -17305,7 +17426,8 @@ var PipelineModelOptionSchema = object({
17305
17426
  sizeMB: number()
17306
17427
  })),
17307
17428
  group: ModelVariantGroupSchema.optional(),
17308
- legacy: boolean().optional()
17429
+ legacy: boolean().optional(),
17430
+ provider: ModelProviderIdSchema.optional()
17309
17431
  });
17310
17432
  var ConfigFieldBridge = custom();
17311
17433
  var PipelineAddonSchemaSchema = object({
@@ -17484,6 +17606,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17484
17606
  steps: array(PipelineStepInputSchema).min(1),
17485
17607
  frame: FrameInputSchema.optional(),
17486
17608
  /**
17609
+ * Process-local lazy frame. Valid only when caller and provider resolve
17610
+ * in the same execution-group process; split/cross-node callers use
17611
+ * `frame`/`image` inline compatibility instead.
17612
+ */
17613
+ frameRef: FrameRefSchema.optional(),
17614
+ /**
17487
17615
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17488
17616
  * the decoded pixels live in. One more member of the one-of
17489
17617
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -17739,7 +17867,10 @@ var NativeCropResultSchema = object({
17739
17867
  * Which source served this crop, so a quality-sensitive consumer (the native
17740
17868
  * `keyFrame`) can reject a degraded fallback:
17741
17869
  * - `native` — cut from the decode worker's retained NATIVE surface (the
17742
- * quality path).
17870
+ * quality path). A subject-tile serve is also native-resolution and stays
17871
+ * `native` here: the public enum cannot name `tile` without a breaking cap
17872
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
17873
+ * internal crop result (`nativeHits` vs `tileHits`).
17743
17874
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
17744
17875
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
17745
17876
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18230,12 +18361,41 @@ var RunnerLocalLoadSchema = object({
18230
18361
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18231
18362
  * working unchanged when they switch to reading from the runner cap.
18232
18363
  */
18364
+ var FrameLazyCountersSchema = object({
18365
+ framesDecoded: number(),
18366
+ framesAdmitted: number(),
18367
+ framesDroppedPixelFree: number(),
18368
+ viewsMaterialized: number(),
18369
+ viewsSkipped: number(),
18370
+ workerToRunnerBytes: number(),
18371
+ runnerToPoolRawBytes: number(),
18372
+ runnerToPoolJpegBytes: number(),
18373
+ onDemandFullFrameRequests: number(),
18374
+ onDemandCropRequests: number(),
18375
+ nativeHits: number(),
18376
+ nativeMisses: number(),
18377
+ tileHits: number(),
18378
+ tileMisses: number(),
18379
+ fallbackHits: number(),
18380
+ fallbackMisses: number(),
18381
+ retainedWritesAvoided: number(),
18382
+ residentRefs: number(),
18383
+ residentBytes: number(),
18384
+ releases: number(),
18385
+ evictions: number(),
18386
+ staleMisses: number()
18387
+ });
18388
+ var FrameLazyMetricsSchema = object({
18389
+ node: FrameLazyCountersSchema,
18390
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18391
+ });
18233
18392
  var RunnerLocalMetricsSchema = object({
18234
18393
  nodeId: string(),
18235
18394
  activeCameras: number(),
18236
18395
  throttledCameras: number(),
18237
18396
  avgInferenceTimeMs: number(),
18238
- queueDepth: number()
18397
+ queueDepth: number(),
18398
+ frameLazy: FrameLazyMetricsSchema.optional()
18239
18399
  });
18240
18400
  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({
18241
18401
  handle: FrameHandleSchema,
@@ -19535,6 +19695,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19535
19695
  location: StorageLocationSchema,
19536
19696
  relativePath: string()
19537
19697
  }), _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" });
19698
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19699
+ var ProfileSettingsSchemaBridge = unknown().nullable();
19700
+ var ProfileSettingsBagSchema = record(string(), unknown());
19538
19701
  /**
19539
19702
  * A live terminal session hosted by the provider addon. Output and input do
19540
19703
  * NOT flow through the capability — they use the addon data plane
@@ -19564,7 +19727,14 @@ var TerminalSessionInfoSchema = object({
19564
19727
  var TerminalProfileInfoSchema = object({
19565
19728
  profileId: string(),
19566
19729
  label: string(),
19567
- description: string().optional()
19730
+ description: string().optional(),
19731
+ /** Spawn defaults the instance form copies on create. */
19732
+ executable: string().optional(),
19733
+ args: array(string()).readonly().optional(),
19734
+ cwd: string().optional(),
19735
+ environment: array(string()).readonly().optional(),
19736
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
19737
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
19568
19738
  });
19569
19739
  /**
19570
19740
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19577,7 +19747,12 @@ var TerminalInstanceInfoSchema = object({
19577
19747
  profileId: string(),
19578
19748
  profileLabel: string(),
19579
19749
  name: string(),
19580
- enabled: boolean()
19750
+ enabled: boolean(),
19751
+ executable: string(),
19752
+ args: array(string()).readonly(),
19753
+ cwd: string(),
19754
+ environment: array(string()).readonly(),
19755
+ profileSettings: ProfileSettingsBagSchema
19581
19756
  });
19582
19757
  var TerminalLegacyCameraSchema = object({
19583
19758
  stableId: string(),
@@ -19607,7 +19782,23 @@ var TerminalOutputBatchSchema = object({
19607
19782
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19608
19783
  targetNodeId: string().min(1),
19609
19784
  profileId: string().min(1),
19610
- name: string().trim().min(1).max(160).optional()
19785
+ name: string().trim().min(1).max(160).optional(),
19786
+ executable: string().max(1024).optional(),
19787
+ args: array(string().max(2048)).max(64).optional(),
19788
+ cwd: string().max(1024).optional(),
19789
+ environment: array(string().max(4096)).max(64).optional(),
19790
+ profileSettings: ProfileSettingsBagSchema.optional()
19791
+ }), TerminalInstanceInfoSchema, {
19792
+ kind: "mutation",
19793
+ auth: "admin"
19794
+ }), method(object({
19795
+ instanceId: string().min(1),
19796
+ name: string().trim().min(1).max(160).optional(),
19797
+ executable: string().max(1024).optional(),
19798
+ args: array(string().max(2048)).max(64).optional(),
19799
+ cwd: string().max(1024).optional(),
19800
+ environment: array(string().max(4096)).max(64).optional(),
19801
+ profileSettings: ProfileSettingsBagSchema.optional()
19611
19802
  }), TerminalInstanceInfoSchema, {
19612
19803
  kind: "mutation",
19613
19804
  auth: "admin"
@@ -19629,7 +19820,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19629
19820
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19630
19821
  profileId: string(),
19631
19822
  cols: number().int().positive(),
19632
- rows: number().int().positive()
19823
+ rows: number().int().positive(),
19824
+ executable: string().max(1024).optional(),
19825
+ args: array(string().max(2048)).max(64).optional(),
19826
+ cwd: string().max(1024).optional(),
19827
+ environment: array(string().max(4096)).max(64).optional()
19633
19828
  }), TerminalSessionInfoSchema, {
19634
19829
  kind: "mutation",
19635
19830
  auth: "admin"
@@ -22434,10 +22629,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
22434
22629
  *
22435
22630
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
22436
22631
  * to receive an ordered list of candidate base URLs it should race
22437
- * on connect — LAN IPv4 first (lowest latency when on same network),
22438
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
22439
- * race them with short timeouts and stick with the winner for the
22440
- * session.
22632
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
22633
+ * when on the same network), then public hostname (if a tunnel is
22634
+ * up). The SDK can race them with short timeouts and stick with the
22635
+ * winner for the session.
22441
22636
  *
22442
22637
  * Why hub-only: agents are not directly addressable by the operator's
22443
22638
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -22592,6 +22787,17 @@ var NotificationEndpointSchema = object({
22592
22787
  /** What the ranking currently resolves to (null when nothing is reachable). */
22593
22788
  resolved: string().nullable()
22594
22789
  });
22790
+ /**
22791
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
22792
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
22793
+ * currently expands to, so the UI can show the effective set either way.
22794
+ */
22795
+ var ViewerEndpointsSchema = object({
22796
+ /** The operator's explicit race set, or empty for AUTO. */
22797
+ baseUrls: array(string()).readonly(),
22798
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
22799
+ resolved: array(string()).readonly()
22800
+ });
22595
22801
  var AllowedAddressesSchema = object({
22596
22802
  /**
22597
22803
  * Allowlist of interface addresses operators have explicitly opted
@@ -22600,6 +22806,20 @@ var AllowedAddressesSchema = object({
22600
22806
  * Network Addresses admin page and persisted by the addon.
22601
22807
  */
22602
22808
  addresses: array(string()).readonly() });
22809
+ var TlsStatusSchema = object({
22810
+ mode: _enum([
22811
+ "generated",
22812
+ "uploaded",
22813
+ "disabled"
22814
+ ]),
22815
+ leafFingerprintSha256: string().nullable(),
22816
+ caFingerprintSha256: string().nullable(),
22817
+ validTo: string().nullable(),
22818
+ sans: array(string()),
22819
+ caCertPem: string().nullable(),
22820
+ reissueError: string().nullable(),
22821
+ restartRequired: boolean()
22822
+ });
22603
22823
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22604
22824
  /**
22605
22825
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -22609,17 +22829,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
22609
22829
  */
22610
22830
  port: number().int().min(1).max(65535).optional(),
22611
22831
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22612
- * candidate. Default `true`. */
22832
+ * candidate. Default `false` — loopback is not a client route. */
22613
22833
  includeLoopback: boolean().optional(),
22614
- /** Skip IPv6 entries. Some legacy clients can't parse them.
22615
- * Default `false`. */
22834
+ /** Skip IPv6 entries. Default `false` the palette includes stable
22835
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
22836
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
22616
22837
  ipv4Only: boolean().optional(),
22617
22838
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
22618
22839
  * Pass `'https'` when the caller is itself loaded over HTTPS
22619
22840
  * to avoid mixed-content blocks in the browser. The public
22620
22841
  * tunnel always emits `https://` regardless. */
22621
22842
  scheme: _enum(["http", "https"]).optional()
22622
- }), 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" });
22843
+ }), 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, {
22844
+ kind: "mutation",
22845
+ auth: "admin"
22846
+ }), method(object({
22847
+ certPem: string().min(1),
22848
+ keyPem: string().min(1),
22849
+ caPem: string().optional()
22850
+ }), TlsStatusSchema, {
22851
+ kind: "mutation",
22852
+ auth: "admin"
22853
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
22854
+ kind: "mutation",
22855
+ auth: "admin"
22856
+ });
22623
22857
  object({
22624
22858
  /** Lifecycle state of the lock. `jammed` means the motor reported
22625
22859
  * failure to reach the target — operator intervention required. */
@@ -23800,7 +24034,12 @@ var PlateInfoSchema = object({
23800
24034
  plateBbox: BoundingBoxSchema.optional(),
23801
24035
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
23802
24036
  keyFrameMediaKey: string().optional(),
23803
- base64: string().optional()
24037
+ base64: string().optional(),
24038
+ /**
24039
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
24040
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
24041
+ */
24042
+ cropUrl: string().optional()
23804
24043
  });
23805
24044
  var MediaFileLiteSchema = object({
23806
24045
  key: string(),
@@ -28382,6 +28621,12 @@ Object.freeze({
28382
28621
  addonId: null,
28383
28622
  access: "create"
28384
28623
  },
28624
+ "localNetwork.downloadCa": {
28625
+ capName: "local-network",
28626
+ capScope: "system",
28627
+ addonId: null,
28628
+ access: "view"
28629
+ },
28385
28630
  "localNetwork.getAllowedAddresses": {
28386
28631
  capName: "local-network",
28387
28632
  capScope: "system",
@@ -28406,18 +28651,42 @@ Object.freeze({
28406
28651
  addonId: null,
28407
28652
  access: "view"
28408
28653
  },
28654
+ "localNetwork.getTlsStatus": {
28655
+ capName: "local-network",
28656
+ capScope: "system",
28657
+ addonId: null,
28658
+ access: "view"
28659
+ },
28660
+ "localNetwork.getViewerEndpoints": {
28661
+ capName: "local-network",
28662
+ capScope: "system",
28663
+ addonId: null,
28664
+ access: "view"
28665
+ },
28409
28666
  "localNetwork.list": {
28410
28667
  capName: "local-network",
28411
28668
  capScope: "system",
28412
28669
  addonId: null,
28413
28670
  access: "view"
28414
28671
  },
28672
+ "localNetwork.regenerateCertificate": {
28673
+ capName: "local-network",
28674
+ capScope: "system",
28675
+ addonId: null,
28676
+ access: "create"
28677
+ },
28415
28678
  "localNetwork.resetAllowlistToBestMatch": {
28416
28679
  capName: "local-network",
28417
28680
  capScope: "system",
28418
28681
  addonId: null,
28419
28682
  access: "delete"
28420
28683
  },
28684
+ "localNetwork.revertToGeneratedCertificate": {
28685
+ capName: "local-network",
28686
+ capScope: "system",
28687
+ addonId: null,
28688
+ access: "create"
28689
+ },
28421
28690
  "localNetwork.setAllowedAddresses": {
28422
28691
  capName: "local-network",
28423
28692
  capScope: "system",
@@ -28430,6 +28699,18 @@ Object.freeze({
28430
28699
  addonId: null,
28431
28700
  access: "create"
28432
28701
  },
28702
+ "localNetwork.setViewerEndpoints": {
28703
+ capName: "local-network",
28704
+ capScope: "system",
28705
+ addonId: null,
28706
+ access: "create"
28707
+ },
28708
+ "localNetwork.uploadCertificate": {
28709
+ capName: "local-network",
28710
+ capScope: "system",
28711
+ addonId: null,
28712
+ access: "create"
28713
+ },
28433
28714
  "lockControl.lock": {
28434
28715
  capName: "lock-control",
28435
28716
  capScope: "device",
@@ -29228,6 +29509,12 @@ Object.freeze({
29228
29509
  addonId: null,
29229
29510
  access: "view"
29230
29511
  },
29512
+ "pipelineAnalytics.getGroup": {
29513
+ capName: "pipeline-analytics",
29514
+ capScope: "device",
29515
+ addonId: null,
29516
+ access: "view"
29517
+ },
29231
29518
  "pipelineAnalytics.getKeyEvents": {
29232
29519
  capName: "pipeline-analytics",
29233
29520
  capScope: "device",
@@ -29312,6 +29599,12 @@ Object.freeze({
29312
29599
  addonId: null,
29313
29600
  access: "view"
29314
29601
  },
29602
+ "pipelineAnalytics.listGroups": {
29603
+ capName: "pipeline-analytics",
29604
+ capScope: "device",
29605
+ addonId: null,
29606
+ access: "view"
29607
+ },
29315
29608
  "pipelineAnalytics.listOpsLog": {
29316
29609
  capName: "pipeline-analytics",
29317
29610
  capScope: "device",
@@ -31310,6 +31603,12 @@ Object.freeze({
31310
31603
  addonId: null,
31311
31604
  access: "create"
31312
31605
  },
31606
+ "terminalSession.updateInstance": {
31607
+ capName: "terminal-session",
31608
+ capScope: "system",
31609
+ addonId: null,
31610
+ access: "create"
31611
+ },
31313
31612
  "terminalSession.writeInput": {
31314
31613
  capName: "terminal-session",
31315
31614
  capScope: "system",
@@ -32725,6 +33024,11 @@ Object.freeze({
32725
33024
  form: "single",
32726
33025
  optional: false
32727
33026
  }],
33027
+ "pipelineAnalytics.getGroup": [{
33028
+ name: "deviceId",
33029
+ form: "single",
33030
+ optional: false
33031
+ }],
32728
33032
  "pipelineAnalytics.getKeyEvents": [{
32729
33033
  name: "deviceId",
32730
33034
  form: "single",
@@ -32780,6 +33084,11 @@ Object.freeze({
32780
33084
  form: "array",
32781
33085
  optional: false
32782
33086
  }],
33087
+ "pipelineAnalytics.listGroups": [{
33088
+ name: "deviceIds",
33089
+ form: "array",
33090
+ optional: false
33091
+ }],
32783
33092
  "pipelineAnalytics.listOpsLog": [{
32784
33093
  name: "deviceId",
32785
33094
  form: "single",
@@ -33797,6 +34106,35 @@ Object.freeze(Object.fromEntries([{
33797
34106
  }]
33798
34107
  }].map((s) => [s.stepId, s.defaultModelId])));
33799
34108
  string().min(1);
34109
+ var CLUSTER_STEP_SETTING_FIELDS = [{
34110
+ stepId: "face-embedding",
34111
+ key: "minLandmarkFaceSize",
34112
+ label: "Min face size for recognition (detection px)",
34113
+ 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.",
34114
+ type: "slider",
34115
+ min: 0,
34116
+ max: 64,
34117
+ step: 2,
34118
+ default: 24
34119
+ }];
34120
+ function clusterStepSettingKey(stepId, fieldKey) {
34121
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
34122
+ }
34123
+ var ClusterSettingNumberSchema = number().finite();
34124
+ function readClusterStepSettings(config) {
34125
+ const out = {};
34126
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
34127
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
34128
+ const value = parsed.success ? parsed.data : field.default;
34129
+ const existing = out[field.stepId] ?? {};
34130
+ out[field.stepId] = {
34131
+ ...existing,
34132
+ [field.key]: value
34133
+ };
34134
+ }
34135
+ return out;
34136
+ }
34137
+ readClusterStepSettings({});
33800
34138
  object({
33801
34139
  /**
33802
34140
  * Fraction of the box's own size added on EACH side before cutting.