camstack 1.2.38 → 1.2.39

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.
@@ -23631,9 +23631,9 @@ var require_zod = __commonJS({
23631
23631
  }
23632
23632
  });
23633
23633
 
23634
- // ../system/dist/dist-iAwSA2_f.js
23635
- var require_dist_iAwSA2_f = __commonJS({
23636
- "../system/dist/dist-iAwSA2_f.js"(exports) {
23634
+ // ../system/dist/dist-C2_1HCpW.js
23635
+ var require_dist_C2_1HCpW = __commonJS({
23636
+ "../system/dist/dist-C2_1HCpW.js"(exports) {
23637
23637
  "use strict";
23638
23638
  var zod = require_zod();
23639
23639
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -26256,6 +26256,15 @@ var require_dist_iAwSA2_f = __commonJS({
26256
26256
  description: zod.z.string().optional(),
26257
26257
  icon: zod.z.string().optional()
26258
26258
  });
26259
+ var ClassMapDefinitionSchema = zod.z.object({
26260
+ mapping: zod.z.record(zod.z.string(), zod.z.enum([
26261
+ "person",
26262
+ "vehicle",
26263
+ "animal",
26264
+ "package"
26265
+ ])),
26266
+ preserveOriginal: zod.z.boolean()
26267
+ });
26259
26268
  var MODEL_FORMATS = [
26260
26269
  "onnx",
26261
26270
  "coreml",
@@ -26404,7 +26413,13 @@ var require_dist_iAwSA2_f = __commonJS({
26404
26413
  * `id` stays the source of truth for resolution/download/persistence; grouping
26405
26414
  * is a presentation overlay resolved back to an `id`.
26406
26415
  */
26407
- group: ModelVariantGroupSchema.optional()
26416
+ group: ModelVariantGroupSchema.optional(),
26417
+ /**
26418
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
26419
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
26420
+ * labels already ARE the CamStack macros (Scrypted identity map).
26421
+ */
26422
+ classMap: ClassMapDefinitionSchema.optional()
26408
26423
  });
26409
26424
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
26410
26425
  format: zod.z.literal("openvino"),
@@ -26433,7 +26448,8 @@ var require_dist_iAwSA2_f = __commonJS({
26433
26448
  "ocr",
26434
26449
  "segmentation"
26435
26450
  ]),
26436
- faceAlignment: zod.z.boolean().optional()
26451
+ faceAlignment: zod.z.boolean().optional(),
26452
+ classMap: ClassMapDefinitionSchema.optional()
26437
26453
  });
26438
26454
  var ConvertArtifactSchema = zod.z.object({
26439
26455
  format: zod.z.enum(MODEL_FORMATS),
@@ -35797,6 +35813,33 @@ var require_dist_iAwSA2_f = __commonJS({
35797
35813
  h: zod.z.number()
35798
35814
  })
35799
35815
  });
35816
+ zod.z.object({
35817
+ crop: zod.z.object({
35818
+ left: zod.z.number(),
35819
+ top: zod.z.number(),
35820
+ width: zod.z.number().positive(),
35821
+ height: zod.z.number().positive()
35822
+ }).optional(),
35823
+ content: zod.z.object({
35824
+ width: zod.z.number().int().positive(),
35825
+ height: zod.z.number().int().positive()
35826
+ }),
35827
+ fit: zod.z.enum(["stretch", "contain"]),
35828
+ format: zod.z.enum([
35829
+ "rgb",
35830
+ "gray",
35831
+ "jpeg"
35832
+ ])
35833
+ });
35834
+ var FrameRefSchema = zod.z.object({
35835
+ registryId: zod.z.string().min(1),
35836
+ id: zod.z.string().min(1),
35837
+ width: zod.z.number().int().positive(),
35838
+ height: zod.z.number().int().positive(),
35839
+ format: zod.z.enum(["rgb", "gray"]),
35840
+ timestamp: zod.z.number(),
35841
+ capturedAt: zod.z.number().optional()
35842
+ });
35800
35843
  var ModelFormatSchema$1 = zod.z.enum([
35801
35844
  "onnx",
35802
35845
  "coreml",
@@ -36096,7 +36139,7 @@ var require_dist_iAwSA2_f = __commonJS({
36096
36139
  * legacy call shape used by existing benchmark code; once all
36097
36140
  * callers pass it explicitly we make it required.
36098
36141
  *
36099
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
36142
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
36100
36143
  * `referenceImage` must be provided:
36101
36144
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
36102
36145
  * Carries the raw buffer, dimensions, and format; the executor
@@ -36118,6 +36161,12 @@ var require_dist_iAwSA2_f = __commonJS({
36118
36161
  steps: zod.z.array(PipelineStepInputSchema).min(1),
36119
36162
  frame: FrameInputSchema.optional(),
36120
36163
  /**
36164
+ * Process-local lazy frame. Valid only when caller and provider resolve
36165
+ * in the same execution-group process; split/cross-node callers use
36166
+ * `frame`/`image` inline compatibility instead.
36167
+ */
36168
+ frameRef: FrameRefSchema.optional(),
36169
+ /**
36121
36170
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
36122
36171
  * the decoded pixels live in. One more member of the one-of
36123
36172
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -36420,7 +36469,10 @@ var require_dist_iAwSA2_f = __commonJS({
36420
36469
  * Which source served this crop, so a quality-sensitive consumer (the native
36421
36470
  * `keyFrame`) can reject a degraded fallback:
36422
36471
  * - `native` — cut from the decode worker's retained NATIVE surface (the
36423
- * quality path).
36472
+ * quality path). A subject-tile serve is also native-resolution and stays
36473
+ * `native` here: the public enum cannot name `tile` without a breaking cap
36474
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
36475
+ * internal crop result (`nativeHits` vs `tileHits`).
36424
36476
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
36425
36477
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
36426
36478
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -36780,12 +36832,41 @@ var require_dist_iAwSA2_f = __commonJS({
36780
36832
  cpuCores: zod.z.number().optional()
36781
36833
  })
36782
36834
  });
36835
+ var FrameLazyCountersSchema = zod.z.object({
36836
+ framesDecoded: zod.z.number(),
36837
+ framesAdmitted: zod.z.number(),
36838
+ framesDroppedPixelFree: zod.z.number(),
36839
+ viewsMaterialized: zod.z.number(),
36840
+ viewsSkipped: zod.z.number(),
36841
+ workerToRunnerBytes: zod.z.number(),
36842
+ runnerToPoolRawBytes: zod.z.number(),
36843
+ runnerToPoolJpegBytes: zod.z.number(),
36844
+ onDemandFullFrameRequests: zod.z.number(),
36845
+ onDemandCropRequests: zod.z.number(),
36846
+ nativeHits: zod.z.number(),
36847
+ nativeMisses: zod.z.number(),
36848
+ tileHits: zod.z.number(),
36849
+ tileMisses: zod.z.number(),
36850
+ fallbackHits: zod.z.number(),
36851
+ fallbackMisses: zod.z.number(),
36852
+ retainedWritesAvoided: zod.z.number(),
36853
+ residentRefs: zod.z.number(),
36854
+ residentBytes: zod.z.number(),
36855
+ releases: zod.z.number(),
36856
+ evictions: zod.z.number(),
36857
+ staleMisses: zod.z.number()
36858
+ });
36859
+ var FrameLazyMetricsSchema = zod.z.object({
36860
+ node: FrameLazyCountersSchema,
36861
+ cameras: zod.z.array(FrameLazyCountersSchema.extend({ deviceId: zod.z.number() }))
36862
+ });
36783
36863
  var RunnerLocalMetricsSchema = zod.z.object({
36784
36864
  nodeId: zod.z.string(),
36785
36865
  activeCameras: zod.z.number(),
36786
36866
  throttledCameras: zod.z.number(),
36787
36867
  avgInferenceTimeMs: zod.z.number(),
36788
- queueDepth: zod.z.number()
36868
+ queueDepth: zod.z.number(),
36869
+ frameLazy: FrameLazyMetricsSchema.optional()
36789
36870
  });
36790
36871
  var pipelineRunnerCapability = {
36791
36872
  name: "pipeline-runner",
@@ -38570,6 +38651,8 @@ var require_dist_iAwSA2_f = __commonJS({
38570
38651
  endDownload: method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
38571
38652
  }
38572
38653
  };
38654
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
38655
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
38573
38656
  var TerminalSessionInfoSchema = zod.z.object({
38574
38657
  /** Opaque session id minted by the provider on `openSession`. */
38575
38658
  sessionId: zod.z.string(),
@@ -38585,7 +38668,14 @@ var require_dist_iAwSA2_f = __commonJS({
38585
38668
  var TerminalProfileInfoSchema = zod.z.object({
38586
38669
  profileId: zod.z.string(),
38587
38670
  label: zod.z.string(),
38588
- description: zod.z.string().optional()
38671
+ description: zod.z.string().optional(),
38672
+ /** Spawn defaults the instance form copies on create. */
38673
+ executable: zod.z.string().optional(),
38674
+ args: zod.z.array(zod.z.string()).readonly().optional(),
38675
+ cwd: zod.z.string().optional(),
38676
+ environment: zod.z.array(zod.z.string()).readonly().optional(),
38677
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
38678
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
38589
38679
  });
38590
38680
  var TerminalInstanceInfoSchema = zod.z.object({
38591
38681
  instanceId: zod.z.string(),
@@ -38594,7 +38684,12 @@ var require_dist_iAwSA2_f = __commonJS({
38594
38684
  profileId: zod.z.string(),
38595
38685
  profileLabel: zod.z.string(),
38596
38686
  name: zod.z.string(),
38597
- enabled: zod.z.boolean()
38687
+ enabled: zod.z.boolean(),
38688
+ executable: zod.z.string(),
38689
+ args: zod.z.array(zod.z.string()).readonly(),
38690
+ cwd: zod.z.string(),
38691
+ environment: zod.z.array(zod.z.string()).readonly(),
38692
+ profileSettings: ProfileSettingsBagSchema
38598
38693
  });
38599
38694
  var TerminalLegacyCameraSchema = zod.z.object({
38600
38695
  stableId: zod.z.string(),
@@ -38633,7 +38728,24 @@ var require_dist_iAwSA2_f = __commonJS({
38633
38728
  createInstance: method(zod.z.object({
38634
38729
  targetNodeId: zod.z.string().min(1),
38635
38730
  profileId: zod.z.string().min(1),
38636
- name: zod.z.string().trim().min(1).max(160).optional()
38731
+ name: zod.z.string().trim().min(1).max(160).optional(),
38732
+ executable: zod.z.string().max(1024).optional(),
38733
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38734
+ cwd: zod.z.string().max(1024).optional(),
38735
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
38736
+ profileSettings: ProfileSettingsBagSchema.optional()
38737
+ }), TerminalInstanceInfoSchema, {
38738
+ kind: "mutation",
38739
+ auth: "admin"
38740
+ }),
38741
+ updateInstance: method(zod.z.object({
38742
+ instanceId: zod.z.string().min(1),
38743
+ name: zod.z.string().trim().min(1).max(160).optional(),
38744
+ executable: zod.z.string().max(1024).optional(),
38745
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38746
+ cwd: zod.z.string().max(1024).optional(),
38747
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
38748
+ profileSettings: ProfileSettingsBagSchema.optional()
38637
38749
  }), TerminalInstanceInfoSchema, {
38638
38750
  kind: "mutation",
38639
38751
  auth: "admin"
@@ -38668,7 +38780,11 @@ var require_dist_iAwSA2_f = __commonJS({
38668
38780
  openSession: method(zod.z.object({
38669
38781
  profileId: zod.z.string(),
38670
38782
  cols: zod.z.number().int().positive(),
38671
- rows: zod.z.number().int().positive()
38783
+ rows: zod.z.number().int().positive(),
38784
+ executable: zod.z.string().max(1024).optional(),
38785
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38786
+ cwd: zod.z.string().max(1024).optional(),
38787
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional()
38672
38788
  }), TerminalSessionInfoSchema, {
38673
38789
  kind: "mutation",
38674
38790
  auth: "admin"
@@ -42391,6 +42507,12 @@ var require_dist_iAwSA2_f = __commonJS({
42391
42507
  /** What the ranking currently resolves to (null when nothing is reachable). */
42392
42508
  resolved: zod.z.string().nullable()
42393
42509
  });
42510
+ var ViewerEndpointsSchema = zod.z.object({
42511
+ /** The operator's explicit race set, or empty for AUTO. */
42512
+ baseUrls: zod.z.array(zod.z.string()).readonly(),
42513
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
42514
+ resolved: zod.z.array(zod.z.string()).readonly()
42515
+ });
42394
42516
  var AllowedAddressesSchema = zod.z.object({
42395
42517
  /**
42396
42518
  * Allowlist of interface addresses operators have explicitly opted
@@ -42400,6 +42522,20 @@ var require_dist_iAwSA2_f = __commonJS({
42400
42522
  */
42401
42523
  addresses: zod.z.array(zod.z.string()).readonly()
42402
42524
  });
42525
+ var TlsStatusSchema = zod.z.object({
42526
+ mode: zod.z.enum([
42527
+ "generated",
42528
+ "uploaded",
42529
+ "disabled"
42530
+ ]),
42531
+ leafFingerprintSha256: zod.z.string().nullable(),
42532
+ caFingerprintSha256: zod.z.string().nullable(),
42533
+ validTo: zod.z.string().nullable(),
42534
+ sans: zod.z.array(zod.z.string()),
42535
+ caCertPem: zod.z.string().nullable(),
42536
+ reissueError: zod.z.string().nullable(),
42537
+ restartRequired: zod.z.boolean()
42538
+ });
42403
42539
  var localNetworkCapability = {
42404
42540
  name: "local-network",
42405
42541
  scope: "system",
@@ -42419,13 +42555,13 @@ var require_dist_iAwSA2_f = __commonJS({
42419
42555
  */
42420
42556
  getPreferred: method(zod.z.void(), PreferredSchema),
42421
42557
  /**
42422
- * Ordered candidate base URLs the SDK should try on connect.
42423
- * Includes LAN IPs (one per non-internal interface), the public
42424
- * tunnel hostname (when active), and loopback as a last-resort
42425
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
42426
- * Honours `getAllowedAddresses()` when set addresses outside
42427
- * the allowlist are dropped (the public tunnel + loopback are
42428
- * always included as escape hatches).
42558
+ * Ordered candidate base URLs (the palette the Network tab shows).
42559
+ * Includes LAN IPv4, stable LAN IPv6, the public tunnel, and mesh when
42560
+ * joined. Loopback is off by default. The SDK races the subset from
42561
+ * `getViewerEndpoints`, not this full list — IPv6 stays here because
42562
+ * WebRTC ICE gathers dual-stack regardless of the HTTP race. Honours
42563
+ * `getAllowedAddresses()` when set addresses outside the allowlist
42564
+ * are dropped (the public tunnel is still included as an escape hatch).
42429
42565
  *
42430
42566
  * **The port is the hub's, not the caller's** (D62 — a function's fact
42431
42567
  * belongs to whoever already owns it). This method used to take a `port`
@@ -42456,10 +42592,11 @@ var require_dist_iAwSA2_f = __commonJS({
42456
42592
  */
42457
42593
  port: zod.z.number().int().min(1).max(65535).optional(),
42458
42594
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
42459
- * candidate. Default `true`. */
42595
+ * candidate. Default `false` — loopback is not a client route. */
42460
42596
  includeLoopback: zod.z.boolean().optional(),
42461
- /** Skip IPv6 entries. Some legacy clients can't parse them.
42462
- * Default `false`. */
42597
+ /** Skip IPv6 entries. Default `false` the palette includes stable
42598
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
42599
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
42463
42600
  ipv4Only: zod.z.boolean().optional(),
42464
42601
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
42465
42602
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -42488,6 +42625,19 @@ var require_dist_iAwSA2_f = __commonJS({
42488
42625
  */
42489
42626
  setNotificationEndpoint: method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
42490
42627
  /**
42628
+ * The endpoints the SDK / viewer races for API access. Empty `baseUrls`
42629
+ * means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
42630
+ * never mesh, never loopback. `resolved` is that set (or the operator's
42631
+ * explicit subset) as it stands right now.
42632
+ */
42633
+ getViewerEndpoints: method(zod.z.void(), ViewerEndpointsSchema),
42634
+ /**
42635
+ * Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
42636
+ * verbatim (not indices) so a temporarily-down tunnel is not silently
42637
+ * dropped from the operator's choice.
42638
+ */
42639
+ setViewerEndpoints: method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
42640
+ /**
42491
42641
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
42492
42642
  * by the admin UI's address selector to seed its checkbox state.
42493
42643
  */
@@ -42505,7 +42655,34 @@ var require_dist_iAwSA2_f = __commonJS({
42505
42655
  * when the operator wants to wipe their manual edits and start
42506
42656
  * over from the auto-detected best matches.
42507
42657
  */
42508
- resetAllowlistToBestMatch: method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" })
42658
+ resetAllowlistToBestMatch: method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" }),
42659
+ /**
42660
+ * Live TLS material for the Network → Local access certificate card.
42661
+ * LAN HTTP / hostname are addon settings (`globalSettingsSchema`), not
42662
+ * a second store — this query is status, not configuration.
42663
+ */
42664
+ getTlsStatus: method(zod.z.void(), TlsStatusSchema),
42665
+ /** Issue a new leaf under the existing local CA. Disabled in uploaded mode. */
42666
+ regenerateCertificate: method(zod.z.object({ reason: zod.z.string().optional() }), TlsStatusSchema, {
42667
+ kind: "mutation",
42668
+ auth: "admin"
42669
+ }),
42670
+ /** Replace the served material with operator-supplied PEMs. */
42671
+ uploadCertificate: method(zod.z.object({
42672
+ certPem: zod.z.string().min(1),
42673
+ keyPem: zod.z.string().min(1),
42674
+ caPem: zod.z.string().optional()
42675
+ }), TlsStatusSchema, {
42676
+ kind: "mutation",
42677
+ auth: "admin"
42678
+ }),
42679
+ /** The local CA PEM, or empty when there is none to download. */
42680
+ downloadCa: method(zod.z.void(), zod.z.object({ pem: zod.z.string() })),
42681
+ /** Drop uploaded material and return to the generated local CA. */
42682
+ revertToGeneratedCertificate: method(zod.z.void(), TlsStatusSchema, {
42683
+ kind: "mutation",
42684
+ auth: "admin"
42685
+ })
42509
42686
  },
42510
42687
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
42511
42688
  mount: { kind: "hub-only" }
@@ -49869,6 +50046,12 @@ var require_dist_iAwSA2_f = __commonJS({
49869
50046
  addonId: null,
49870
50047
  access: "create"
49871
50048
  },
50049
+ "localNetwork.downloadCa": {
50050
+ capName: "local-network",
50051
+ capScope: "system",
50052
+ addonId: null,
50053
+ access: "view"
50054
+ },
49872
50055
  "localNetwork.getAllowedAddresses": {
49873
50056
  capName: "local-network",
49874
50057
  capScope: "system",
@@ -49893,18 +50076,42 @@ var require_dist_iAwSA2_f = __commonJS({
49893
50076
  addonId: null,
49894
50077
  access: "view"
49895
50078
  },
50079
+ "localNetwork.getTlsStatus": {
50080
+ capName: "local-network",
50081
+ capScope: "system",
50082
+ addonId: null,
50083
+ access: "view"
50084
+ },
50085
+ "localNetwork.getViewerEndpoints": {
50086
+ capName: "local-network",
50087
+ capScope: "system",
50088
+ addonId: null,
50089
+ access: "view"
50090
+ },
49896
50091
  "localNetwork.list": {
49897
50092
  capName: "local-network",
49898
50093
  capScope: "system",
49899
50094
  addonId: null,
49900
50095
  access: "view"
49901
50096
  },
50097
+ "localNetwork.regenerateCertificate": {
50098
+ capName: "local-network",
50099
+ capScope: "system",
50100
+ addonId: null,
50101
+ access: "create"
50102
+ },
49902
50103
  "localNetwork.resetAllowlistToBestMatch": {
49903
50104
  capName: "local-network",
49904
50105
  capScope: "system",
49905
50106
  addonId: null,
49906
50107
  access: "delete"
49907
50108
  },
50109
+ "localNetwork.revertToGeneratedCertificate": {
50110
+ capName: "local-network",
50111
+ capScope: "system",
50112
+ addonId: null,
50113
+ access: "create"
50114
+ },
49908
50115
  "localNetwork.setAllowedAddresses": {
49909
50116
  capName: "local-network",
49910
50117
  capScope: "system",
@@ -49917,6 +50124,18 @@ var require_dist_iAwSA2_f = __commonJS({
49917
50124
  addonId: null,
49918
50125
  access: "create"
49919
50126
  },
50127
+ "localNetwork.setViewerEndpoints": {
50128
+ capName: "local-network",
50129
+ capScope: "system",
50130
+ addonId: null,
50131
+ access: "create"
50132
+ },
50133
+ "localNetwork.uploadCertificate": {
50134
+ capName: "local-network",
50135
+ capScope: "system",
50136
+ addonId: null,
50137
+ access: "create"
50138
+ },
49920
50139
  "lockControl.lock": {
49921
50140
  capName: "lock-control",
49922
50141
  capScope: "device",
@@ -52797,6 +53016,12 @@ var require_dist_iAwSA2_f = __commonJS({
52797
53016
  addonId: null,
52798
53017
  access: "create"
52799
53018
  },
53019
+ "terminalSession.updateInstance": {
53020
+ capName: "terminal-session",
53021
+ capScope: "system",
53022
+ addonId: null,
53023
+ access: "create"
53024
+ },
52800
53025
  "terminalSession.writeInput": {
52801
53026
  capName: "terminal-session",
52802
53027
  capScope: "system",
@@ -55425,6 +55650,35 @@ var require_dist_iAwSA2_f = __commonJS({
55425
55650
  }]
55426
55651
  }].map((s) => [s.stepId, s.defaultModelId])));
55427
55652
  zod.z.string().min(1);
55653
+ var CLUSTER_STEP_SETTING_FIELDS = [{
55654
+ stepId: "face-embedding",
55655
+ key: "minLandmarkFaceSize",
55656
+ label: "Min face size for recognition (detection px)",
55657
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node \u2014 the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
55658
+ type: "slider",
55659
+ min: 0,
55660
+ max: 64,
55661
+ step: 2,
55662
+ default: 24
55663
+ }];
55664
+ function clusterStepSettingKey(stepId, fieldKey) {
55665
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
55666
+ }
55667
+ var ClusterSettingNumberSchema = zod.z.number().finite();
55668
+ function readClusterStepSettings(config) {
55669
+ const out = {};
55670
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
55671
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
55672
+ const value = parsed.success ? parsed.data : field.default;
55673
+ const existing = out[field.stepId] ?? {};
55674
+ out[field.stepId] = {
55675
+ ...existing,
55676
+ [field.key]: value
55677
+ };
55678
+ }
55679
+ return out;
55680
+ }
55681
+ readClusterStepSettings({});
55428
55682
  zod.z.object({
55429
55683
  /**
55430
55684
  * Fraction of the box's own size added on EACH side before cutting.
@@ -56256,7 +56510,7 @@ var require_alerts_addon = __commonJS({
56256
56510
  [Symbol.toStringTag]: { value: "Module" }
56257
56511
  });
56258
56512
  require_chunk_Cek0wNdY();
56259
- var require_dist10 = require_dist_iAwSA2_f();
56513
+ var require_dist10 = require_dist_C2_1HCpW();
56260
56514
  function selectExpired(alerts, cutoffMs) {
56261
56515
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
56262
56516
  }
@@ -57075,7 +57329,7 @@ var require_console_logging = __commonJS({
57075
57329
  [Symbol.toStringTag]: { value: "Module" }
57076
57330
  });
57077
57331
  require_chunk_Cek0wNdY();
57078
- var require_dist10 = require_dist_iAwSA2_f();
57332
+ var require_dist10 = require_dist_C2_1HCpW();
57079
57333
  var require_formatter = require_formatter_DqAKDlvN();
57080
57334
  var LEVEL_RANK = {
57081
57335
  debug: 0,
@@ -57169,7 +57423,7 @@ var require_core_blocks_addon = __commonJS({
57169
57423
  "use strict";
57170
57424
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
57171
57425
  var require_chunk = require_chunk_Cek0wNdY();
57172
- var require_dist10 = require_dist_iAwSA2_f();
57426
+ var require_dist10 = require_dist_C2_1HCpW();
57173
57427
  var node_crypto = __require("crypto");
57174
57428
  var node_fs_promises = __require("fs/promises");
57175
57429
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -58066,11 +58320,11 @@ var require_core_blocks = __commonJS({
58066
58320
  }
58067
58321
  });
58068
58322
 
58069
- // ../system/dist/retired-settings-keys-OfhqQio4.js
58070
- var require_retired_settings_keys_OfhqQio4 = __commonJS({
58071
- "../system/dist/retired-settings-keys-OfhqQio4.js"(exports) {
58323
+ // ../system/dist/retired-settings-keys-DHRXLMPn.js
58324
+ var require_retired_settings_keys_DHRXLMPn = __commonJS({
58325
+ "../system/dist/retired-settings-keys-DHRXLMPn.js"(exports) {
58072
58326
  "use strict";
58073
- var require_dist10 = require_dist_iAwSA2_f();
58327
+ var require_dist10 = require_dist_C2_1HCpW();
58074
58328
  function settingsStoreIsAuthoritativeHere(env) {
58075
58329
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
58076
58330
  return raw === "" || raw === "hub";
@@ -60113,8 +60367,8 @@ var require_device_manager_addon = __commonJS({
60113
60367
  [Symbol.toStringTag]: { value: "Module" }
60114
60368
  });
60115
60369
  require_chunk_Cek0wNdY();
60116
- var require_dist10 = require_dist_iAwSA2_f();
60117
- var require_retired_settings_keys = require_retired_settings_keys_OfhqQio4();
60370
+ var require_dist10 = require_dist_C2_1HCpW();
60371
+ var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
60118
60372
  var node_crypto = __require("crypto");
60119
60373
  var _camstack_types_node = require_node();
60120
60374
  var JOB_HISTORY = 20;
@@ -64441,7 +64695,7 @@ var require_hub_forwarder = __commonJS({
64441
64695
  [Symbol.toStringTag]: { value: "Module" }
64442
64696
  });
64443
64697
  require_chunk_Cek0wNdY();
64444
- var require_dist10 = require_dist_iAwSA2_f();
64698
+ var require_dist10 = require_dist_C2_1HCpW();
64445
64699
  var require_formatter = require_formatter_DqAKDlvN();
64446
64700
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
64447
64701
  var HubForwarderDestination = class {
@@ -64578,7 +64832,7 @@ var require_liveness_monitor_addon = __commonJS({
64578
64832
  "use strict";
64579
64833
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
64580
64834
  require_chunk_Cek0wNdY();
64581
- var require_dist10 = require_dist_iAwSA2_f();
64835
+ var require_dist10 = require_dist_C2_1HCpW();
64582
64836
  var NO_DEVICES = "liveness:no-devices";
64583
64837
  var ALL_OFFLINE = "liveness:all-devices-offline";
64584
64838
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -64768,7 +65022,7 @@ var require_local_auth_addon = __commonJS({
64768
65022
  [Symbol.toStringTag]: { value: "Module" }
64769
65023
  });
64770
65024
  var require_chunk = require_chunk_Cek0wNdY();
64771
- var require_dist10 = require_dist_iAwSA2_f();
65025
+ var require_dist10 = require_dist_C2_1HCpW();
64772
65026
  var node_crypto = __require("crypto");
64773
65027
  node_crypto = require_chunk.__toESM(node_crypto);
64774
65028
  var crypto$1 = __require("crypto");
@@ -72452,7 +72706,7 @@ var require_loki_logging = __commonJS({
72452
72706
  [Symbol.toStringTag]: { value: "Module" }
72453
72707
  });
72454
72708
  require_chunk_Cek0wNdY();
72455
- var require_dist10 = require_dist_iAwSA2_f();
72709
+ var require_dist10 = require_dist_C2_1HCpW();
72456
72710
  function sanitizeLabelName(raw) {
72457
72711
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
72458
72712
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -73017,7 +73271,7 @@ var require_native_metrics_addon = __commonJS({
73017
73271
  [Symbol.toStringTag]: { value: "Module" }
73018
73272
  });
73019
73273
  var require_chunk = require_chunk_Cek0wNdY();
73020
- var require_dist10 = require_dist_iAwSA2_f();
73274
+ var require_dist10 = require_dist_C2_1HCpW();
73021
73275
  var node_child_process = __require("child_process");
73022
73276
  var node_util = __require("util");
73023
73277
  var node_os = __require("os");
@@ -73959,7 +74213,7 @@ var require_filesystem_storage_addon = __commonJS({
73959
74213
  [Symbol.toStringTag]: { value: "Module" }
73960
74214
  });
73961
74215
  var require_chunk = require_chunk_Cek0wNdY();
73962
- var require_dist10 = require_dist_iAwSA2_f();
74216
+ var require_dist10 = require_dist_C2_1HCpW();
73963
74217
  var node_crypto = __require("crypto");
73964
74218
  var node_fs_promises = __require("fs/promises");
73965
74219
  var node_path = __require("path");
@@ -75075,8 +75329,8 @@ var require_sqlite_settings_addon = __commonJS({
75075
75329
  [Symbol.toStringTag]: { value: "Module" }
75076
75330
  });
75077
75331
  var require_chunk = require_chunk_Cek0wNdY();
75078
- var require_dist10 = require_dist_iAwSA2_f();
75079
- var require_retired_settings_keys = require_retired_settings_keys_OfhqQio4();
75332
+ var require_dist10 = require_dist_C2_1HCpW();
75333
+ var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
75080
75334
  var node_crypto = __require("crypto");
75081
75335
  var node_fs = __require("fs");
75082
75336
  var node_module = __require("module");
@@ -76620,7 +76874,7 @@ var require_storage_orchestrator_addon = __commonJS({
76620
76874
  [Symbol.toStringTag]: { value: "Module" }
76621
76875
  });
76622
76876
  var require_chunk = require_chunk_Cek0wNdY();
76623
- var require_dist10 = require_dist_iAwSA2_f();
76877
+ var require_dist10 = require_dist_C2_1HCpW();
76624
76878
  var node_crypto = __require("crypto");
76625
76879
  var node_fs_promises = __require("fs/promises");
76626
76880
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -78499,7 +78753,7 @@ var require_system_config_addon = __commonJS({
78499
78753
  [Symbol.toStringTag]: { value: "Module" }
78500
78754
  });
78501
78755
  require_chunk_Cek0wNdY();
78502
- var require_dist10 = require_dist_iAwSA2_f();
78756
+ var require_dist10 = require_dist_C2_1HCpW();
78503
78757
  var SECTION_TITLES = {
78504
78758
  server: "Server",
78505
78759
  auth: "Authentication"
@@ -96560,7 +96814,7 @@ var require_winston_logging = __commonJS({
96560
96814
  [Symbol.toStringTag]: { value: "Module" }
96561
96815
  });
96562
96816
  var require_chunk = require_chunk_Cek0wNdY();
96563
- var require_dist10 = require_dist_iAwSA2_f();
96817
+ var require_dist10 = require_dist_C2_1HCpW();
96564
96818
  var require_formatter = require_formatter_DqAKDlvN();
96565
96819
  var node_path = __require("path");
96566
96820
  node_path = require_chunk.__toESM(node_path);
@@ -96697,9 +96951,9 @@ var require_winston_logging = __commonJS({
96697
96951
  }
96698
96952
  });
96699
96953
 
96700
- // ../system/dist/file-data-plane-DUHPHa-Y.js
96701
- var require_file_data_plane_DUHPHa_Y = __commonJS({
96702
- "../system/dist/file-data-plane-DUHPHa-Y.js"(exports) {
96954
+ // ../system/dist/file-data-plane-DO8KbxCe.js
96955
+ var require_file_data_plane_DO8KbxCe = __commonJS({
96956
+ "../system/dist/file-data-plane-DO8KbxCe.js"(exports) {
96703
96957
  "use strict";
96704
96958
  var require_chunk = require_chunk_Cek0wNdY();
96705
96959
  var node_crypto = __require("crypto");
@@ -96732,15 +96986,56 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96732
96986
  if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
96733
96987
  return headers;
96734
96988
  }
96735
- async function downloadFile(url, destPath, onProgress) {
96989
+ var DEFAULT_MAX_REDIRECTS = 5;
96990
+ function normalizeDownloadOptions(third) {
96991
+ if (typeof third === "function") return { onProgress: third };
96992
+ return third ?? {};
96993
+ }
96994
+ function isRedirectStatus(status) {
96995
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
96996
+ }
96997
+ function resolveRedirectUrl(current, location) {
96998
+ return new URL(location, current);
96999
+ }
97000
+ async function downloadFile(url, destPath, onProgressOrOptions) {
96736
97001
  if (node_fs.existsSync(destPath)) return destPath;
97002
+ const opts = normalizeDownloadOptions(onProgressOrOptions);
97003
+ const fetchImpl = opts.fetchImpl ?? fetch;
97004
+ const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
96737
97005
  node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
96738
97006
  const tmpPath = destPath + ".downloading";
96739
97007
  try {
96740
- const response = await fetch(url, {
96741
- redirect: "follow",
96742
- headers: buildHeaders(url)
96743
- });
97008
+ let current = url;
97009
+ const seen = /* @__PURE__ */ new Set();
97010
+ let response;
97011
+ const manual = opts.redirectPolicy !== void 0;
97012
+ for (let hop = 0; hop <= maxRedirects; hop++) {
97013
+ const parsed = new URL(current);
97014
+ if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
97015
+ if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
97016
+ seen.add(parsed.href);
97017
+ const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
97018
+ const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
97019
+ try {
97020
+ response = await fetchImpl(current, {
97021
+ redirect: manual ? "manual" : "follow",
97022
+ headers: buildHeaders(current),
97023
+ ...controller ? { signal: controller.signal } : {}
97024
+ });
97025
+ } finally {
97026
+ if (timer) clearTimeout(timer);
97027
+ }
97028
+ if (manual && isRedirectStatus(response.status)) {
97029
+ const location = response.headers.get("location");
97030
+ if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
97031
+ if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
97032
+ current = resolveRedirectUrl(current, location).href;
97033
+ continue;
97034
+ }
97035
+ break;
97036
+ }
97037
+ if (!response) throw new Error(`No response downloading ${url}`);
97038
+ if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
96744
97039
  if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
96745
97040
  if (!response.body) throw new Error(`No response body from ${url}`);
96746
97041
  const total = parseInt(response.headers.get("content-length") ?? "0", 10);
@@ -96751,9 +97046,10 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96751
97046
  for (; ; ) {
96752
97047
  const { done, value } = await reader.read();
96753
97048
  if (done || !value) break;
96754
- fileStream.write(value);
96755
97049
  downloaded += value.length;
96756
- onProgress?.(downloaded, total);
97050
+ if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
97051
+ fileStream.write(value);
97052
+ opts.onProgress?.(downloaded, total);
96757
97053
  }
96758
97054
  } finally {
96759
97055
  fileStream.end();
@@ -115038,6 +115334,752 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
115038
115334
  }
115039
115335
  });
115040
115336
 
115337
+ // ../system/dist/lan-http-bind-DmgpFP6_.js
115338
+ var require_lan_http_bind_DmgpFP6 = __commonJS({
115339
+ "../system/dist/lan-http-bind-DmgpFP6_.js"(exports) {
115340
+ "use strict";
115341
+ var require_chunk = require_chunk_Cek0wNdY();
115342
+ var node_crypto = __require("crypto");
115343
+ var node_fs_promises = __require("fs/promises");
115344
+ var node_path = __require("path");
115345
+ var node_child_process = __require("child_process");
115346
+ var node_util = __require("util");
115347
+ var node_os = __require("os");
115348
+ node_os = require_chunk.__toESM(node_os);
115349
+ var node_fs = __require("fs");
115350
+ var node_http = __require("http");
115351
+ var node_net = __require("net");
115352
+ var SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
115353
+ var MAX_LEAF_VALIDITY_DAYS = 397;
115354
+ var LEAF_RENEWAL_WINDOW_DAYS = 30;
115355
+ var CA_VALIDITY_DAYS = 3650;
115356
+ var MS_PER_DAY = 864e5;
115357
+ var REASONS_REQUIRING_NEW_CA = [
115358
+ "missing",
115359
+ "unreadable",
115360
+ "no-local-ca",
115361
+ "ca-expiring"
115362
+ ];
115363
+ function reasonRequiresNewCa(reason) {
115364
+ return REASONS_REQUIRING_NEW_CA.includes(reason);
115365
+ }
115366
+ function parse4(pem) {
115367
+ try {
115368
+ return new node_crypto.X509Certificate(pem);
115369
+ } catch {
115370
+ return null;
115371
+ }
115372
+ }
115373
+ function daysBetween(from, to) {
115374
+ return (to.getTime() - from.getTime()) / MS_PER_DAY;
115375
+ }
115376
+ function hasServerAuthEku(leaf) {
115377
+ const eku = leaf.keyUsage;
115378
+ return eku !== void 0 && eku.length === 1 && eku[0] === "1.3.6.1.5.5.7.3.1";
115379
+ }
115380
+ function keyMatches(leaf, keyPem) {
115381
+ try {
115382
+ return leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem));
115383
+ } catch {
115384
+ return false;
115385
+ }
115386
+ }
115387
+ function coversIdentity(leaf, identity) {
115388
+ for (const name of identity.requiredDnsNames) if (leaf.checkHost(name) === void 0) return false;
115389
+ for (const ip of identity.requiredIpAddresses) if (leaf.checkIP(ip) === void 0) return false;
115390
+ return true;
115391
+ }
115392
+ function evaluateExistingCert(input) {
115393
+ const leaf = parse4(input.chainPem);
115394
+ const ca = parse4(input.caPem);
115395
+ if (leaf === null || ca === null) return "unreadable";
115396
+ if (daysBetween(input.now, new Date(ca.validTo)) < 427) return "ca-expiring";
115397
+ if (!keyMatches(leaf, input.keyPem)) return "key-mismatch";
115398
+ if (daysBetween(input.now, new Date(leaf.validTo)) < 30) return "expiring";
115399
+ if (!hasServerAuthEku(leaf)) return "missing-server-auth-eku";
115400
+ if (leaf.ca || !leaf.checkIssued(ca) || !leaf.verify(ca.publicKey)) return "not-issued-by-local-ca";
115401
+ if (daysBetween(new Date(leaf.validFrom), new Date(leaf.validTo)) > 398) return "validity-too-long";
115402
+ if (!coversIdentity(leaf, input.identity)) return "san-coverage-gap";
115403
+ return null;
115404
+ }
115405
+ var VOLATILE_INTERFACE_PREFIXES = [
115406
+ "docker",
115407
+ "br-",
115408
+ "veth",
115409
+ "virbr",
115410
+ "cni",
115411
+ "flannel",
115412
+ "tun",
115413
+ "utun",
115414
+ "tap",
115415
+ "wg",
115416
+ "zt",
115417
+ "tailscale",
115418
+ "ppp",
115419
+ "awdl",
115420
+ "llw"
115421
+ ];
115422
+ var DNS_NAME_PATTERN = /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/;
115423
+ function isIpv4(value) {
115424
+ return (0, node_net.isIP)(value) === 4;
115425
+ }
115426
+ function isIpv6(value) {
115427
+ return (0, node_net.isIP)(value) === 6;
115428
+ }
115429
+ function isLinkLocal(value) {
115430
+ if (isIpv4(value)) return value.startsWith("169.254.");
115431
+ if (!isIpv6(value)) return false;
115432
+ const firstGroup = value.split(":")[0] ?? "";
115433
+ if (firstGroup === "") return false;
115434
+ const parsed = Number.parseInt(firstGroup, 16);
115435
+ return Number.isFinite(parsed) && (parsed & 65472) === 65152;
115436
+ }
115437
+ function isUniqueLocalIpv6(value) {
115438
+ if (!isIpv6(value)) return false;
115439
+ const firstGroup = value.split(":")[0] ?? "";
115440
+ const parsed = Number.parseInt(firstGroup, 16);
115441
+ return Number.isFinite(parsed) && (parsed & 65024) === 64512;
115442
+ }
115443
+ function isVolatileInterface(name) {
115444
+ const lower = name.toLowerCase();
115445
+ return VOLATILE_INTERFACE_PREFIXES.some((prefix) => lower.startsWith(prefix));
115446
+ }
115447
+ function isStableGateAddress(address) {
115448
+ if (isLinkLocal(address)) return false;
115449
+ if (isIpv4(address)) return true;
115450
+ return isUniqueLocalIpv6(address);
115451
+ }
115452
+ function addSan(dns, ips, value) {
115453
+ const trimmed = value.trim();
115454
+ if (trimmed === "") return;
115455
+ if ((0, node_net.isIP)(trimmed) !== 0) {
115456
+ if (!isLinkLocal(trimmed)) ips.add(trimmed);
115457
+ return;
115458
+ }
115459
+ if (DNS_NAME_PATTERN.test(trimmed)) dns.add(trimmed);
115460
+ }
115461
+ function collectCertIdentity(options) {
115462
+ const dnsNames = /* @__PURE__ */ new Set();
115463
+ const ipAddresses = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
115464
+ const requiredDnsNames = /* @__PURE__ */ new Set();
115465
+ const requiredIpAddresses = /* @__PURE__ */ new Set(["127.0.0.1"]);
115466
+ for (const name of [
115467
+ "localhost",
115468
+ options.commonName,
115469
+ node_os.hostname()
115470
+ ]) {
115471
+ addSan(dnsNames, ipAddresses, name);
115472
+ addSan(requiredDnsNames, requiredIpAddresses, name);
115473
+ }
115474
+ for (const [ifaceName, addrs] of Object.entries(node_os.networkInterfaces())) for (const addr of addrs ?? []) {
115475
+ if (addr.internal) continue;
115476
+ if (isLinkLocal(addr.address)) continue;
115477
+ ipAddresses.add(addr.address);
115478
+ if (isVolatileInterface(ifaceName)) continue;
115479
+ if (isStableGateAddress(addr.address)) requiredIpAddresses.add(addr.address);
115480
+ }
115481
+ for (const san of options.extraSans) {
115482
+ addSan(dnsNames, ipAddresses, san);
115483
+ addSan(requiredDnsNames, requiredIpAddresses, san);
115484
+ }
115485
+ return {
115486
+ dnsNames: [...dnsNames],
115487
+ ipAddresses: [...ipAddresses],
115488
+ requiredDnsNames: [...requiredDnsNames],
115489
+ requiredIpAddresses: [...requiredIpAddresses]
115490
+ };
115491
+ }
115492
+ var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
115493
+ var CA_COMMON_NAME = "CamStack Local CA";
115494
+ function sanValue(identity) {
115495
+ const parts = [];
115496
+ for (const dns of identity.dnsNames) parts.push(`DNS:${dns}`);
115497
+ for (const ip of identity.ipAddresses) if ((0, node_net.isIP)(ip) !== 0) parts.push(`IP:${ip}`);
115498
+ return parts.join(",");
115499
+ }
115500
+ async function generateCa(tmpDir) {
115501
+ const caCertPath = (0, node_path.join)(tmpDir, "ca.crt");
115502
+ const caKeyPath = (0, node_path.join)(tmpDir, "ca.key");
115503
+ await execFileAsync("openssl", [
115504
+ "req",
115505
+ "-x509",
115506
+ "-newkey",
115507
+ "rsa:2048",
115508
+ "-nodes",
115509
+ "-sha256",
115510
+ "-days",
115511
+ String(CA_VALIDITY_DAYS),
115512
+ "-keyout",
115513
+ caKeyPath,
115514
+ "-out",
115515
+ caCertPath,
115516
+ "-subj",
115517
+ `/CN=${CA_COMMON_NAME}`,
115518
+ "-addext",
115519
+ "basicConstraints=critical,CA:TRUE,pathlen:0",
115520
+ "-addext",
115521
+ "keyUsage=critical,keyCertSign,cRLSign",
115522
+ "-addext",
115523
+ "subjectKeyIdentifier=hash"
115524
+ ]);
115525
+ await (0, node_fs_promises.chmod)(caKeyPath, 384);
115526
+ return {
115527
+ caCertPath,
115528
+ caKeyPath
115529
+ };
115530
+ }
115531
+ async function issueLeaf(tmpDir, ca, identity, commonName, validDays) {
115532
+ const keyPath = (0, node_path.join)(tmpDir, "leaf.key");
115533
+ const csrPath = (0, node_path.join)(tmpDir, "leaf.csr");
115534
+ const certPath = (0, node_path.join)(tmpDir, "leaf.crt");
115535
+ const extPath = (0, node_path.join)(tmpDir, "leaf.ext");
115536
+ await (0, node_fs_promises.writeFile)(extPath, [
115537
+ "basicConstraints=critical,CA:FALSE",
115538
+ "keyUsage=critical,digitalSignature,keyEncipherment",
115539
+ "extendedKeyUsage=serverAuth",
115540
+ "subjectKeyIdentifier=hash",
115541
+ "authorityKeyIdentifier=keyid,issuer",
115542
+ `subjectAltName=${sanValue(identity)}`,
115543
+ ""
115544
+ ].join("\n"), "utf-8");
115545
+ await execFileAsync("openssl", [
115546
+ "req",
115547
+ "-new",
115548
+ "-newkey",
115549
+ "rsa:2048",
115550
+ "-nodes",
115551
+ "-sha256",
115552
+ "-keyout",
115553
+ keyPath,
115554
+ "-out",
115555
+ csrPath,
115556
+ "-subj",
115557
+ `/CN=${commonName}`
115558
+ ]);
115559
+ await execFileAsync("openssl", [
115560
+ "x509",
115561
+ "-req",
115562
+ "-in",
115563
+ csrPath,
115564
+ "-CA",
115565
+ ca.caCertPath,
115566
+ "-CAkey",
115567
+ ca.caKeyPath,
115568
+ "-set_serial",
115569
+ `0x00${(0, node_crypto.randomBytes)(16).toString("hex")}`,
115570
+ "-days",
115571
+ String(validDays),
115572
+ "-sha256",
115573
+ "-extfile",
115574
+ extPath,
115575
+ "-out",
115576
+ certPath
115577
+ ]);
115578
+ await (0, node_fs_promises.chmod)(keyPath, 384);
115579
+ await (0, node_fs_promises.rm)(csrPath, { force: true });
115580
+ await (0, node_fs_promises.rm)(extPath, { force: true });
115581
+ return {
115582
+ certPath,
115583
+ keyPath
115584
+ };
115585
+ }
115586
+ var DEFAULT_COMMON_NAME = "camstack.local";
115587
+ async function ensureTlsCert(dataDir, options) {
115588
+ const tlsDir2 = (0, node_path.join)(dataDir, "tls");
115589
+ const paths = {
115590
+ certPath: (0, node_path.join)(tlsDir2, "camstack.crt"),
115591
+ keyPath: (0, node_path.join)(tlsDir2, "camstack.key"),
115592
+ caCertPath: (0, node_path.join)(tlsDir2, "camstack-ca.crt"),
115593
+ caKeyPath: (0, node_path.join)(tlsDir2, "camstack-ca.key")
115594
+ };
115595
+ const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
115596
+ const validDays = Math.min(options?.validDays ?? 397, 397);
115597
+ const identity = collectCertIdentity({
115598
+ commonName,
115599
+ extraSans: options?.extraSans ?? []
115600
+ });
115601
+ const reason = decideRegeneration(paths, identity);
115602
+ if (reason === null) return describe(paths, false, null, false, null, null);
115603
+ const previousFingerprint = readFingerprint(paths.certPath);
115604
+ const caRotated = reasonRequiresNewCa(reason);
115605
+ (0, node_fs.mkdirSync)(tlsDir2, { recursive: true });
115606
+ try {
115607
+ await regenerate(paths, identity, commonName, validDays, caRotated);
115608
+ } catch (err) {
115609
+ const message = err instanceof Error ? err.message : String(err);
115610
+ if (!canKeepServing(paths)) throw err;
115611
+ return describe(paths, false, null, false, null, message);
115612
+ }
115613
+ return describe(paths, true, reason, caRotated, previousFingerprint, null);
115614
+ }
115615
+ async function reissueTlsLeaf(dataDir, options) {
115616
+ const tlsDir2 = (0, node_path.join)(dataDir, "tls");
115617
+ const paths = {
115618
+ certPath: (0, node_path.join)(tlsDir2, "camstack.crt"),
115619
+ keyPath: (0, node_path.join)(tlsDir2, "camstack.key"),
115620
+ caCertPath: (0, node_path.join)(tlsDir2, "camstack-ca.crt"),
115621
+ caKeyPath: (0, node_path.join)(tlsDir2, "camstack-ca.key")
115622
+ };
115623
+ if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return ensureTlsCert(dataDir, options);
115624
+ const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
115625
+ const validDays = Math.min(options?.validDays ?? 397, 397);
115626
+ const identity = collectCertIdentity({
115627
+ commonName,
115628
+ extraSans: options?.extraSans ?? []
115629
+ });
115630
+ const previousFingerprint = readFingerprint(paths.certPath);
115631
+ (0, node_fs.mkdirSync)(tlsDir2, { recursive: true });
115632
+ await regenerate(paths, identity, commonName, validDays, false);
115633
+ return describe(paths, true, "san-coverage-gap", false, previousFingerprint, null);
115634
+ }
115635
+ function canKeepServing(paths) {
115636
+ if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return false;
115637
+ if (!(0, node_fs.existsSync)(paths.caCertPath)) return false;
115638
+ return readFingerprint(paths.certPath) !== null;
115639
+ }
115640
+ function readFingerprint(certPath) {
115641
+ try {
115642
+ return new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath)).fingerprint256;
115643
+ } catch {
115644
+ return null;
115645
+ }
115646
+ }
115647
+ function decideRegeneration(paths, identity) {
115648
+ if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return "missing";
115649
+ if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return "no-local-ca";
115650
+ try {
115651
+ return evaluateExistingCert({
115652
+ chainPem: (0, node_fs.readFileSync)(paths.certPath, "utf-8"),
115653
+ keyPem: (0, node_fs.readFileSync)(paths.keyPath, "utf-8"),
115654
+ caPem: (0, node_fs.readFileSync)(paths.caCertPath, "utf-8"),
115655
+ identity,
115656
+ now: /* @__PURE__ */ new Date()
115657
+ });
115658
+ } catch {
115659
+ return "unreadable";
115660
+ }
115661
+ }
115662
+ async function regenerate(paths, identity, commonName, validDays, newCa) {
115663
+ const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "camstack-tls-"));
115664
+ try {
115665
+ const ca = newCa ? await generateCa(scratch) : {
115666
+ caCertPath: paths.caCertPath,
115667
+ caKeyPath: paths.caKeyPath
115668
+ };
115669
+ const leaf = await issueLeaf(scratch, ca, identity, commonName, validDays);
115670
+ const chainPath = (0, node_path.join)(scratch, "chain.crt");
115671
+ await (0, node_fs_promises.writeFile)(chainPath, `${(0, node_fs.readFileSync)(leaf.certPath, "utf-8").trimEnd()}
115672
+ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
115673
+ `, "utf-8");
115674
+ if (newCa) {
115675
+ await (0, node_fs_promises.copyFile)(ca.caCertPath, `${paths.caCertPath}.new`);
115676
+ await (0, node_fs_promises.copyFile)(ca.caKeyPath, `${paths.caKeyPath}.new`);
115677
+ (0, node_fs.renameSync)(`${paths.caCertPath}.new`, paths.caCertPath);
115678
+ (0, node_fs.renameSync)(`${paths.caKeyPath}.new`, paths.caKeyPath);
115679
+ await (0, node_fs_promises.chmod)(paths.caKeyPath, 384);
115680
+ }
115681
+ await (0, node_fs_promises.copyFile)(leaf.keyPath, `${paths.keyPath}.new`);
115682
+ await (0, node_fs_promises.copyFile)(chainPath, `${paths.certPath}.new`);
115683
+ (0, node_fs.renameSync)(`${paths.keyPath}.new`, paths.keyPath);
115684
+ (0, node_fs.renameSync)(`${paths.certPath}.new`, paths.certPath);
115685
+ await (0, node_fs_promises.chmod)(paths.keyPath, 384);
115686
+ } finally {
115687
+ await (0, node_fs_promises.rm)(scratch, {
115688
+ recursive: true,
115689
+ force: true
115690
+ });
115691
+ }
115692
+ }
115693
+ function describe(paths, generated, reason, caRotated, previousFingerprintSha256, reissueError) {
115694
+ const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.certPath));
115695
+ const ca = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.caCertPath));
115696
+ const san = leaf.subjectAltName ?? "";
115697
+ return {
115698
+ ...paths,
115699
+ generated,
115700
+ reason,
115701
+ caRotated,
115702
+ fingerprintSha256: leaf.fingerprint256,
115703
+ previousFingerprintSha256,
115704
+ caFingerprintSha256: ca.fingerprint256,
115705
+ validTo: new Date(leaf.validTo).toISOString(),
115706
+ sans: san === "" ? [] : san.split(", "),
115707
+ reissueError
115708
+ };
115709
+ }
115710
+ function loadTlsCert(certPath, keyPath) {
115711
+ return {
115712
+ cert: (0, node_fs.readFileSync)(certPath),
115713
+ key: (0, node_fs.readFileSync)(keyPath)
115714
+ };
115715
+ }
115716
+ function validateUploadedTls(certPem, keyPem) {
115717
+ let leaf;
115718
+ try {
115719
+ leaf = new node_crypto.X509Certificate(certPem);
115720
+ } catch {
115721
+ return {
115722
+ ok: false,
115723
+ error: "Certificate PEM could not be parsed."
115724
+ };
115725
+ }
115726
+ try {
115727
+ if (!leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem))) return {
115728
+ ok: false,
115729
+ error: "Private key does not match the certificate."
115730
+ };
115731
+ } catch {
115732
+ return {
115733
+ ok: false,
115734
+ error: "Private key PEM could not be parsed."
115735
+ };
115736
+ }
115737
+ const eku = leaf.keyUsage;
115738
+ if (eku === void 0 || !eku.includes("1.3.6.1.5.5.7.3.1")) return {
115739
+ ok: false,
115740
+ error: "Certificate is missing extendedKeyUsage = serverAuth."
115741
+ };
115742
+ return {
115743
+ ok: true,
115744
+ fingerprintSha256: leaf.fingerprint256,
115745
+ validTo: new Date(leaf.validTo).toISOString()
115746
+ };
115747
+ }
115748
+ function tlsDir(dataDir) {
115749
+ return (0, node_path.join)(dataDir, "tls");
115750
+ }
115751
+ function readTlsMode(dataDir) {
115752
+ const marker = (0, node_path.join)(tlsDir(dataDir), "mode");
115753
+ if ((0, node_fs.existsSync)(marker)) {
115754
+ const raw = (0, node_fs.readFileSync)(marker, "utf-8").trim();
115755
+ if (raw === "uploaded") return "uploaded";
115756
+ if (raw === "disabled") return "disabled";
115757
+ }
115758
+ return (0, node_fs.existsSync)((0, node_path.join)(tlsDir(dataDir), "camstack.crt")) ? "generated" : "disabled";
115759
+ }
115760
+ function writeTlsMode(dataDir, mode) {
115761
+ (0, node_fs.mkdirSync)(tlsDir(dataDir), { recursive: true });
115762
+ (0, node_fs.writeFileSync)((0, node_path.join)(tlsDir(dataDir), "mode"), `${mode}
115763
+ `, "utf-8");
115764
+ }
115765
+ function readExtraSans(dataDir) {
115766
+ const path = (0, node_path.join)(tlsDir(dataDir), "extra-sans.json");
115767
+ if (!(0, node_fs.existsSync)(path)) return [];
115768
+ try {
115769
+ const parsed = JSON.parse((0, node_fs.readFileSync)(path, "utf-8"));
115770
+ if (!Array.isArray(parsed)) return [];
115771
+ return parsed.filter((entry) => typeof entry === "string" && entry.length > 0);
115772
+ } catch {
115773
+ return [];
115774
+ }
115775
+ }
115776
+ function writeExtraSans(dataDir, sans) {
115777
+ (0, node_fs.mkdirSync)(tlsDir(dataDir), { recursive: true });
115778
+ (0, node_fs.writeFileSync)((0, node_path.join)(tlsDir(dataDir), "extra-sans.json"), `${JSON.stringify(sans)}
115779
+ `, "utf-8");
115780
+ }
115781
+ function readTlsAccessStatus(dataDir, restartRequired = false) {
115782
+ const dir = tlsDir(dataDir);
115783
+ const certPath = (0, node_path.join)(dir, "camstack.crt");
115784
+ const caPath = (0, node_path.join)(dir, "camstack-ca.crt");
115785
+ const mode = readTlsMode(dataDir);
115786
+ if (!(0, node_fs.existsSync)(certPath)) return {
115787
+ mode: "disabled",
115788
+ leafFingerprintSha256: null,
115789
+ caFingerprintSha256: null,
115790
+ validTo: null,
115791
+ sans: [],
115792
+ caCertPem: (0, node_fs.existsSync)(caPath) ? (0, node_fs.readFileSync)(caPath, "utf-8") : null,
115793
+ reissueError: null,
115794
+ restartRequired
115795
+ };
115796
+ try {
115797
+ const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath));
115798
+ const caPem = (0, node_fs.existsSync)(caPath) ? (0, node_fs.readFileSync)(caPath, "utf-8") : null;
115799
+ const ca = caPem !== null ? new node_crypto.X509Certificate(caPem) : null;
115800
+ const san = leaf.subjectAltName ?? "";
115801
+ return {
115802
+ mode,
115803
+ leafFingerprintSha256: leaf.fingerprint256,
115804
+ caFingerprintSha256: ca?.fingerprint256 ?? null,
115805
+ validTo: new Date(leaf.validTo).toISOString(),
115806
+ sans: san === "" ? [] : san.split(", "),
115807
+ caCertPem: caPem,
115808
+ reissueError: null,
115809
+ restartRequired
115810
+ };
115811
+ } catch {
115812
+ return {
115813
+ mode,
115814
+ leafFingerprintSha256: null,
115815
+ caFingerprintSha256: null,
115816
+ validTo: null,
115817
+ sans: [],
115818
+ caCertPem: null,
115819
+ reissueError: "Certificate on disk could not be parsed.",
115820
+ restartRequired
115821
+ };
115822
+ }
115823
+ }
115824
+ var DEFAULT_HTTP_PORT = 4480;
115825
+ var handlers = null;
115826
+ var server = null;
115827
+ var pending = null;
115828
+ var state = {
115829
+ listening: false,
115830
+ error: null,
115831
+ port: DEFAULT_HTTP_PORT
115832
+ };
115833
+ var boundRequestedHost = null;
115834
+ var DEFAULT_LAN_HTTP_PORT = DEFAULT_HTTP_PORT;
115835
+ function allFamiliesListenHost(host) {
115836
+ if (host === "0.0.0.0" || host === "*" || host === "") return {
115837
+ host: "::",
115838
+ ipv6Only: false
115839
+ };
115840
+ return {
115841
+ host,
115842
+ ipv6Only: false
115843
+ };
115844
+ }
115845
+ function registerLanHttpHandler(next) {
115846
+ handlers = next;
115847
+ }
115848
+ function readLanHttpState() {
115849
+ return state;
115850
+ }
115851
+ async function applyLanHttp(options) {
115852
+ pending = options;
115853
+ if (!options.enabled) {
115854
+ await closeLanHttp();
115855
+ state = {
115856
+ listening: false,
115857
+ error: null,
115858
+ port: options.port
115859
+ };
115860
+ return state;
115861
+ }
115862
+ if (handlers === null) {
115863
+ state = {
115864
+ listening: false,
115865
+ error: "HTTP listener is not registered yet",
115866
+ port: options.port
115867
+ };
115868
+ return state;
115869
+ }
115870
+ if (server !== null && state.listening && (options.port === 0 || state.port === options.port) && boundRequestedHost === options.host) return state;
115871
+ await closeLanHttp();
115872
+ try {
115873
+ const bound = await listenHttp(options.port, options.host, handlers);
115874
+ server = bound;
115875
+ boundRequestedHost = options.host;
115876
+ const addr = bound.address();
115877
+ state = {
115878
+ listening: true,
115879
+ error: null,
115880
+ port: typeof addr === "object" && addr !== null ? addr.port : options.port
115881
+ };
115882
+ return state;
115883
+ } catch (err) {
115884
+ server = null;
115885
+ state = {
115886
+ listening: false,
115887
+ error: err instanceof Error ? err.message : String(err),
115888
+ port: options.port
115889
+ };
115890
+ return state;
115891
+ }
115892
+ }
115893
+ async function bindPendingLanHttp() {
115894
+ if (pending === null) return applyLanHttp({
115895
+ enabled: true,
115896
+ port: DEFAULT_HTTP_PORT,
115897
+ host: "0.0.0.0"
115898
+ });
115899
+ return applyLanHttp(pending);
115900
+ }
115901
+ async function closeLanHttp() {
115902
+ const current = server;
115903
+ server = null;
115904
+ boundRequestedHost = null;
115905
+ if (current === null) return;
115906
+ await new Promise((resolve) => {
115907
+ current.close(() => resolve());
115908
+ });
115909
+ }
115910
+ function listenHttp(port, host, next) {
115911
+ const resolved = allFamiliesListenHost(host);
115912
+ return listenOn(port, resolved, next).catch((err) => {
115913
+ if (resolved.host === "::" && host !== "::") return listenOn(port, {
115914
+ host: "0.0.0.0",
115915
+ ipv6Only: false
115916
+ }, next);
115917
+ throw err;
115918
+ });
115919
+ }
115920
+ function listenOn(port, bind, next) {
115921
+ return new Promise((resolve, reject) => {
115922
+ const created = (0, node_http.createServer)(next.onRequest);
115923
+ created.on("upgrade", next.onUpgrade);
115924
+ const onError = (err) => {
115925
+ created.off("listening", onListening);
115926
+ created.close();
115927
+ reject(err);
115928
+ };
115929
+ const onListening = () => {
115930
+ created.off("error", onError);
115931
+ resolve(created);
115932
+ };
115933
+ created.once("error", onError);
115934
+ created.once("listening", onListening);
115935
+ created.listen({
115936
+ port,
115937
+ host: bind.host,
115938
+ ipv6Only: bind.ipv6Only
115939
+ });
115940
+ });
115941
+ }
115942
+ Object.defineProperty(exports, "CA_COMMON_NAME", {
115943
+ enumerable: true,
115944
+ get: function() {
115945
+ return CA_COMMON_NAME;
115946
+ }
115947
+ });
115948
+ Object.defineProperty(exports, "CA_VALIDITY_DAYS", {
115949
+ enumerable: true,
115950
+ get: function() {
115951
+ return CA_VALIDITY_DAYS;
115952
+ }
115953
+ });
115954
+ Object.defineProperty(exports, "DEFAULT_LAN_HTTP_PORT", {
115955
+ enumerable: true,
115956
+ get: function() {
115957
+ return DEFAULT_LAN_HTTP_PORT;
115958
+ }
115959
+ });
115960
+ Object.defineProperty(exports, "LEAF_RENEWAL_WINDOW_DAYS", {
115961
+ enumerable: true,
115962
+ get: function() {
115963
+ return LEAF_RENEWAL_WINDOW_DAYS;
115964
+ }
115965
+ });
115966
+ Object.defineProperty(exports, "MAX_LEAF_VALIDITY_DAYS", {
115967
+ enumerable: true,
115968
+ get: function() {
115969
+ return MAX_LEAF_VALIDITY_DAYS;
115970
+ }
115971
+ });
115972
+ Object.defineProperty(exports, "SERVER_AUTH_OID", {
115973
+ enumerable: true,
115974
+ get: function() {
115975
+ return SERVER_AUTH_OID;
115976
+ }
115977
+ });
115978
+ Object.defineProperty(exports, "allFamiliesListenHost", {
115979
+ enumerable: true,
115980
+ get: function() {
115981
+ return allFamiliesListenHost;
115982
+ }
115983
+ });
115984
+ Object.defineProperty(exports, "applyLanHttp", {
115985
+ enumerable: true,
115986
+ get: function() {
115987
+ return applyLanHttp;
115988
+ }
115989
+ });
115990
+ Object.defineProperty(exports, "bindPendingLanHttp", {
115991
+ enumerable: true,
115992
+ get: function() {
115993
+ return bindPendingLanHttp;
115994
+ }
115995
+ });
115996
+ Object.defineProperty(exports, "closeLanHttp", {
115997
+ enumerable: true,
115998
+ get: function() {
115999
+ return closeLanHttp;
116000
+ }
116001
+ });
116002
+ Object.defineProperty(exports, "collectCertIdentity", {
116003
+ enumerable: true,
116004
+ get: function() {
116005
+ return collectCertIdentity;
116006
+ }
116007
+ });
116008
+ Object.defineProperty(exports, "ensureTlsCert", {
116009
+ enumerable: true,
116010
+ get: function() {
116011
+ return ensureTlsCert;
116012
+ }
116013
+ });
116014
+ Object.defineProperty(exports, "evaluateExistingCert", {
116015
+ enumerable: true,
116016
+ get: function() {
116017
+ return evaluateExistingCert;
116018
+ }
116019
+ });
116020
+ Object.defineProperty(exports, "loadTlsCert", {
116021
+ enumerable: true,
116022
+ get: function() {
116023
+ return loadTlsCert;
116024
+ }
116025
+ });
116026
+ Object.defineProperty(exports, "readExtraSans", {
116027
+ enumerable: true,
116028
+ get: function() {
116029
+ return readExtraSans;
116030
+ }
116031
+ });
116032
+ Object.defineProperty(exports, "readLanHttpState", {
116033
+ enumerable: true,
116034
+ get: function() {
116035
+ return readLanHttpState;
116036
+ }
116037
+ });
116038
+ Object.defineProperty(exports, "readTlsAccessStatus", {
116039
+ enumerable: true,
116040
+ get: function() {
116041
+ return readTlsAccessStatus;
116042
+ }
116043
+ });
116044
+ Object.defineProperty(exports, "readTlsMode", {
116045
+ enumerable: true,
116046
+ get: function() {
116047
+ return readTlsMode;
116048
+ }
116049
+ });
116050
+ Object.defineProperty(exports, "registerLanHttpHandler", {
116051
+ enumerable: true,
116052
+ get: function() {
116053
+ return registerLanHttpHandler;
116054
+ }
116055
+ });
116056
+ Object.defineProperty(exports, "reissueTlsLeaf", {
116057
+ enumerable: true,
116058
+ get: function() {
116059
+ return reissueTlsLeaf;
116060
+ }
116061
+ });
116062
+ Object.defineProperty(exports, "validateUploadedTls", {
116063
+ enumerable: true,
116064
+ get: function() {
116065
+ return validateUploadedTls;
116066
+ }
116067
+ });
116068
+ Object.defineProperty(exports, "writeExtraSans", {
116069
+ enumerable: true,
116070
+ get: function() {
116071
+ return writeExtraSans;
116072
+ }
116073
+ });
116074
+ Object.defineProperty(exports, "writeTlsMode", {
116075
+ enumerable: true,
116076
+ get: function() {
116077
+ return writeTlsMode;
116078
+ }
116079
+ });
116080
+ }
116081
+ });
116082
+
115041
116083
  // ../system/dist/custom-action-registry-jY0NOZK8.js
115042
116084
  var require_custom_action_registry_jY0NOZK8 = __commonJS({
115043
116085
  "../system/dist/custom-action-registry-jY0NOZK8.js"(exports) {
@@ -118837,7 +119879,7 @@ var require_dist3 = __commonJS({
118837
119879
  "use strict";
118838
119880
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
118839
119881
  var require_chunk = require_chunk_Cek0wNdY();
118840
- var require_dist10 = require_dist_iAwSA2_f();
119882
+ var require_dist10 = require_dist_C2_1HCpW();
118841
119883
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
118842
119884
  require_alerts();
118843
119885
  var require_formatter = require_formatter_DqAKDlvN();
@@ -118861,9 +119903,10 @@ var require_dist3 = __commonJS({
118861
119903
  var require_builtins_system_config_system_config_addon = require_system_config_addon();
118862
119904
  require_system_config();
118863
119905
  var require_builtins_winston_logging_index = require_winston_logging();
118864
- var require_file_data_plane = require_file_data_plane_DUHPHa_Y();
119906
+ var require_file_data_plane = require_file_data_plane_DO8KbxCe();
118865
119907
  var require_manifest_python_deps = require_manifest_python_deps_CwBbX4Ut();
118866
119908
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
119909
+ var require_lan_http_bind = require_lan_http_bind_DmgpFP6();
118867
119910
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
118868
119911
  var zod = require_zod();
118869
119912
  var node_crypto = __require("crypto");
@@ -118883,7 +119926,6 @@ var require_dist3 = __commonJS({
118883
119926
  var node_vm = __require("vm");
118884
119927
  node_vm = require_chunk.__toESM(node_vm);
118885
119928
  var _camstack_types_addon = require_addon();
118886
- var node_net = __require("net");
118887
119929
  var node_url = __require("url");
118888
119930
  var node_events = __require("events");
118889
119931
  var node_stream = __require("stream");
@@ -120169,7 +121211,7 @@ var require_dist3 = __commonJS({
120169
121211
  if (node.children) for (const child of node.children) this.validateNode(child, errors, warnings);
120170
121212
  }
120171
121213
  };
120172
- var execFileAsync$4 = (0, node_util.promisify)(node_child_process.execFile);
121214
+ var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120173
121215
  var PythonEnvManager = class {
120174
121216
  venvPath;
120175
121217
  cachedProbe = null;
@@ -120179,12 +121221,12 @@ var require_dist3 = __commonJS({
120179
121221
  async probe() {
120180
121222
  if (this.cachedProbe) return this.cachedProbe;
120181
121223
  for (const cmd of ["python3", "python"]) try {
120182
- const { stdout } = await execFileAsync$4(cmd, ["--version"]);
121224
+ const { stdout } = await execFileAsync$3(cmd, ["--version"]);
120183
121225
  const version2 = stdout.trim().replace("Python ", "");
120184
121226
  const major = parseInt(version2.split(".")[0] ?? "0", 10);
120185
121227
  const minor = parseInt(version2.split(".")[1] ?? "0", 10);
120186
121228
  if (major < 3 || major === 3 && minor < 10) continue;
120187
- const { stdout: pathOut } = await execFileAsync$4(cmd, ["-c", "import sys; print(sys.executable)"]);
121229
+ const { stdout: pathOut } = await execFileAsync$3(cmd, ["-c", "import sys; print(sys.executable)"]);
120188
121230
  this.cachedProbe = {
120189
121231
  available: true,
120190
121232
  version: version2,
@@ -120200,13 +121242,13 @@ var require_dist3 = __commonJS({
120200
121242
  async ensure(options) {
120201
121243
  const probe = await this.probe();
120202
121244
  if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
120203
- if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$4(probe.path, [
121245
+ if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$3(probe.path, [
120204
121246
  "-m",
120205
121247
  "venv",
120206
121248
  this.venvPath
120207
121249
  ]);
120208
121250
  const venvPython = node_path.join(this.venvPath, "bin", "python");
120209
- if (options.packages.length > 0) await execFileAsync$4(venvPython, [
121251
+ if (options.packages.length > 0) await execFileAsync$3(venvPython, [
120210
121252
  "-m",
120211
121253
  "pip",
120212
121254
  "install",
@@ -120648,338 +121690,6 @@ var require_dist3 = __commonJS({
120648
121690
  };
120649
121691
  }
120650
121692
  };
120651
- var SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
120652
- var MAX_LEAF_VALIDITY_DAYS = 397;
120653
- var LEAF_RENEWAL_WINDOW_DAYS = 30;
120654
- var CA_VALIDITY_DAYS = 3650;
120655
- var MS_PER_DAY = 864e5;
120656
- var REASONS_REQUIRING_NEW_CA = [
120657
- "missing",
120658
- "unreadable",
120659
- "no-local-ca",
120660
- "ca-expiring"
120661
- ];
120662
- function reasonRequiresNewCa(reason) {
120663
- return REASONS_REQUIRING_NEW_CA.includes(reason);
120664
- }
120665
- function parse$1(pem) {
120666
- try {
120667
- return new node_crypto.X509Certificate(pem);
120668
- } catch {
120669
- return null;
120670
- }
120671
- }
120672
- function daysBetween(from, to) {
120673
- return (to.getTime() - from.getTime()) / MS_PER_DAY;
120674
- }
120675
- function hasServerAuthEku(leaf) {
120676
- const eku = leaf.keyUsage;
120677
- return eku !== void 0 && eku.length === 1 && eku[0] === "1.3.6.1.5.5.7.3.1";
120678
- }
120679
- function keyMatches(leaf, keyPem) {
120680
- try {
120681
- return leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem));
120682
- } catch {
120683
- return false;
120684
- }
120685
- }
120686
- function coversIdentity(leaf, identity) {
120687
- for (const name2 of identity.requiredDnsNames) if (leaf.checkHost(name2) === void 0) return false;
120688
- for (const ip of identity.requiredIpAddresses) if (leaf.checkIP(ip) === void 0) return false;
120689
- return true;
120690
- }
120691
- function evaluateExistingCert(input) {
120692
- const leaf = parse$1(input.chainPem);
120693
- const ca = parse$1(input.caPem);
120694
- if (leaf === null || ca === null) return "unreadable";
120695
- if (daysBetween(input.now, new Date(ca.validTo)) < 427) return "ca-expiring";
120696
- if (!keyMatches(leaf, input.keyPem)) return "key-mismatch";
120697
- if (daysBetween(input.now, new Date(leaf.validTo)) < 30) return "expiring";
120698
- if (!hasServerAuthEku(leaf)) return "missing-server-auth-eku";
120699
- if (leaf.ca || !leaf.checkIssued(ca) || !leaf.verify(ca.publicKey)) return "not-issued-by-local-ca";
120700
- if (daysBetween(new Date(leaf.validFrom), new Date(leaf.validTo)) > 398) return "validity-too-long";
120701
- if (!coversIdentity(leaf, input.identity)) return "san-coverage-gap";
120702
- return null;
120703
- }
120704
- var VOLATILE_INTERFACE_PREFIXES = [
120705
- "docker",
120706
- "br-",
120707
- "veth",
120708
- "virbr",
120709
- "cni",
120710
- "flannel",
120711
- "tun",
120712
- "utun",
120713
- "tap",
120714
- "wg",
120715
- "zt",
120716
- "tailscale",
120717
- "ppp",
120718
- "awdl",
120719
- "llw"
120720
- ];
120721
- var DNS_NAME_PATTERN = /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/;
120722
- function isIpv4(value) {
120723
- return (0, node_net.isIP)(value) === 4;
120724
- }
120725
- function isIpv6(value) {
120726
- return (0, node_net.isIP)(value) === 6;
120727
- }
120728
- function isLinkLocal(value) {
120729
- if (isIpv4(value)) return value.startsWith("169.254.");
120730
- if (!isIpv6(value)) return false;
120731
- const firstGroup = value.split(":")[0] ?? "";
120732
- if (firstGroup === "") return false;
120733
- const parsed = Number.parseInt(firstGroup, 16);
120734
- return Number.isFinite(parsed) && (parsed & 65472) === 65152;
120735
- }
120736
- function isUniqueLocalIpv6(value) {
120737
- if (!isIpv6(value)) return false;
120738
- const firstGroup = value.split(":")[0] ?? "";
120739
- const parsed = Number.parseInt(firstGroup, 16);
120740
- return Number.isFinite(parsed) && (parsed & 65024) === 64512;
120741
- }
120742
- function isVolatileInterface(name2) {
120743
- const lower = name2.toLowerCase();
120744
- return VOLATILE_INTERFACE_PREFIXES.some((prefix) => lower.startsWith(prefix));
120745
- }
120746
- function isStableGateAddress(address) {
120747
- if (isLinkLocal(address)) return false;
120748
- if (isIpv4(address)) return true;
120749
- return isUniqueLocalIpv6(address);
120750
- }
120751
- function addSan(dns, ips, value) {
120752
- const trimmed = value.trim();
120753
- if (trimmed === "") return;
120754
- if ((0, node_net.isIP)(trimmed) !== 0) {
120755
- if (!isLinkLocal(trimmed)) ips.add(trimmed);
120756
- return;
120757
- }
120758
- if (DNS_NAME_PATTERN.test(trimmed)) dns.add(trimmed);
120759
- }
120760
- function collectCertIdentity(options) {
120761
- const dnsNames = /* @__PURE__ */ new Set();
120762
- const ipAddresses = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
120763
- const requiredDnsNames = /* @__PURE__ */ new Set();
120764
- const requiredIpAddresses = /* @__PURE__ */ new Set(["127.0.0.1"]);
120765
- for (const name2 of [
120766
- "localhost",
120767
- options.commonName,
120768
- node_os.hostname()
120769
- ]) {
120770
- addSan(dnsNames, ipAddresses, name2);
120771
- addSan(requiredDnsNames, requiredIpAddresses, name2);
120772
- }
120773
- for (const [ifaceName, addrs] of Object.entries(node_os.networkInterfaces())) for (const addr of addrs ?? []) {
120774
- if (addr.internal) continue;
120775
- if (isLinkLocal(addr.address)) continue;
120776
- ipAddresses.add(addr.address);
120777
- if (isVolatileInterface(ifaceName)) continue;
120778
- if (isStableGateAddress(addr.address)) requiredIpAddresses.add(addr.address);
120779
- }
120780
- for (const san of options.extraSans) {
120781
- addSan(dnsNames, ipAddresses, san);
120782
- addSan(requiredDnsNames, requiredIpAddresses, san);
120783
- }
120784
- return {
120785
- dnsNames: [...dnsNames],
120786
- ipAddresses: [...ipAddresses],
120787
- requiredDnsNames: [...requiredDnsNames],
120788
- requiredIpAddresses: [...requiredIpAddresses]
120789
- };
120790
- }
120791
- var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120792
- var CA_COMMON_NAME = "CamStack Local CA";
120793
- function sanValue(identity) {
120794
- const parts = [];
120795
- for (const dns of identity.dnsNames) parts.push(`DNS:${dns}`);
120796
- for (const ip of identity.ipAddresses) if ((0, node_net.isIP)(ip) !== 0) parts.push(`IP:${ip}`);
120797
- return parts.join(",");
120798
- }
120799
- async function generateCa(tmpDir) {
120800
- const caCertPath = (0, node_path.join)(tmpDir, "ca.crt");
120801
- const caKeyPath = (0, node_path.join)(tmpDir, "ca.key");
120802
- await execFileAsync$3("openssl", [
120803
- "req",
120804
- "-x509",
120805
- "-newkey",
120806
- "rsa:2048",
120807
- "-nodes",
120808
- "-sha256",
120809
- "-days",
120810
- String(CA_VALIDITY_DAYS),
120811
- "-keyout",
120812
- caKeyPath,
120813
- "-out",
120814
- caCertPath,
120815
- "-subj",
120816
- `/CN=${CA_COMMON_NAME}`,
120817
- "-addext",
120818
- "basicConstraints=critical,CA:TRUE,pathlen:0",
120819
- "-addext",
120820
- "keyUsage=critical,keyCertSign,cRLSign",
120821
- "-addext",
120822
- "subjectKeyIdentifier=hash"
120823
- ]);
120824
- await (0, node_fs_promises.chmod)(caKeyPath, 384);
120825
- return {
120826
- caCertPath,
120827
- caKeyPath
120828
- };
120829
- }
120830
- async function issueLeaf(tmpDir, ca, identity, commonName, validDays) {
120831
- const keyPath = (0, node_path.join)(tmpDir, "leaf.key");
120832
- const csrPath = (0, node_path.join)(tmpDir, "leaf.csr");
120833
- const certPath = (0, node_path.join)(tmpDir, "leaf.crt");
120834
- const extPath = (0, node_path.join)(tmpDir, "leaf.ext");
120835
- await (0, node_fs_promises.writeFile)(extPath, [
120836
- "basicConstraints=critical,CA:FALSE",
120837
- "keyUsage=critical,digitalSignature,keyEncipherment",
120838
- "extendedKeyUsage=serverAuth",
120839
- "subjectKeyIdentifier=hash",
120840
- "authorityKeyIdentifier=keyid,issuer",
120841
- `subjectAltName=${sanValue(identity)}`,
120842
- ""
120843
- ].join("\n"), "utf-8");
120844
- await execFileAsync$3("openssl", [
120845
- "req",
120846
- "-new",
120847
- "-newkey",
120848
- "rsa:2048",
120849
- "-nodes",
120850
- "-sha256",
120851
- "-keyout",
120852
- keyPath,
120853
- "-out",
120854
- csrPath,
120855
- "-subj",
120856
- `/CN=${commonName}`
120857
- ]);
120858
- await execFileAsync$3("openssl", [
120859
- "x509",
120860
- "-req",
120861
- "-in",
120862
- csrPath,
120863
- "-CA",
120864
- ca.caCertPath,
120865
- "-CAkey",
120866
- ca.caKeyPath,
120867
- "-set_serial",
120868
- `0x00${(0, node_crypto.randomBytes)(16).toString("hex")}`,
120869
- "-days",
120870
- String(validDays),
120871
- "-sha256",
120872
- "-extfile",
120873
- extPath,
120874
- "-out",
120875
- certPath
120876
- ]);
120877
- await (0, node_fs_promises.chmod)(keyPath, 384);
120878
- await (0, node_fs_promises.rm)(csrPath, { force: true });
120879
- await (0, node_fs_promises.rm)(extPath, { force: true });
120880
- return {
120881
- certPath,
120882
- keyPath
120883
- };
120884
- }
120885
- var DEFAULT_COMMON_NAME = "camstack.local";
120886
- async function ensureTlsCert(dataDir, options) {
120887
- const tlsDir = (0, node_path.join)(dataDir, "tls");
120888
- const paths = {
120889
- certPath: (0, node_path.join)(tlsDir, "camstack.crt"),
120890
- keyPath: (0, node_path.join)(tlsDir, "camstack.key"),
120891
- caCertPath: (0, node_path.join)(tlsDir, "camstack-ca.crt"),
120892
- caKeyPath: (0, node_path.join)(tlsDir, "camstack-ca.key")
120893
- };
120894
- const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
120895
- const validDays = Math.min(options?.validDays ?? 397, 397);
120896
- const identity = collectCertIdentity({
120897
- commonName,
120898
- extraSans: options?.extraSans ?? []
120899
- });
120900
- const reason = decideRegeneration(paths, identity);
120901
- if (reason === null) return describe(paths, false, null, false, null);
120902
- const previousFingerprint = readFingerprint(paths.certPath);
120903
- const caRotated = reasonRequiresNewCa(reason);
120904
- (0, node_fs.mkdirSync)(tlsDir, { recursive: true });
120905
- await regenerate(paths, identity, commonName, validDays, caRotated);
120906
- return describe(paths, true, reason, caRotated, previousFingerprint);
120907
- }
120908
- function readFingerprint(certPath) {
120909
- try {
120910
- return new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath)).fingerprint256;
120911
- } catch {
120912
- return null;
120913
- }
120914
- }
120915
- function decideRegeneration(paths, identity) {
120916
- if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return "missing";
120917
- if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return "no-local-ca";
120918
- try {
120919
- return evaluateExistingCert({
120920
- chainPem: (0, node_fs.readFileSync)(paths.certPath, "utf-8"),
120921
- keyPem: (0, node_fs.readFileSync)(paths.keyPath, "utf-8"),
120922
- caPem: (0, node_fs.readFileSync)(paths.caCertPath, "utf-8"),
120923
- identity,
120924
- now: /* @__PURE__ */ new Date()
120925
- });
120926
- } catch {
120927
- return "unreadable";
120928
- }
120929
- }
120930
- async function regenerate(paths, identity, commonName, validDays, newCa) {
120931
- const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "camstack-tls-"));
120932
- try {
120933
- const ca = newCa ? await generateCa(scratch) : {
120934
- caCertPath: paths.caCertPath,
120935
- caKeyPath: paths.caKeyPath
120936
- };
120937
- const leaf = await issueLeaf(scratch, ca, identity, commonName, validDays);
120938
- const chainPath = (0, node_path.join)(scratch, "chain.crt");
120939
- await (0, node_fs_promises.writeFile)(chainPath, `${(0, node_fs.readFileSync)(leaf.certPath, "utf-8").trimEnd()}
120940
- ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
120941
- `, "utf-8");
120942
- if (newCa) {
120943
- await (0, node_fs_promises.copyFile)(ca.caCertPath, `${paths.caCertPath}.new`);
120944
- await (0, node_fs_promises.copyFile)(ca.caKeyPath, `${paths.caKeyPath}.new`);
120945
- (0, node_fs.renameSync)(`${paths.caCertPath}.new`, paths.caCertPath);
120946
- (0, node_fs.renameSync)(`${paths.caKeyPath}.new`, paths.caKeyPath);
120947
- await (0, node_fs_promises.chmod)(paths.caKeyPath, 384);
120948
- }
120949
- await (0, node_fs_promises.copyFile)(leaf.keyPath, `${paths.keyPath}.new`);
120950
- await (0, node_fs_promises.copyFile)(chainPath, `${paths.certPath}.new`);
120951
- (0, node_fs.renameSync)(`${paths.keyPath}.new`, paths.keyPath);
120952
- (0, node_fs.renameSync)(`${paths.certPath}.new`, paths.certPath);
120953
- await (0, node_fs_promises.chmod)(paths.keyPath, 384);
120954
- } finally {
120955
- await (0, node_fs_promises.rm)(scratch, {
120956
- recursive: true,
120957
- force: true
120958
- });
120959
- }
120960
- }
120961
- function describe(paths, generated, reason, caRotated, previousFingerprintSha256) {
120962
- const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.certPath));
120963
- const ca = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.caCertPath));
120964
- const san = leaf.subjectAltName ?? "";
120965
- return {
120966
- ...paths,
120967
- generated,
120968
- reason,
120969
- caRotated,
120970
- fingerprintSha256: leaf.fingerprint256,
120971
- previousFingerprintSha256,
120972
- caFingerprintSha256: ca.fingerprint256,
120973
- validTo: new Date(leaf.validTo).toISOString(),
120974
- sans: san === "" ? [] : san.split(", ")
120975
- };
120976
- }
120977
- function loadTlsCert(certPath, keyPath) {
120978
- return {
120979
- cert: (0, node_fs.readFileSync)(certPath),
120980
- key: (0, node_fs.readFileSync)(keyPath)
120981
- };
120982
- }
120983
121693
  function serializeSetting(value) {
120984
121694
  if (typeof value === "number") return {
120985
121695
  value: String(value),
@@ -199251,8 +199961,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199251
199961
  exports.AlertCenterAddon = require_builtins_alerts_alerts_addon.AlertCenterAddon;
199252
199962
  exports.ApiKeyManager = require_builtins_local_auth_local_auth_addon.ApiKeyManager;
199253
199963
  exports.AuthManager = require_builtins_local_auth_local_auth_addon.AuthManager;
199254
- exports.CA_COMMON_NAME = CA_COMMON_NAME;
199255
- exports.CA_VALIDITY_DAYS = CA_VALIDITY_DAYS;
199964
+ exports.CA_COMMON_NAME = require_lan_http_bind.CA_COMMON_NAME;
199965
+ exports.CA_VALIDITY_DAYS = require_lan_http_bind.CA_VALIDITY_DAYS;
199256
199966
  exports.CLUSTER_SECRET_MISMATCH_TYPE = CLUSTER_SECRET_MISMATCH_TYPE;
199257
199967
  exports.CLUSTER_SECRET_REJECTED_EXIT_CODE = CLUSTER_SECRET_REJECTED_EXIT_CODE;
199258
199968
  exports.CORE_CAP_SERVICE_NAME = CORE_CAP_SERVICE_NAME;
@@ -199269,6 +199979,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199269
199979
  exports.CoreBlocksAddon = require_builtins_core_blocks_core_blocks_addon.CoreBlocksAddon;
199270
199980
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
199271
199981
  exports.DEFAULT_DATA_PATH = DEFAULT_DATA_PATH;
199982
+ exports.DEFAULT_LAN_HTTP_PORT = require_lan_http_bind.DEFAULT_LAN_HTTP_PORT;
199272
199983
  exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_dist10.DEVICE_SETTINGS_CONTRIBUTION_METHODS;
199273
199984
  exports.DEVICE_STATUS_METHOD = require_dist10.DEVICE_STATUS_METHOD;
199274
199985
  exports.DataPlaneRegistry = DataPlaneRegistry;
@@ -199299,7 +200010,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199299
200010
  exports.INFRA_CAPABILITIES = INFRA_CAPABILITIES;
199300
200011
  exports.IntegrationRegistry = IntegrationRegistry;
199301
200012
  exports.JobJournal = JobJournal;
199302
- exports.LEAF_RENEWAL_WINDOW_DAYS = LEAF_RENEWAL_WINDOW_DAYS;
200013
+ exports.LEAF_RENEWAL_WINDOW_DAYS = require_lan_http_bind.LEAF_RENEWAL_WINDOW_DAYS;
199303
200014
  exports.LifecycleJobEngine = LifecycleJobEngine;
199304
200015
  exports.LifecycleStateMachine = LifecycleStateMachine;
199305
200016
  exports.LivenessMonitorAddon = require_builtins_liveness_monitor_liveness_monitor_addon.LivenessMonitorAddon;
@@ -199310,7 +200021,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199310
200021
  exports.LogRingBuffer = LogRingBuffer;
199311
200022
  exports.LokiDestination = require_builtins_loki_logging_index.LokiDestination$1;
199312
200023
  exports.LokiLoggingAddon = require_builtins_loki_logging_index.LokiLoggingAddon$1;
199313
- exports.MAX_LEAF_VALIDITY_DAYS = MAX_LEAF_VALIDITY_DAYS;
200024
+ exports.MAX_LEAF_VALIDITY_DAYS = require_lan_http_bind.MAX_LEAF_VALIDITY_DAYS;
199314
200025
  exports.METHOD_ACCESS_MAP = require_dist10.METHOD_ACCESS_MAP;
199315
200026
  exports.ModelDownloadService = require_file_data_plane.ModelDownloadService;
199316
200027
  exports.NATIVE_PROVIDER_SERVICE_INFIX = require_manifest_python_deps.NATIVE_PROVIDER_SERVICE_INFIX;
@@ -199336,7 +200047,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199336
200047
  exports.ReadinessTimeoutError = require_dist10.ReadinessTimeoutError;
199337
200048
  exports.ReplEngine = ReplEngine;
199338
200049
  exports.RingBuffer = RingBuffer;
199339
- exports.SERVER_AUTH_OID = SERVER_AUTH_OID;
200050
+ exports.SERVER_AUTH_OID = require_lan_http_bind.SERVER_AUTH_OID;
199340
200051
  exports.ScopedLogger = ScopedLogger;
199341
200052
  exports.ScopedTokenManager = require_builtins_local_auth_local_auth_addon.ScopedTokenManager;
199342
200053
  exports.SocketChannel = require_manifest_python_deps.SocketChannel;
@@ -199360,6 +200071,9 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199360
200071
  exports.__resetCapUsageRegistryForTests = require_manifest_python_deps.__resetCapUsageRegistryForTests;
199361
200072
  exports.adaptBrokerToCluster = require_manifest_python_deps.adaptBrokerToCluster;
199362
200073
  exports.addonSettingsCapability = require_dist10.addonSettingsCapability;
200074
+ exports.allFamiliesListenHost = require_lan_http_bind.allFamiliesListenHost;
200075
+ exports.applyLanHttp = require_lan_http_bind.applyLanHttp;
200076
+ exports.bindPendingLanHttp = require_lan_http_bind.bindPendingLanHttp;
199363
200077
  exports.bootstrapSchema = bootstrapSchema;
199364
200078
  exports.brokerCallForCap = require_manifest_python_deps.brokerCallForCap;
199365
200079
  exports.brokerTransportLink = require_manifest_python_deps.brokerTransportLink;
@@ -199386,9 +200100,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199386
200100
  exports.classifyAddonDir = classifyAddonDir;
199387
200101
  exports.classifyCapRoute = require_manifest_python_deps.classifyCapRoute;
199388
200102
  exports.clearPendingRestart = clearPendingRestart;
200103
+ exports.closeLanHttp = require_lan_http_bind.closeLanHttp;
199389
200104
  exports.clusterEventTopic = require_manifest_python_deps.clusterEventTopic;
199390
200105
  exports.clusterSecretMatches = clusterSecretMatches;
199391
- exports.collectCertIdentity = collectCertIdentity;
200106
+ exports.collectCertIdentity = require_lan_http_bind.collectCertIdentity;
199392
200107
  exports.collectModelFiles = require_file_data_plane.collectModelFiles;
199393
200108
  exports.contentTypeFor = require_file_data_plane.contentTypeFor;
199394
200109
  exports.copyDirRecursive = copyDirRecursive;
@@ -199454,8 +200169,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199454
200169
  return _camstack_types_node.ensurePython;
199455
200170
  }
199456
200171
  });
199457
- exports.ensureTlsCert = ensureTlsCert;
199458
- exports.evaluateExistingCert = evaluateExistingCert;
200172
+ exports.ensureTlsCert = require_lan_http_bind.ensureTlsCert;
200173
+ exports.evaluateExistingCert = require_lan_http_bind.evaluateExistingCert;
199459
200174
  exports.expandCapMethods = require_dist10.expandCapMethods;
199460
200175
  exports.fetchJson = require_file_data_plane.fetchJson;
199461
200176
  Object.defineProperty(exports, "findInPath", {
@@ -199519,7 +200234,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199519
200234
  exports.isInfraCapability = isInfraCapability;
199520
200235
  exports.isModelDownloaded = require_file_data_plane.isModelDownloaded;
199521
200236
  exports.isSourceNewer = isSourceNewer;
199522
- exports.loadTlsCert = loadTlsCert;
200237
+ exports.loadTlsCert = require_lan_http_bind.loadTlsCert;
199523
200238
  exports.localEndpointPath = require_manifest_python_deps.localEndpointPath;
199524
200239
  exports.localProviderLink = require_manifest_python_deps.localProviderLink;
199525
200240
  exports.mountNativeCapService = require_manifest_python_deps.mountNativeCapService;
@@ -199528,9 +200243,15 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199528
200243
  exports.parseTokenizedUrl = require_file_data_plane.parseTokenizedUrl;
199529
200244
  exports.proxyToUpstream = proxyToUpstream;
199530
200245
  exports.quarantineAddonResidue = quarantineAddonResidue;
200246
+ exports.readExtraSans = require_lan_http_bind.readExtraSans;
200247
+ exports.readLanHttpState = require_lan_http_bind.readLanHttpState;
199531
200248
  exports.readPendingRestart = readPendingRestart;
200249
+ exports.readTlsAccessStatus = require_lan_http_bind.readTlsAccessStatus;
200250
+ exports.readTlsMode = require_lan_http_bind.readTlsMode;
199532
200251
  exports.readinessKey = require_dist10.readinessKey;
199533
200252
  exports.registerEventBusService = require_manifest_python_deps.registerEventBusService;
200253
+ exports.registerLanHttpHandler = require_lan_http_bind.registerLanHttpHandler;
200254
+ exports.reissueTlsLeaf = require_lan_http_bind.reissueTlsLeaf;
199534
200255
  exports.resolveFilePath = require_file_data_plane.resolveFilePath;
199535
200256
  exports.resolveHwAccel = require_manifest_python_deps.resolveHwAccel;
199536
200257
  exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation;
@@ -199551,7 +200272,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199551
200272
  exports.subscribePassthrough = require_manifest_python_deps.subscribePassthrough;
199552
200273
  exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
199553
200274
  exports.validateProviderRegistrations = require_manifest_python_deps.validateProviderRegistrations;
200275
+ exports.validateUploadedTls = require_lan_http_bind.validateUploadedTls;
200276
+ exports.writeExtraSans = require_lan_http_bind.writeExtraSans;
199554
200277
  exports.writePendingRestart = writePendingRestart;
200278
+ exports.writeTlsMode = require_lan_http_bind.writeTlsMode;
199555
200279
  }
199556
200280
  });
199557
200281
 
@@ -239766,6 +240490,16 @@ var require_dist9 = __commonJS({
239766
240490
  description: zod.z.string().optional(),
239767
240491
  icon: zod.z.string().optional()
239768
240492
  });
240493
+ var CLASS_MAP_MACRO_TARGETS = [
240494
+ "person",
240495
+ "vehicle",
240496
+ "animal",
240497
+ "package"
240498
+ ];
240499
+ var ClassMapDefinitionSchema = zod.z.object({
240500
+ mapping: zod.z.record(zod.z.string(), zod.z.enum(CLASS_MAP_MACRO_TARGETS)),
240501
+ preserveOriginal: zod.z.boolean()
240502
+ });
239769
240503
  var FORMAT_KEYS = [
239770
240504
  "onnx",
239771
240505
  "coreml",
@@ -240034,7 +240768,13 @@ var require_dist9 = __commonJS({
240034
240768
  * `id` stays the source of truth for resolution/download/persistence; grouping
240035
240769
  * is a presentation overlay resolved back to an `id`.
240036
240770
  */
240037
- group: ModelVariantGroupSchema.optional()
240771
+ group: ModelVariantGroupSchema.optional(),
240772
+ /**
240773
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
240774
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
240775
+ * labels already ARE the CamStack macros (Scrypted identity map).
240776
+ */
240777
+ classMap: ClassMapDefinitionSchema.optional()
240038
240778
  });
240039
240779
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
240040
240780
  format: zod.z.literal("openvino"),
@@ -240063,7 +240803,8 @@ var require_dist9 = __commonJS({
240063
240803
  "ocr",
240064
240804
  "segmentation"
240065
240805
  ]),
240066
- faceAlignment: zod.z.boolean().optional()
240806
+ faceAlignment: zod.z.boolean().optional(),
240807
+ classMap: ClassMapDefinitionSchema.optional()
240067
240808
  });
240068
240809
  var ConvertArtifactSchema = zod.z.object({
240069
240810
  format: zod.z.enum(MODEL_FORMATS),
@@ -250963,6 +251704,33 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250963
251704
  h: zod.z.number()
250964
251705
  })
250965
251706
  });
251707
+ zod.z.object({
251708
+ crop: zod.z.object({
251709
+ left: zod.z.number(),
251710
+ top: zod.z.number(),
251711
+ width: zod.z.number().positive(),
251712
+ height: zod.z.number().positive()
251713
+ }).optional(),
251714
+ content: zod.z.object({
251715
+ width: zod.z.number().int().positive(),
251716
+ height: zod.z.number().int().positive()
251717
+ }),
251718
+ fit: zod.z.enum(["stretch", "contain"]),
251719
+ format: zod.z.enum([
251720
+ "rgb",
251721
+ "gray",
251722
+ "jpeg"
251723
+ ])
251724
+ });
251725
+ var FrameRefSchema = zod.z.object({
251726
+ registryId: zod.z.string().min(1),
251727
+ id: zod.z.string().min(1),
251728
+ width: zod.z.number().int().positive(),
251729
+ height: zod.z.number().int().positive(),
251730
+ format: zod.z.enum(["rgb", "gray"]),
251731
+ timestamp: zod.z.number(),
251732
+ capturedAt: zod.z.number().optional()
251733
+ });
250966
251734
  var ModelFormatSchema$1 = zod.z.enum([
250967
251735
  "onnx",
250968
251736
  "coreml",
@@ -251262,7 +252030,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251262
252030
  * legacy call shape used by existing benchmark code; once all
251263
252031
  * callers pass it explicitly we make it required.
251264
252032
  *
251265
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
252033
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
251266
252034
  * `referenceImage` must be provided:
251267
252035
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
251268
252036
  * Carries the raw buffer, dimensions, and format; the executor
@@ -251284,6 +252052,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251284
252052
  steps: zod.z.array(PipelineStepInputSchema).min(1),
251285
252053
  frame: FrameInputSchema.optional(),
251286
252054
  /**
252055
+ * Process-local lazy frame. Valid only when caller and provider resolve
252056
+ * in the same execution-group process; split/cross-node callers use
252057
+ * `frame`/`image` inline compatibility instead.
252058
+ */
252059
+ frameRef: FrameRefSchema.optional(),
252060
+ /**
251287
252061
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
251288
252062
  * the decoded pixels live in. One more member of the one-of
251289
252063
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -251586,7 +252360,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251586
252360
  * Which source served this crop, so a quality-sensitive consumer (the native
251587
252361
  * `keyFrame`) can reject a degraded fallback:
251588
252362
  * - `native` — cut from the decode worker's retained NATIVE surface (the
251589
- * quality path).
252363
+ * quality path). A subject-tile serve is also native-resolution and stays
252364
+ * `native` here: the public enum cannot name `tile` without a breaking cap
252365
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
252366
+ * internal crop result (`nativeHits` vs `tileHits`).
251590
252367
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
251591
252368
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
251592
252369
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -252089,12 +252866,41 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
252089
252866
  cpuCores: zod.z.number().optional()
252090
252867
  })
252091
252868
  });
252869
+ var FrameLazyCountersSchema = zod.z.object({
252870
+ framesDecoded: zod.z.number(),
252871
+ framesAdmitted: zod.z.number(),
252872
+ framesDroppedPixelFree: zod.z.number(),
252873
+ viewsMaterialized: zod.z.number(),
252874
+ viewsSkipped: zod.z.number(),
252875
+ workerToRunnerBytes: zod.z.number(),
252876
+ runnerToPoolRawBytes: zod.z.number(),
252877
+ runnerToPoolJpegBytes: zod.z.number(),
252878
+ onDemandFullFrameRequests: zod.z.number(),
252879
+ onDemandCropRequests: zod.z.number(),
252880
+ nativeHits: zod.z.number(),
252881
+ nativeMisses: zod.z.number(),
252882
+ tileHits: zod.z.number(),
252883
+ tileMisses: zod.z.number(),
252884
+ fallbackHits: zod.z.number(),
252885
+ fallbackMisses: zod.z.number(),
252886
+ retainedWritesAvoided: zod.z.number(),
252887
+ residentRefs: zod.z.number(),
252888
+ residentBytes: zod.z.number(),
252889
+ releases: zod.z.number(),
252890
+ evictions: zod.z.number(),
252891
+ staleMisses: zod.z.number()
252892
+ });
252893
+ var FrameLazyMetricsSchema = zod.z.object({
252894
+ node: FrameLazyCountersSchema,
252895
+ cameras: zod.z.array(FrameLazyCountersSchema.extend({ deviceId: zod.z.number() }))
252896
+ });
252092
252897
  var RunnerLocalMetricsSchema = zod.z.object({
252093
252898
  nodeId: zod.z.string(),
252094
252899
  activeCameras: zod.z.number(),
252095
252900
  throttledCameras: zod.z.number(),
252096
252901
  avgInferenceTimeMs: zod.z.number(),
252097
- queueDepth: zod.z.number()
252902
+ queueDepth: zod.z.number(),
252903
+ frameLazy: FrameLazyMetricsSchema.optional()
252098
252904
  });
252099
252905
  var pipelineRunnerCapability = {
252100
252906
  name: "pipeline-runner",
@@ -253900,6 +254706,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253900
254706
  endDownload: require_sleep.method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
253901
254707
  }
253902
254708
  };
254709
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
254710
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
253903
254711
  var TerminalSessionInfoSchema = zod.z.object({
253904
254712
  /** Opaque session id minted by the provider on `openSession`. */
253905
254713
  sessionId: zod.z.string(),
@@ -253915,7 +254723,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253915
254723
  var TerminalProfileInfoSchema = zod.z.object({
253916
254724
  profileId: zod.z.string(),
253917
254725
  label: zod.z.string(),
253918
- description: zod.z.string().optional()
254726
+ description: zod.z.string().optional(),
254727
+ /** Spawn defaults the instance form copies on create. */
254728
+ executable: zod.z.string().optional(),
254729
+ args: zod.z.array(zod.z.string()).readonly().optional(),
254730
+ cwd: zod.z.string().optional(),
254731
+ environment: zod.z.array(zod.z.string()).readonly().optional(),
254732
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
254733
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
253919
254734
  });
253920
254735
  var TerminalInstanceInfoSchema = zod.z.object({
253921
254736
  instanceId: zod.z.string(),
@@ -253924,7 +254739,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253924
254739
  profileId: zod.z.string(),
253925
254740
  profileLabel: zod.z.string(),
253926
254741
  name: zod.z.string(),
253927
- enabled: zod.z.boolean()
254742
+ enabled: zod.z.boolean(),
254743
+ executable: zod.z.string(),
254744
+ args: zod.z.array(zod.z.string()).readonly(),
254745
+ cwd: zod.z.string(),
254746
+ environment: zod.z.array(zod.z.string()).readonly(),
254747
+ profileSettings: ProfileSettingsBagSchema
253928
254748
  });
253929
254749
  var TerminalLegacyCameraSchema = zod.z.object({
253930
254750
  stableId: zod.z.string(),
@@ -253963,7 +254783,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253963
254783
  createInstance: require_sleep.method(zod.z.object({
253964
254784
  targetNodeId: zod.z.string().min(1),
253965
254785
  profileId: zod.z.string().min(1),
253966
- name: zod.z.string().trim().min(1).max(160).optional()
254786
+ name: zod.z.string().trim().min(1).max(160).optional(),
254787
+ executable: zod.z.string().max(1024).optional(),
254788
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
254789
+ cwd: zod.z.string().max(1024).optional(),
254790
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
254791
+ profileSettings: ProfileSettingsBagSchema.optional()
254792
+ }), TerminalInstanceInfoSchema, {
254793
+ kind: "mutation",
254794
+ auth: "admin"
254795
+ }),
254796
+ updateInstance: require_sleep.method(zod.z.object({
254797
+ instanceId: zod.z.string().min(1),
254798
+ name: zod.z.string().trim().min(1).max(160).optional(),
254799
+ executable: zod.z.string().max(1024).optional(),
254800
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
254801
+ cwd: zod.z.string().max(1024).optional(),
254802
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
254803
+ profileSettings: ProfileSettingsBagSchema.optional()
253967
254804
  }), TerminalInstanceInfoSchema, {
253968
254805
  kind: "mutation",
253969
254806
  auth: "admin"
@@ -253998,7 +254835,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253998
254835
  openSession: require_sleep.method(zod.z.object({
253999
254836
  profileId: zod.z.string(),
254000
254837
  cols: zod.z.number().int().positive(),
254001
- rows: zod.z.number().int().positive()
254838
+ rows: zod.z.number().int().positive(),
254839
+ executable: zod.z.string().max(1024).optional(),
254840
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
254841
+ cwd: zod.z.string().max(1024).optional(),
254842
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional()
254002
254843
  }), TerminalSessionInfoSchema, {
254003
254844
  kind: "mutation",
254004
254845
  auth: "admin"
@@ -257724,6 +258565,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257724
258565
  /** What the ranking currently resolves to (null when nothing is reachable). */
257725
258566
  resolved: zod.z.string().nullable()
257726
258567
  });
258568
+ var ViewerEndpointsSchema = zod.z.object({
258569
+ /** The operator's explicit race set, or empty for AUTO. */
258570
+ baseUrls: zod.z.array(zod.z.string()).readonly(),
258571
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
258572
+ resolved: zod.z.array(zod.z.string()).readonly()
258573
+ });
257727
258574
  var AllowedAddressesSchema = zod.z.object({
257728
258575
  /**
257729
258576
  * Allowlist of interface addresses operators have explicitly opted
@@ -257733,6 +258580,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257733
258580
  */
257734
258581
  addresses: zod.z.array(zod.z.string()).readonly()
257735
258582
  });
258583
+ var TlsStatusSchema = zod.z.object({
258584
+ mode: zod.z.enum([
258585
+ "generated",
258586
+ "uploaded",
258587
+ "disabled"
258588
+ ]),
258589
+ leafFingerprintSha256: zod.z.string().nullable(),
258590
+ caFingerprintSha256: zod.z.string().nullable(),
258591
+ validTo: zod.z.string().nullable(),
258592
+ sans: zod.z.array(zod.z.string()),
258593
+ caCertPem: zod.z.string().nullable(),
258594
+ reissueError: zod.z.string().nullable(),
258595
+ restartRequired: zod.z.boolean()
258596
+ });
257736
258597
  var localNetworkCapability = {
257737
258598
  name: "local-network",
257738
258599
  scope: "system",
@@ -257752,13 +258613,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257752
258613
  */
257753
258614
  getPreferred: require_sleep.method(zod.z.void(), PreferredSchema),
257754
258615
  /**
257755
- * Ordered candidate base URLs the SDK should try on connect.
257756
- * Includes LAN IPs (one per non-internal interface), the public
257757
- * tunnel hostname (when active), and loopback as a last-resort
257758
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
257759
- * Honours `getAllowedAddresses()` when set addresses outside
257760
- * the allowlist are dropped (the public tunnel + loopback are
257761
- * always included as escape hatches).
258616
+ * Ordered candidate base URLs (the palette the Network tab shows).
258617
+ * Includes LAN IPv4, stable LAN IPv6, the public tunnel, and mesh when
258618
+ * joined. Loopback is off by default. The SDK races the subset from
258619
+ * `getViewerEndpoints`, not this full list — IPv6 stays here because
258620
+ * WebRTC ICE gathers dual-stack regardless of the HTTP race. Honours
258621
+ * `getAllowedAddresses()` when set addresses outside the allowlist
258622
+ * are dropped (the public tunnel is still included as an escape hatch).
257762
258623
  *
257763
258624
  * **The port is the hub's, not the caller's** (D62 — a function's fact
257764
258625
  * belongs to whoever already owns it). This method used to take a `port`
@@ -257789,10 +258650,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257789
258650
  */
257790
258651
  port: zod.z.number().int().min(1).max(65535).optional(),
257791
258652
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
257792
- * candidate. Default `true`. */
258653
+ * candidate. Default `false` — loopback is not a client route. */
257793
258654
  includeLoopback: zod.z.boolean().optional(),
257794
- /** Skip IPv6 entries. Some legacy clients can't parse them.
257795
- * Default `false`. */
258655
+ /** Skip IPv6 entries. Default `false` the palette includes stable
258656
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
258657
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
257796
258658
  ipv4Only: zod.z.boolean().optional(),
257797
258659
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
257798
258660
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -257821,6 +258683,19 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257821
258683
  */
257822
258684
  setNotificationEndpoint: require_sleep.method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
257823
258685
  /**
258686
+ * The endpoints the SDK / viewer races for API access. Empty `baseUrls`
258687
+ * means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
258688
+ * never mesh, never loopback. `resolved` is that set (or the operator's
258689
+ * explicit subset) as it stands right now.
258690
+ */
258691
+ getViewerEndpoints: require_sleep.method(zod.z.void(), ViewerEndpointsSchema),
258692
+ /**
258693
+ * Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
258694
+ * verbatim (not indices) so a temporarily-down tunnel is not silently
258695
+ * dropped from the operator's choice.
258696
+ */
258697
+ setViewerEndpoints: require_sleep.method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
258698
+ /**
257824
258699
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
257825
258700
  * by the admin UI's address selector to seed its checkbox state.
257826
258701
  */
@@ -257838,7 +258713,34 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257838
258713
  * when the operator wants to wipe their manual edits and start
257839
258714
  * over from the auto-detected best matches.
257840
258715
  */
257841
- resetAllowlistToBestMatch: require_sleep.method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" })
258716
+ resetAllowlistToBestMatch: require_sleep.method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" }),
258717
+ /**
258718
+ * Live TLS material for the Network → Local access certificate card.
258719
+ * LAN HTTP / hostname are addon settings (`globalSettingsSchema`), not
258720
+ * a second store — this query is status, not configuration.
258721
+ */
258722
+ getTlsStatus: require_sleep.method(zod.z.void(), TlsStatusSchema),
258723
+ /** Issue a new leaf under the existing local CA. Disabled in uploaded mode. */
258724
+ regenerateCertificate: require_sleep.method(zod.z.object({ reason: zod.z.string().optional() }), TlsStatusSchema, {
258725
+ kind: "mutation",
258726
+ auth: "admin"
258727
+ }),
258728
+ /** Replace the served material with operator-supplied PEMs. */
258729
+ uploadCertificate: require_sleep.method(zod.z.object({
258730
+ certPem: zod.z.string().min(1),
258731
+ keyPem: zod.z.string().min(1),
258732
+ caPem: zod.z.string().optional()
258733
+ }), TlsStatusSchema, {
258734
+ kind: "mutation",
258735
+ auth: "admin"
258736
+ }),
258737
+ /** The local CA PEM, or empty when there is none to download. */
258738
+ downloadCa: require_sleep.method(zod.z.void(), zod.z.object({ pem: zod.z.string() })),
258739
+ /** Drop uploaded material and return to the generated local CA. */
258740
+ revertToGeneratedCertificate: require_sleep.method(zod.z.void(), TlsStatusSchema, {
258741
+ kind: "mutation",
258742
+ auth: "admin"
258743
+ })
257842
258744
  },
257843
258745
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
257844
258746
  mount: { kind: "hub-only" }
@@ -268127,6 +269029,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268127
269029
  addonId: null,
268128
269030
  access: "create"
268129
269031
  },
269032
+ "localNetwork.downloadCa": {
269033
+ capName: "local-network",
269034
+ capScope: "system",
269035
+ addonId: null,
269036
+ access: "view"
269037
+ },
268130
269038
  "localNetwork.getAllowedAddresses": {
268131
269039
  capName: "local-network",
268132
269040
  capScope: "system",
@@ -268151,18 +269059,42 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268151
269059
  addonId: null,
268152
269060
  access: "view"
268153
269061
  },
269062
+ "localNetwork.getTlsStatus": {
269063
+ capName: "local-network",
269064
+ capScope: "system",
269065
+ addonId: null,
269066
+ access: "view"
269067
+ },
269068
+ "localNetwork.getViewerEndpoints": {
269069
+ capName: "local-network",
269070
+ capScope: "system",
269071
+ addonId: null,
269072
+ access: "view"
269073
+ },
268154
269074
  "localNetwork.list": {
268155
269075
  capName: "local-network",
268156
269076
  capScope: "system",
268157
269077
  addonId: null,
268158
269078
  access: "view"
268159
269079
  },
269080
+ "localNetwork.regenerateCertificate": {
269081
+ capName: "local-network",
269082
+ capScope: "system",
269083
+ addonId: null,
269084
+ access: "create"
269085
+ },
268160
269086
  "localNetwork.resetAllowlistToBestMatch": {
268161
269087
  capName: "local-network",
268162
269088
  capScope: "system",
268163
269089
  addonId: null,
268164
269090
  access: "delete"
268165
269091
  },
269092
+ "localNetwork.revertToGeneratedCertificate": {
269093
+ capName: "local-network",
269094
+ capScope: "system",
269095
+ addonId: null,
269096
+ access: "create"
269097
+ },
268166
269098
  "localNetwork.setAllowedAddresses": {
268167
269099
  capName: "local-network",
268168
269100
  capScope: "system",
@@ -268175,6 +269107,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268175
269107
  addonId: null,
268176
269108
  access: "create"
268177
269109
  },
269110
+ "localNetwork.setViewerEndpoints": {
269111
+ capName: "local-network",
269112
+ capScope: "system",
269113
+ addonId: null,
269114
+ access: "create"
269115
+ },
269116
+ "localNetwork.uploadCertificate": {
269117
+ capName: "local-network",
269118
+ capScope: "system",
269119
+ addonId: null,
269120
+ access: "create"
269121
+ },
268178
269122
  "lockControl.lock": {
268179
269123
  capName: "lock-control",
268180
269124
  capScope: "device",
@@ -271055,6 +271999,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
271055
271999
  addonId: null,
271056
272000
  access: "create"
271057
272001
  },
272002
+ "terminalSession.updateInstance": {
272003
+ capName: "terminal-session",
272004
+ capScope: "system",
272005
+ addonId: null,
272006
+ access: "create"
272007
+ },
271058
272008
  "terminalSession.writeInput": {
271059
272009
  capName: "terminal-session",
271060
272010
  capScope: "system",
@@ -274313,9 +275263,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274313
275263
  getConnectionEndpoints: (input) => dispatch("localNetwork", "getConnectionEndpoints", "query", input),
274314
275264
  getNotificationEndpoint: (input) => dispatch("localNetwork", "getNotificationEndpoint", "query", input),
274315
275265
  setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
275266
+ getViewerEndpoints: (input) => dispatch("localNetwork", "getViewerEndpoints", "query", input),
275267
+ setViewerEndpoints: (input) => dispatch("localNetwork", "setViewerEndpoints", "mutation", input),
274316
275268
  getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
274317
275269
  setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
274318
- resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input)
275270
+ resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input),
275271
+ getTlsStatus: (input) => dispatch("localNetwork", "getTlsStatus", "query", input),
275272
+ regenerateCertificate: (input) => dispatch("localNetwork", "regenerateCertificate", "mutation", input),
275273
+ uploadCertificate: (input) => dispatch("localNetwork", "uploadCertificate", "mutation", input),
275274
+ downloadCa: (input) => dispatch("localNetwork", "downloadCa", "query", input),
275275
+ revertToGeneratedCertificate: (input) => dispatch("localNetwork", "revertToGeneratedCertificate", "mutation", input)
274319
275276
  },
274320
275277
  meshNetwork: {
274321
275278
  getStatus: (input) => dispatch("meshNetwork", "getStatus", "query", input),
@@ -274597,6 +275554,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274597
275554
  listProfiles: (input) => dispatch("terminalSession", "listProfiles", "query", input),
274598
275555
  listInstances: (input) => dispatch("terminalSession", "listInstances", "query", input),
274599
275556
  createInstance: (input) => dispatch("terminalSession", "createInstance", "mutation", input),
275557
+ updateInstance: (input) => dispatch("terminalSession", "updateInstance", "mutation", input),
274600
275558
  deleteInstance: (input) => dispatch("terminalSession", "deleteInstance", "mutation", input),
274601
275559
  setInstanceEnabled: (input) => dispatch("terminalSession", "setInstanceEnabled", "mutation", input),
274602
275560
  listLegacyCameras: (input) => dispatch("terminalSession", "listLegacyCameras", "query", input),
@@ -275511,6 +276469,58 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275511
276469
  const chosen = models[stepId];
275512
276470
  return chosen !== void 0 && chosen !== "" ? chosen : step2.defaultModelId;
275513
276471
  }
276472
+ var DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = 24;
276473
+ var CLUSTER_STEP_SETTING_FIELDS = [{
276474
+ stepId: "face-embedding",
276475
+ key: "minLandmarkFaceSize",
276476
+ label: "Min face size for recognition (detection px)",
276477
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node \u2014 the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
276478
+ type: "slider",
276479
+ min: 0,
276480
+ max: 64,
276481
+ step: 2,
276482
+ default: 24
276483
+ }];
276484
+ function clusterStepSettingKey(stepId, fieldKey) {
276485
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
276486
+ }
276487
+ function clusterStepSettingFieldsFor(stepId) {
276488
+ return CLUSTER_STEP_SETTING_FIELDS.filter((field) => field.stepId === stepId);
276489
+ }
276490
+ var ClusterSettingNumberSchema = zod.z.number().finite();
276491
+ function readClusterStepSettings(config) {
276492
+ const out = {};
276493
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
276494
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
276495
+ const value = parsed.success ? parsed.data : field.default;
276496
+ const existing = out[field.stepId] ?? {};
276497
+ out[field.stepId] = {
276498
+ ...existing,
276499
+ [field.key]: value
276500
+ };
276501
+ }
276502
+ return out;
276503
+ }
276504
+ var DEFAULT_CLUSTER_STEP_SETTINGS = readClusterStepSettings({});
276505
+ function pickClusterStepSettings(view) {
276506
+ if (view === null) return DEFAULT_CLUSTER_STEP_SETTINGS;
276507
+ const flat = {};
276508
+ const wanted = new Set(CLUSTER_STEP_SETTING_FIELDS.map((field) => clusterStepSettingKey(field.stepId, field.key)));
276509
+ for (const section of view.sections) for (const entry of section.fields) {
276510
+ if (!isHydratedField$2(entry) || typeof entry.key !== "string") continue;
276511
+ if (wanted.has(entry.key)) flat[entry.key] = entry.value;
276512
+ }
276513
+ return readClusterStepSettings(flat);
276514
+ }
276515
+ function overlayClusterStepSettings(stepId, deviceSettings, cluster) {
276516
+ const overlay = cluster[stepId];
276517
+ if (overlay === void 0 || Object.keys(overlay).length === 0) return deviceSettings === void 0 ? void 0 : { ...deviceSettings };
276518
+ if (deviceSettings === void 0) return { ...overlay };
276519
+ return {
276520
+ ...deviceSettings,
276521
+ ...overlay
276522
+ };
276523
+ }
275514
276524
  var DETAIL_CROP_SECTION_ID = "detail-crop";
275515
276525
  var DETAIL_CROP_PADDING_KEY = "detailCropPaddingRatio";
275516
276526
  var DETAIL_CROP_SQUARE_KEY = "detailCropSquare";
@@ -277299,8 +278309,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277299
278309
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
277300
278310
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
277301
278311
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
278312
+ exports.CLASS_MAP_MACRO_TARGETS = CLASS_MAP_MACRO_TARGETS;
277302
278313
  exports.CLUSTER_MODEL_SCOPED_STEPS = CLUSTER_MODEL_SCOPED_STEPS;
277303
278314
  exports.CLUSTER_MODEL_SECTION_ID = CLUSTER_MODEL_SECTION_ID;
278315
+ exports.CLUSTER_STEP_SETTING_FIELDS = CLUSTER_STEP_SETTING_FIELDS;
277304
278316
  exports.COCO_80_LABELS = COCO_80_LABELS;
277305
278317
  exports.COCO_TO_MACRO = COCO_TO_MACRO;
277306
278318
  exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
@@ -277344,6 +278356,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277344
278356
  exports.CapabilityBindingsSchema = CapabilityBindingsSchema;
277345
278357
  exports.CarbonMonoxideStatusSchema = CarbonMonoxideStatusSchema;
277346
278358
  exports.ChargingStatus = require_sleep.ChargingStatus;
278359
+ exports.ClassMapDefinitionSchema = ClassMapDefinitionSchema;
277347
278360
  exports.ClientNetworkStatsSchema = ClientNetworkStatsSchema;
277348
278361
  exports.ClimateControlStatusSchema = ClimateControlStatusSchema;
277349
278362
  exports.ClipPlaybackSchema = ClipPlaybackSchema;
@@ -277389,11 +278402,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277389
278402
  exports.DEFAULT_ADDON_PLACEMENT = DEFAULT_ADDON_PLACEMENT;
277390
278403
  exports.DEFAULT_AUDIO_ANALYZER_CONFIG = DEFAULT_AUDIO_ANALYZER_CONFIG;
277391
278404
  exports.DEFAULT_CLUSTER_STEP_MODELS = DEFAULT_CLUSTER_STEP_MODELS;
278405
+ exports.DEFAULT_CLUSTER_STEP_SETTINGS = DEFAULT_CLUSTER_STEP_SETTINGS;
277392
278406
  exports.DEFAULT_DECODER_HWACCEL_CONFIG = DEFAULT_DECODER_HWACCEL_CONFIG;
277393
278407
  exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
277394
278408
  exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
277395
278409
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
277396
278410
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
278411
+ exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
277397
278412
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
277398
278413
  exports.DEFAULT_POOL_MEMORY_POLICY = DEFAULT_POOL_MEMORY_POLICY;
277399
278414
  exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
@@ -277517,6 +278532,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277517
278532
  exports.FrameHandleFormatSchema = require_sleep.FrameHandleFormatSchema;
277518
278533
  exports.FrameHandleSchema = require_sleep.FrameHandleSchema;
277519
278534
  exports.FrameInputSchema = FrameInputSchema;
278535
+ exports.FrameLazyCountersSchema = FrameLazyCountersSchema;
278536
+ exports.FrameLazyMetricsSchema = FrameLazyMetricsSchema;
277520
278537
  exports.GasStatusSchema = GasStatusSchema;
277521
278538
  exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
277522
278539
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
@@ -278171,6 +279188,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278171
279188
  exports.classifyStreams = classifyStreams;
278172
279189
  exports.climateControlCapability = climateControlCapability;
278173
279190
  exports.clusterModelSettingKey = clusterModelSettingKey;
279191
+ exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
279192
+ exports.clusterStepSettingKey = clusterStepSettingKey;
278174
279193
  exports.collectHydratedFieldEntries = require_sleep.collectHydratedFieldEntries;
278175
279194
  exports.collectHydratedFieldValues = require_sleep.collectHydratedFieldValues;
278176
279195
  exports.colorCapability = colorCapability;
@@ -278361,6 +279380,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278361
279380
  exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
278362
279381
  exports.osdCapability = osdCapability;
278363
279382
  exports.osdManagerCapability = osdManagerCapability;
279383
+ exports.overlayClusterStepSettings = overlayClusterStepSettings;
278364
279384
  exports.parseCameraStreamConfig = parseCameraStreamConfig;
278365
279385
  exports.parseExpression = parseExpression;
278366
279386
  exports.parseJsonArray = require_sleep.parseJsonArray;
@@ -278374,6 +279394,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278374
279394
  exports.petFeederCapability = petFeederCapability;
278375
279395
  exports.pickAccessoryControl = pickAccessoryControl;
278376
279396
  exports.pickClusterStepModels = pickClusterStepModels;
279397
+ exports.pickClusterStepSettings = pickClusterStepSettings;
278377
279398
  exports.pickDetailCropConvention = pickDetailCropConvention;
278378
279399
  exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
278379
279400
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
@@ -278398,6 +279419,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278398
279419
  exports.ptzCapability = ptzCapability;
278399
279420
  exports.pythonScriptForBackend = pythonScriptForBackend;
278400
279421
  exports.readClusterStepModels = readClusterStepModels;
279422
+ exports.readClusterStepSettings = readClusterStepSettings;
278401
279423
  exports.readDetailCropConvention = readDetailCropConvention;
278402
279424
  exports.readDeviceStateFrom = readDeviceStateFrom;
278403
279425
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
@@ -394926,18 +395948,26 @@ var require_session_cookie = __commonJS({
394926
395948
  exports.isEmbedRedirectTarget = isEmbedRedirectTarget;
394927
395949
  exports.isSessionGradeJwtPayload = isSessionGradeJwtPayload;
394928
395950
  exports.SESSION_COOKIE = "camstack_session";
394929
- function buildSessionCookie(token2, ttlSec) {
395951
+ function buildSessionCookie(token2, ttlSec, opts = {}) {
394930
395952
  return {
394931
395953
  name: exports.SESSION_COOKIE,
394932
395954
  value: token2,
394933
- options: { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: ttlSec }
395955
+ options: {
395956
+ httpOnly: true,
395957
+ sameSite: "lax",
395958
+ // Secure cookies are invisible on the LAN HTTP sibling (plain http://).
395959
+ // Default stays true so HTTPS callers do not regress.
395960
+ secure: opts.secure ?? true,
395961
+ path: "/",
395962
+ maxAge: ttlSec
395963
+ }
394934
395964
  };
394935
395965
  }
394936
- function clearSessionCookie() {
395966
+ function clearSessionCookie(opts = {}) {
394937
395967
  return {
394938
395968
  name: exports.SESSION_COOKIE,
394939
395969
  value: "",
394940
- options: { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: 0 }
395970
+ options: { httpOnly: true, sameSite: "lax", secure: opts.secure ?? true, path: "/", maxAge: 0 }
394941
395971
  };
394942
395972
  }
394943
395973
  function readSessionCookieFromHeader(header) {
@@ -395102,6 +396132,25 @@ var require_health_routes = __commonJS({
395102
396132
  }
395103
396133
  });
395104
396134
 
396135
+ // ../../server/backend/dist/api/health/adaptive-probe.routes.js
396136
+ var require_adaptive_probe_routes = __commonJS({
396137
+ "../../server/backend/dist/api/health/adaptive-probe.routes.js"(exports) {
396138
+ "use strict";
396139
+ Object.defineProperty(exports, "__esModule", { value: true });
396140
+ exports.ADAPTIVE_PROBE_BYTES = void 0;
396141
+ exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
396142
+ exports.ADAPTIVE_PROBE_BYTES = 128 * 1024;
396143
+ var BODY = Buffer.alloc(exports.ADAPTIVE_PROBE_BYTES, 97);
396144
+ function registerAdaptiveProbeRoute(fastify) {
396145
+ fastify.get("/adaptive-probe", async (_req, reply) => {
396146
+ reply.header("cache-control", "no-store");
396147
+ reply.header("content-type", "application/octet-stream");
396148
+ return reply.send(BODY);
396149
+ });
396150
+ }
396151
+ }
396152
+ });
396153
+
395105
396154
  // ../../server/backend/dist/api/model-distributor.js
395106
396155
  var require_model_distributor = __commonJS({
395107
396156
  "../../server/backend/dist/api/model-distributor.js"(exports) {
@@ -402068,19 +403117,8 @@ var require_trpc_router = __commonJS({
402068
403117
  const relayOnly = FORCE_RELAY_REMOTE ? (0, client_ip_js_1.deriveRelayOnly)(clientClass) : false;
402069
403118
  return { ...input, relayOnly };
402070
403119
  }
402071
- var REMOTE_INITIAL_ADAPTIVE_TIER = "low";
402072
- function enrichHintsWithClientClass(input, clientClass) {
402073
- if (clientClass !== "remote")
402074
- return input;
402075
- const isAdaptive = input.target === void 0 || input.target.kind === "adaptive";
402076
- if (!isAdaptive)
402077
- return input;
402078
- if (input.hints?.prefersTier !== void 0)
402079
- return input;
402080
- return {
402081
- ...input,
402082
- hints: { ...input.hints, prefersTier: REMOTE_INITIAL_ADAPTIVE_TIER }
402083
- };
403120
+ function enrichHintsWithClientClass(input, _clientClass) {
403121
+ return input;
402084
403122
  }
402085
403123
  function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
402086
403124
  const userAgent = (0, client_ip_js_1.extractUserAgent)(ctx.req);
@@ -402418,7 +403456,8 @@ var require_boot_config = __commonJS({
402418
403456
  const pair = loadTlsCert(config.tls.certPath, config.tls.keyPath);
402419
403457
  tlsOptions = { key: pair.key, cert: pair.cert };
402420
403458
  } else {
402421
- const tlsResult = await ensureTlsCert(dataPath);
403459
+ const extraSans = [...core.readExtraSans?.(dataPath) ?? []];
403460
+ const tlsResult = await ensureTlsCert(dataPath, extraSans.length > 0 ? { extraSans } : void 0);
402422
403461
  tlsCert = tlsResult;
402423
403462
  logTlsCert(tlsResult);
402424
403463
  const pair = loadTlsCert(tlsResult.certPath, tlsResult.keyPath);
@@ -409742,7 +410781,13 @@ var require_manual_boot = __commonJS({
409742
410781
  });
409743
410782
  },
409744
410783
  async listen(port, host) {
409745
- await fastify.listen({ port, host });
410784
+ await fastify.listen({
410785
+ port,
410786
+ host,
410787
+ // Dual-stack when binding `::`. Positional listen() drops this and
410788
+ // on macOS/BSD `IPV6_V6ONLY` defaults to 1 — IPv4 clients die.
410789
+ ipv6Only: host === "::" ? false : void 0
410790
+ });
409746
410791
  },
409747
410792
  close
409748
410793
  };
@@ -409807,6 +410852,7 @@ var require_main4 = __commonJS({
409807
410852
  var addon_upload_1 = require_addon_upload();
409808
410853
  var auth_whoami_1 = require_auth_whoami();
409809
410854
  var health_routes_1 = require_health_routes();
410855
+ var adaptive_probe_routes_1 = require_adaptive_probe_routes();
409810
410856
  var model_distributor_js_1 = require_model_distributor();
409811
410857
  var oauth2_routes_js_1 = require_oauth2_routes();
409812
410858
  var server_upload_1 = require_server_upload();
@@ -410044,6 +411090,7 @@ var require_main4 = __commonJS({
410044
411090
  verifyToken: (token2) => app.get(auth_service_1.AuthService).verifyToken(token2)
410045
411091
  });
410046
411092
  console.log(`[bootstrap] Health routes registered (hub v${hubVersion})`);
411093
+ (0, adaptive_probe_routes_1.registerAdaptiveProbeRoute)(fastify);
410047
411094
  } catch (err) {
410048
411095
  console.warn("[bootstrap] Failed to register health routes:", err);
410049
411096
  }
@@ -410281,12 +411328,12 @@ var require_main4 = __commonJS({
410281
411328
  } catch {
410282
411329
  return reply.status(401).send({ error: "invalid token" });
410283
411330
  }
410284
- const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec);
411331
+ const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec, { secure: request.protocol === "https" });
410285
411332
  reply.setCookie(c.name, c.value, c.options);
410286
411333
  return reply.send({ ok: true });
410287
411334
  });
410288
- fastify.delete("/api/auth/session", async (_request, reply) => {
410289
- const c = (0, session_cookie_js_1.clearSessionCookie)();
411335
+ fastify.delete("/api/auth/session", async (request, reply) => {
411336
+ const c = (0, session_cookie_js_1.clearSessionCookie)({ secure: request.protocol === "https" });
410290
411337
  reply.setCookie(c.name, c.value, c.options);
410291
411338
  return reply.send({ ok: true });
410292
411339
  });
@@ -410306,7 +411353,7 @@ var require_main4 = __commonJS({
410306
411353
  } catch {
410307
411354
  return reply.status(401).send({ error: "invalid token" });
410308
411355
  }
410309
- const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec);
411356
+ const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec, { secure: request.protocol === "https" });
410310
411357
  reply.setCookie(c.name, c.value, c.options);
410311
411358
  return reply.redirect(next);
410312
411359
  });
@@ -410571,7 +411618,7 @@ var require_main4 = __commonJS({
410571
411618
  const url = request.url;
410572
411619
  if ((0, spa_static_1.isRetiredPublicPath)(url))
410573
411620
  return reply.callNotFound();
410574
- if (url.startsWith("/trpc") || url.startsWith("/api/") || url.startsWith("/agent") || url.startsWith("/health") || url.startsWith("/viewer")) {
411621
+ if (url.startsWith("/trpc") || url.startsWith("/api/") || url.startsWith("/agent") || url.startsWith("/health") || url.startsWith("/adaptive-probe") || url.startsWith("/viewer")) {
410575
411622
  return reply.callNotFound();
410576
411623
  }
410577
411624
  const { staticDir, indexPath } = adminUiState;
@@ -410661,7 +411708,16 @@ var require_main4 = __commonJS({
410661
411708
  }
410662
411709
  };
410663
411710
  try {
410664
- await app.listen(port, host);
411711
+ const listenHost = (0, system_1.allFamiliesListenHost)(host).host;
411712
+ try {
411713
+ await app.listen(port, listenHost);
411714
+ } catch (listenErr) {
411715
+ if (listenHost === "::" && host !== "::") {
411716
+ await app.listen(port, "0.0.0.0");
411717
+ } else {
411718
+ throw listenErr;
411719
+ }
411720
+ }
410665
411721
  } catch (listenErr) {
410666
411722
  if (listenErr !== null && typeof listenErr === "object" && "code" in listenErr && listenErr.code === "EADDRINUSE") {
410667
411723
  console.error(`[bootstrap] FATAL: Port ${port} is already in use. Stop the other process or change server.port in config.yaml.`);
@@ -410672,6 +411728,26 @@ var require_main4 = __commonJS({
410672
411728
  const logger = app.get(logging_service_1.LoggingService).createLogger("System");
410673
411729
  const protocol = tlsOptions ? "https" : "http";
410674
411730
  logger.info("CamStack server listening", { meta: { protocol, host, port, trpcRegistered } });
411731
+ (0, system_1.registerLanHttpHandler)({
411732
+ onRequest: (req, res) => {
411733
+ fastify.server.emit("request", req, res);
411734
+ },
411735
+ onUpgrade: (req, socket, head) => {
411736
+ fastify.server.emit("upgrade", req, socket, head);
411737
+ }
411738
+ });
411739
+ try {
411740
+ const lanHttp = await (0, system_1.bindPendingLanHttp)();
411741
+ if (lanHttp.listening) {
411742
+ logger.info("LAN HTTP listening", { meta: { port: lanHttp.port } });
411743
+ } else if (lanHttp.error) {
411744
+ logger.warn("LAN HTTP not bound", { meta: { error: lanHttp.error, port: lanHttp.port } });
411745
+ }
411746
+ } catch (err) {
411747
+ logger.warn("LAN HTTP bind failed", {
411748
+ meta: { error: err instanceof Error ? err.message : String(err) }
411749
+ });
411750
+ }
410675
411751
  void Promise.all([resolveAdminUi(), resolveViewerUi()]);
410676
411752
  const postBoot = app.get(post_boot_service_1.PostBootService);
410677
411753
  await postBoot.run({ port, host, dataPath, trpcRegistered, tlsCert });