camstack 1.2.37 → 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-C1Aea3c6.js
23635
- var require_dist_C1Aea3c6 = __commonJS({
23636
- "../system/dist/dist-C1Aea3c6.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) {
@@ -23641,6 +23641,7 @@ var require_dist_C1Aea3c6 = __commonJS({
23641
23641
  EventCategory2["SystemAddonsReady"] = "system.addons-ready";
23642
23642
  EventCategory2["SystemRestarting"] = "system.restarting";
23643
23643
  EventCategory2["SystemRestartCompleted"] = "system.restart-completed";
23644
+ EventCategory2["SystemTlsCertChanged"] = "system.tls-cert-changed";
23644
23645
  EventCategory2["UpdateAvailable"] = "update.available";
23645
23646
  EventCategory2["SystemReadyState"] = "system.ready-state";
23646
23647
  EventCategory2["AddonStarted"] = "addon.started";
@@ -26255,6 +26256,15 @@ var require_dist_C1Aea3c6 = __commonJS({
26255
26256
  description: zod.z.string().optional(),
26256
26257
  icon: zod.z.string().optional()
26257
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
+ });
26258
26268
  var MODEL_FORMATS = [
26259
26269
  "onnx",
26260
26270
  "coreml",
@@ -26403,7 +26413,13 @@ var require_dist_C1Aea3c6 = __commonJS({
26403
26413
  * `id` stays the source of truth for resolution/download/persistence; grouping
26404
26414
  * is a presentation overlay resolved back to an `id`.
26405
26415
  */
26406
- 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()
26407
26423
  });
26408
26424
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
26409
26425
  format: zod.z.literal("openvino"),
@@ -26432,7 +26448,8 @@ var require_dist_C1Aea3c6 = __commonJS({
26432
26448
  "ocr",
26433
26449
  "segmentation"
26434
26450
  ]),
26435
- faceAlignment: zod.z.boolean().optional()
26451
+ faceAlignment: zod.z.boolean().optional(),
26452
+ classMap: ClassMapDefinitionSchema.optional()
26436
26453
  });
26437
26454
  var ConvertArtifactSchema = zod.z.object({
26438
26455
  format: zod.z.enum(MODEL_FORMATS),
@@ -35796,6 +35813,33 @@ var require_dist_C1Aea3c6 = __commonJS({
35796
35813
  h: zod.z.number()
35797
35814
  })
35798
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
+ });
35799
35843
  var ModelFormatSchema$1 = zod.z.enum([
35800
35844
  "onnx",
35801
35845
  "coreml",
@@ -36095,7 +36139,7 @@ var require_dist_C1Aea3c6 = __commonJS({
36095
36139
  * legacy call shape used by existing benchmark code; once all
36096
36140
  * callers pass it explicitly we make it required.
36097
36141
  *
36098
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
36142
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
36099
36143
  * `referenceImage` must be provided:
36100
36144
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
36101
36145
  * Carries the raw buffer, dimensions, and format; the executor
@@ -36117,6 +36161,12 @@ var require_dist_C1Aea3c6 = __commonJS({
36117
36161
  steps: zod.z.array(PipelineStepInputSchema).min(1),
36118
36162
  frame: FrameInputSchema.optional(),
36119
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
+ /**
36120
36170
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
36121
36171
  * the decoded pixels live in. One more member of the one-of
36122
36172
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -36419,7 +36469,10 @@ var require_dist_C1Aea3c6 = __commonJS({
36419
36469
  * Which source served this crop, so a quality-sensitive consumer (the native
36420
36470
  * `keyFrame`) can reject a degraded fallback:
36421
36471
  * - `native` — cut from the decode worker's retained NATIVE surface (the
36422
- * 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`).
36423
36476
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
36424
36477
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
36425
36478
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -36779,12 +36832,41 @@ var require_dist_C1Aea3c6 = __commonJS({
36779
36832
  cpuCores: zod.z.number().optional()
36780
36833
  })
36781
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
+ });
36782
36863
  var RunnerLocalMetricsSchema = zod.z.object({
36783
36864
  nodeId: zod.z.string(),
36784
36865
  activeCameras: zod.z.number(),
36785
36866
  throttledCameras: zod.z.number(),
36786
36867
  avgInferenceTimeMs: zod.z.number(),
36787
- queueDepth: zod.z.number()
36868
+ queueDepth: zod.z.number(),
36869
+ frameLazy: FrameLazyMetricsSchema.optional()
36788
36870
  });
36789
36871
  var pipelineRunnerCapability = {
36790
36872
  name: "pipeline-runner",
@@ -38569,6 +38651,8 @@ var require_dist_C1Aea3c6 = __commonJS({
38569
38651
  endDownload: method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
38570
38652
  }
38571
38653
  };
38654
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
38655
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
38572
38656
  var TerminalSessionInfoSchema = zod.z.object({
38573
38657
  /** Opaque session id minted by the provider on `openSession`. */
38574
38658
  sessionId: zod.z.string(),
@@ -38584,7 +38668,14 @@ var require_dist_C1Aea3c6 = __commonJS({
38584
38668
  var TerminalProfileInfoSchema = zod.z.object({
38585
38669
  profileId: zod.z.string(),
38586
38670
  label: zod.z.string(),
38587
- 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()
38588
38679
  });
38589
38680
  var TerminalInstanceInfoSchema = zod.z.object({
38590
38681
  instanceId: zod.z.string(),
@@ -38593,7 +38684,12 @@ var require_dist_C1Aea3c6 = __commonJS({
38593
38684
  profileId: zod.z.string(),
38594
38685
  profileLabel: zod.z.string(),
38595
38686
  name: zod.z.string(),
38596
- 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
38597
38693
  });
38598
38694
  var TerminalLegacyCameraSchema = zod.z.object({
38599
38695
  stableId: zod.z.string(),
@@ -38632,7 +38728,24 @@ var require_dist_C1Aea3c6 = __commonJS({
38632
38728
  createInstance: method(zod.z.object({
38633
38729
  targetNodeId: zod.z.string().min(1),
38634
38730
  profileId: zod.z.string().min(1),
38635
- 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()
38636
38749
  }), TerminalInstanceInfoSchema, {
38637
38750
  kind: "mutation",
38638
38751
  auth: "admin"
@@ -38667,7 +38780,11 @@ var require_dist_C1Aea3c6 = __commonJS({
38667
38780
  openSession: method(zod.z.object({
38668
38781
  profileId: zod.z.string(),
38669
38782
  cols: zod.z.number().int().positive(),
38670
- 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()
38671
38788
  }), TerminalSessionInfoSchema, {
38672
38789
  kind: "mutation",
38673
38790
  auth: "admin"
@@ -42390,6 +42507,12 @@ var require_dist_C1Aea3c6 = __commonJS({
42390
42507
  /** What the ranking currently resolves to (null when nothing is reachable). */
42391
42508
  resolved: zod.z.string().nullable()
42392
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
+ });
42393
42516
  var AllowedAddressesSchema = zod.z.object({
42394
42517
  /**
42395
42518
  * Allowlist of interface addresses operators have explicitly opted
@@ -42399,6 +42522,20 @@ var require_dist_C1Aea3c6 = __commonJS({
42399
42522
  */
42400
42523
  addresses: zod.z.array(zod.z.string()).readonly()
42401
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
+ });
42402
42539
  var localNetworkCapability = {
42403
42540
  name: "local-network",
42404
42541
  scope: "system",
@@ -42418,13 +42555,13 @@ var require_dist_C1Aea3c6 = __commonJS({
42418
42555
  */
42419
42556
  getPreferred: method(zod.z.void(), PreferredSchema),
42420
42557
  /**
42421
- * Ordered candidate base URLs the SDK should try on connect.
42422
- * Includes LAN IPs (one per non-internal interface), the public
42423
- * tunnel hostname (when active), and loopback as a last-resort
42424
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
42425
- * Honours `getAllowedAddresses()` when set addresses outside
42426
- * the allowlist are dropped (the public tunnel + loopback are
42427
- * 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).
42428
42565
  *
42429
42566
  * **The port is the hub's, not the caller's** (D62 — a function's fact
42430
42567
  * belongs to whoever already owns it). This method used to take a `port`
@@ -42455,10 +42592,11 @@ var require_dist_C1Aea3c6 = __commonJS({
42455
42592
  */
42456
42593
  port: zod.z.number().int().min(1).max(65535).optional(),
42457
42594
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
42458
- * candidate. Default `true`. */
42595
+ * candidate. Default `false` — loopback is not a client route. */
42459
42596
  includeLoopback: zod.z.boolean().optional(),
42460
- /** Skip IPv6 entries. Some legacy clients can't parse them.
42461
- * 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`. */
42462
42600
  ipv4Only: zod.z.boolean().optional(),
42463
42601
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
42464
42602
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -42487,6 +42625,19 @@ var require_dist_C1Aea3c6 = __commonJS({
42487
42625
  */
42488
42626
  setNotificationEndpoint: method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
42489
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
+ /**
42490
42641
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
42491
42642
  * by the admin UI's address selector to seed its checkbox state.
42492
42643
  */
@@ -42504,7 +42655,34 @@ var require_dist_C1Aea3c6 = __commonJS({
42504
42655
  * when the operator wants to wipe their manual edits and start
42505
42656
  * over from the auto-detected best matches.
42506
42657
  */
42507
- 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
+ })
42508
42686
  },
42509
42687
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
42510
42688
  mount: { kind: "hub-only" }
@@ -49868,6 +50046,12 @@ var require_dist_C1Aea3c6 = __commonJS({
49868
50046
  addonId: null,
49869
50047
  access: "create"
49870
50048
  },
50049
+ "localNetwork.downloadCa": {
50050
+ capName: "local-network",
50051
+ capScope: "system",
50052
+ addonId: null,
50053
+ access: "view"
50054
+ },
49871
50055
  "localNetwork.getAllowedAddresses": {
49872
50056
  capName: "local-network",
49873
50057
  capScope: "system",
@@ -49892,18 +50076,42 @@ var require_dist_C1Aea3c6 = __commonJS({
49892
50076
  addonId: null,
49893
50077
  access: "view"
49894
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
+ },
49895
50091
  "localNetwork.list": {
49896
50092
  capName: "local-network",
49897
50093
  capScope: "system",
49898
50094
  addonId: null,
49899
50095
  access: "view"
49900
50096
  },
50097
+ "localNetwork.regenerateCertificate": {
50098
+ capName: "local-network",
50099
+ capScope: "system",
50100
+ addonId: null,
50101
+ access: "create"
50102
+ },
49901
50103
  "localNetwork.resetAllowlistToBestMatch": {
49902
50104
  capName: "local-network",
49903
50105
  capScope: "system",
49904
50106
  addonId: null,
49905
50107
  access: "delete"
49906
50108
  },
50109
+ "localNetwork.revertToGeneratedCertificate": {
50110
+ capName: "local-network",
50111
+ capScope: "system",
50112
+ addonId: null,
50113
+ access: "create"
50114
+ },
49907
50115
  "localNetwork.setAllowedAddresses": {
49908
50116
  capName: "local-network",
49909
50117
  capScope: "system",
@@ -49916,6 +50124,18 @@ var require_dist_C1Aea3c6 = __commonJS({
49916
50124
  addonId: null,
49917
50125
  access: "create"
49918
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
+ },
49919
50139
  "lockControl.lock": {
49920
50140
  capName: "lock-control",
49921
50141
  capScope: "device",
@@ -52796,6 +53016,12 @@ var require_dist_C1Aea3c6 = __commonJS({
52796
53016
  addonId: null,
52797
53017
  access: "create"
52798
53018
  },
53019
+ "terminalSession.updateInstance": {
53020
+ capName: "terminal-session",
53021
+ capScope: "system",
53022
+ addonId: null,
53023
+ access: "create"
53024
+ },
52799
53025
  "terminalSession.writeInput": {
52800
53026
  capName: "terminal-session",
52801
53027
  capScope: "system",
@@ -55424,6 +55650,35 @@ var require_dist_C1Aea3c6 = __commonJS({
55424
55650
  }]
55425
55651
  }].map((s) => [s.stepId, s.defaultModelId])));
55426
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({});
55427
55682
  zod.z.object({
55428
55683
  /**
55429
55684
  * Fraction of the box's own size added on EACH side before cutting.
@@ -56255,7 +56510,7 @@ var require_alerts_addon = __commonJS({
56255
56510
  [Symbol.toStringTag]: { value: "Module" }
56256
56511
  });
56257
56512
  require_chunk_Cek0wNdY();
56258
- var require_dist10 = require_dist_C1Aea3c6();
56513
+ var require_dist10 = require_dist_C2_1HCpW();
56259
56514
  function selectExpired(alerts, cutoffMs) {
56260
56515
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
56261
56516
  }
@@ -56307,6 +56562,10 @@ var require_alerts_addon = __commonJS({
56307
56562
  severity: "warning",
56308
56563
  titleTemplate: "System restarting"
56309
56564
  },
56565
+ "system.tls-cert-changed": {
56566
+ severity: "warning",
56567
+ titleTemplate: "TLS certificate changed"
56568
+ },
56310
56569
  "device.registered": {
56311
56570
  severity: "info",
56312
56571
  titleTemplate: "Device registered"
@@ -56795,6 +57054,8 @@ var require_alerts_addon = __commonJS({
56795
57054
  return `Storage critical for device "${deviceId ?? "unknown"}"`;
56796
57055
  case "system.boot":
56797
57056
  return `System booted in "${data.mode ?? "unknown"}" mode`;
57057
+ case "system.tls-cert-changed":
57058
+ return data.caRotated === true ? `TLS certificate reissued (${String(data.reason)}) \u2014 the local CA also changed. Re-install ${String(data.caCertPath)} on any device that trusted the old one.` : `TLS certificate reissued (${String(data.reason)}) \u2014 the local CA is unchanged, previously trusted devices keep working.`;
56798
57059
  case "process.crashed":
56799
57060
  return `Process "${processId ?? "unknown"}" crashed`;
56800
57061
  default:
@@ -57068,7 +57329,7 @@ var require_console_logging = __commonJS({
57068
57329
  [Symbol.toStringTag]: { value: "Module" }
57069
57330
  });
57070
57331
  require_chunk_Cek0wNdY();
57071
- var require_dist10 = require_dist_C1Aea3c6();
57332
+ var require_dist10 = require_dist_C2_1HCpW();
57072
57333
  var require_formatter = require_formatter_DqAKDlvN();
57073
57334
  var LEVEL_RANK = {
57074
57335
  debug: 0,
@@ -57162,7 +57423,7 @@ var require_core_blocks_addon = __commonJS({
57162
57423
  "use strict";
57163
57424
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
57164
57425
  var require_chunk = require_chunk_Cek0wNdY();
57165
- var require_dist10 = require_dist_C1Aea3c6();
57426
+ var require_dist10 = require_dist_C2_1HCpW();
57166
57427
  var node_crypto = __require("crypto");
57167
57428
  var node_fs_promises = __require("fs/promises");
57168
57429
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -58059,11 +58320,11 @@ var require_core_blocks = __commonJS({
58059
58320
  }
58060
58321
  });
58061
58322
 
58062
- // ../system/dist/retired-settings-keys-B52KsNz8.js
58063
- var require_retired_settings_keys_B52KsNz8 = __commonJS({
58064
- "../system/dist/retired-settings-keys-B52KsNz8.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) {
58065
58326
  "use strict";
58066
- var require_dist10 = require_dist_C1Aea3c6();
58327
+ var require_dist10 = require_dist_C2_1HCpW();
58067
58328
  function settingsStoreIsAuthoritativeHere(env) {
58068
58329
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
58069
58330
  return raw === "" || raw === "hub";
@@ -60106,8 +60367,8 @@ var require_device_manager_addon = __commonJS({
60106
60367
  [Symbol.toStringTag]: { value: "Module" }
60107
60368
  });
60108
60369
  require_chunk_Cek0wNdY();
60109
- var require_dist10 = require_dist_C1Aea3c6();
60110
- var require_retired_settings_keys = require_retired_settings_keys_B52KsNz8();
60370
+ var require_dist10 = require_dist_C2_1HCpW();
60371
+ var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
60111
60372
  var node_crypto = __require("crypto");
60112
60373
  var _camstack_types_node = require_node();
60113
60374
  var JOB_HISTORY = 20;
@@ -64434,7 +64695,7 @@ var require_hub_forwarder = __commonJS({
64434
64695
  [Symbol.toStringTag]: { value: "Module" }
64435
64696
  });
64436
64697
  require_chunk_Cek0wNdY();
64437
- var require_dist10 = require_dist_C1Aea3c6();
64698
+ var require_dist10 = require_dist_C2_1HCpW();
64438
64699
  var require_formatter = require_formatter_DqAKDlvN();
64439
64700
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
64440
64701
  var HubForwarderDestination = class {
@@ -64571,7 +64832,7 @@ var require_liveness_monitor_addon = __commonJS({
64571
64832
  "use strict";
64572
64833
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
64573
64834
  require_chunk_Cek0wNdY();
64574
- var require_dist10 = require_dist_C1Aea3c6();
64835
+ var require_dist10 = require_dist_C2_1HCpW();
64575
64836
  var NO_DEVICES = "liveness:no-devices";
64576
64837
  var ALL_OFFLINE = "liveness:all-devices-offline";
64577
64838
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -64761,7 +65022,7 @@ var require_local_auth_addon = __commonJS({
64761
65022
  [Symbol.toStringTag]: { value: "Module" }
64762
65023
  });
64763
65024
  var require_chunk = require_chunk_Cek0wNdY();
64764
- var require_dist10 = require_dist_C1Aea3c6();
65025
+ var require_dist10 = require_dist_C2_1HCpW();
64765
65026
  var node_crypto = __require("crypto");
64766
65027
  node_crypto = require_chunk.__toESM(node_crypto);
64767
65028
  var crypto$1 = __require("crypto");
@@ -72445,7 +72706,7 @@ var require_loki_logging = __commonJS({
72445
72706
  [Symbol.toStringTag]: { value: "Module" }
72446
72707
  });
72447
72708
  require_chunk_Cek0wNdY();
72448
- var require_dist10 = require_dist_C1Aea3c6();
72709
+ var require_dist10 = require_dist_C2_1HCpW();
72449
72710
  function sanitizeLabelName(raw) {
72450
72711
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
72451
72712
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -73010,7 +73271,7 @@ var require_native_metrics_addon = __commonJS({
73010
73271
  [Symbol.toStringTag]: { value: "Module" }
73011
73272
  });
73012
73273
  var require_chunk = require_chunk_Cek0wNdY();
73013
- var require_dist10 = require_dist_C1Aea3c6();
73274
+ var require_dist10 = require_dist_C2_1HCpW();
73014
73275
  var node_child_process = __require("child_process");
73015
73276
  var node_util = __require("util");
73016
73277
  var node_os = __require("os");
@@ -73952,7 +74213,7 @@ var require_filesystem_storage_addon = __commonJS({
73952
74213
  [Symbol.toStringTag]: { value: "Module" }
73953
74214
  });
73954
74215
  var require_chunk = require_chunk_Cek0wNdY();
73955
- var require_dist10 = require_dist_C1Aea3c6();
74216
+ var require_dist10 = require_dist_C2_1HCpW();
73956
74217
  var node_crypto = __require("crypto");
73957
74218
  var node_fs_promises = __require("fs/promises");
73958
74219
  var node_path = __require("path");
@@ -75068,8 +75329,8 @@ var require_sqlite_settings_addon = __commonJS({
75068
75329
  [Symbol.toStringTag]: { value: "Module" }
75069
75330
  });
75070
75331
  var require_chunk = require_chunk_Cek0wNdY();
75071
- var require_dist10 = require_dist_C1Aea3c6();
75072
- var require_retired_settings_keys = require_retired_settings_keys_B52KsNz8();
75332
+ var require_dist10 = require_dist_C2_1HCpW();
75333
+ var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
75073
75334
  var node_crypto = __require("crypto");
75074
75335
  var node_fs = __require("fs");
75075
75336
  var node_module = __require("module");
@@ -76613,7 +76874,7 @@ var require_storage_orchestrator_addon = __commonJS({
76613
76874
  [Symbol.toStringTag]: { value: "Module" }
76614
76875
  });
76615
76876
  var require_chunk = require_chunk_Cek0wNdY();
76616
- var require_dist10 = require_dist_C1Aea3c6();
76877
+ var require_dist10 = require_dist_C2_1HCpW();
76617
76878
  var node_crypto = __require("crypto");
76618
76879
  var node_fs_promises = __require("fs/promises");
76619
76880
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -78492,7 +78753,7 @@ var require_system_config_addon = __commonJS({
78492
78753
  [Symbol.toStringTag]: { value: "Module" }
78493
78754
  });
78494
78755
  require_chunk_Cek0wNdY();
78495
- var require_dist10 = require_dist_C1Aea3c6();
78756
+ var require_dist10 = require_dist_C2_1HCpW();
78496
78757
  var SECTION_TITLES = {
78497
78758
  server: "Server",
78498
78759
  auth: "Authentication"
@@ -96553,7 +96814,7 @@ var require_winston_logging = __commonJS({
96553
96814
  [Symbol.toStringTag]: { value: "Module" }
96554
96815
  });
96555
96816
  var require_chunk = require_chunk_Cek0wNdY();
96556
- var require_dist10 = require_dist_C1Aea3c6();
96817
+ var require_dist10 = require_dist_C2_1HCpW();
96557
96818
  var require_formatter = require_formatter_DqAKDlvN();
96558
96819
  var node_path = __require("path");
96559
96820
  node_path = require_chunk.__toESM(node_path);
@@ -96690,9 +96951,9 @@ var require_winston_logging = __commonJS({
96690
96951
  }
96691
96952
  });
96692
96953
 
96693
- // ../system/dist/file-data-plane-DUHPHa-Y.js
96694
- var require_file_data_plane_DUHPHa_Y = __commonJS({
96695
- "../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) {
96696
96957
  "use strict";
96697
96958
  var require_chunk = require_chunk_Cek0wNdY();
96698
96959
  var node_crypto = __require("crypto");
@@ -96725,15 +96986,56 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96725
96986
  if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
96726
96987
  return headers;
96727
96988
  }
96728
- 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) {
96729
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;
96730
97005
  node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
96731
97006
  const tmpPath = destPath + ".downloading";
96732
97007
  try {
96733
- const response = await fetch(url, {
96734
- redirect: "follow",
96735
- headers: buildHeaders(url)
96736
- });
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}`);
96737
97039
  if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
96738
97040
  if (!response.body) throw new Error(`No response body from ${url}`);
96739
97041
  const total = parseInt(response.headers.get("content-length") ?? "0", 10);
@@ -96744,9 +97046,10 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96744
97046
  for (; ; ) {
96745
97047
  const { done, value } = await reader.read();
96746
97048
  if (done || !value) break;
96747
- fileStream.write(value);
96748
97049
  downloaded += value.length;
96749
- 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);
96750
97053
  }
96751
97054
  } finally {
96752
97055
  fileStream.end();
@@ -97541,15 +97844,16 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
97541
97844
  }
97542
97845
  });
97543
97846
 
97544
- // ../types/dist/event-category-CRPORAAz.js
97545
- var require_event_category_CRPORAAz = __commonJS({
97546
- "../types/dist/event-category-CRPORAAz.js"(exports) {
97847
+ // ../types/dist/event-category-EY0GNjV9.js
97848
+ var require_event_category_EY0GNjV9 = __commonJS({
97849
+ "../types/dist/event-category-EY0GNjV9.js"(exports) {
97547
97850
  "use strict";
97548
97851
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
97549
97852
  EventCategory2["SystemBoot"] = "system.boot";
97550
97853
  EventCategory2["SystemAddonsReady"] = "system.addons-ready";
97551
97854
  EventCategory2["SystemRestarting"] = "system.restarting";
97552
97855
  EventCategory2["SystemRestartCompleted"] = "system.restart-completed";
97856
+ EventCategory2["SystemTlsCertChanged"] = "system.tls-cert-changed";
97553
97857
  EventCategory2["UpdateAvailable"] = "update.available";
97554
97858
  EventCategory2["SystemReadyState"] = "system.ready-state";
97555
97859
  EventCategory2["AddonStarted"] = "addon.started";
@@ -97707,11 +98011,11 @@ var require_event_category_CRPORAAz = __commonJS({
97707
98011
  }
97708
98012
  });
97709
98013
 
97710
- // ../types/dist/sleep-CMRLJj2e.js
97711
- var require_sleep_CMRLJj2e = __commonJS({
97712
- "../types/dist/sleep-CMRLJj2e.js"(exports) {
98014
+ // ../types/dist/sleep-C2XhJhkd.js
98015
+ var require_sleep_C2XhJhkd = __commonJS({
98016
+ "../types/dist/sleep-C2XhJhkd.js"(exports) {
97713
98017
  "use strict";
97714
- var require_event_category = require_event_category_CRPORAAz();
98018
+ var require_event_category = require_event_category_EY0GNjV9();
97715
98019
  var zod = require_zod();
97716
98020
  var WELL_KNOWN_TABS = [
97717
98021
  {
@@ -101148,8 +101452,8 @@ var require_addon = __commonJS({
101148
101452
  "../types/dist/addon.js"(exports) {
101149
101453
  "use strict";
101150
101454
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
101151
- var require_event_category = require_event_category_CRPORAAz();
101152
- var require_sleep = require_sleep_CMRLJj2e();
101455
+ var require_event_category = require_event_category_EY0GNjV9();
101456
+ var require_sleep = require_sleep_C2XhJhkd();
101153
101457
  var require_err_msg = require_err_msg_COpsHMw2();
101154
101458
  var CAP_INPUT_DEFAULTS = Object.freeze({
101155
101459
  "addons": { "getLogs": { "limit": 100 } },
@@ -108023,9 +108327,9 @@ var require_dist2 = __commonJS({
108023
108327
  }
108024
108328
  });
108025
108329
 
108026
- // ../system/dist/manifest-python-deps-MA_BZGBz.js
108027
- var require_manifest_python_deps_MA_BZGBz = __commonJS({
108028
- "../system/dist/manifest-python-deps-MA_BZGBz.js"(exports) {
108330
+ // ../system/dist/manifest-python-deps-CwBbX4Ut.js
108331
+ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108332
+ "../system/dist/manifest-python-deps-CwBbX4Ut.js"(exports) {
108029
108333
  "use strict";
108030
108334
  var require_chunk = require_chunk_Cek0wNdY();
108031
108335
  var node_crypto = __require("crypto");
@@ -108046,8 +108350,8 @@ var require_manifest_python_deps_MA_BZGBz = __commonJS({
108046
108350
  var node_vm = __require("vm");
108047
108351
  node_vm = require_chunk.__toESM(node_vm);
108048
108352
  var _camstack_types_addon = require_addon();
108049
- var _trpc_client = require_dist2();
108050
108353
  var node_net = __require("net");
108354
+ var _trpc_client = require_dist2();
108051
108355
  var HEAP_WATCH_INTERVAL_MS = 6e4;
108052
108356
  var HEAP_WATCH_WARN_RATIO = 0.8;
108053
108357
  var HEAP_WATCH_ESCALATE_RATIO = 0.7;
@@ -115030,6 +115334,752 @@ var require_manifest_python_deps_MA_BZGBz = __commonJS({
115030
115334
  }
115031
115335
  });
115032
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
+
115033
116083
  // ../system/dist/custom-action-registry-jY0NOZK8.js
115034
116084
  var require_custom_action_registry_jY0NOZK8 = __commonJS({
115035
116085
  "../system/dist/custom-action-registry-jY0NOZK8.js"(exports) {
@@ -118829,7 +119879,7 @@ var require_dist3 = __commonJS({
118829
119879
  "use strict";
118830
119880
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
118831
119881
  var require_chunk = require_chunk_Cek0wNdY();
118832
- var require_dist10 = require_dist_C1Aea3c6();
119882
+ var require_dist10 = require_dist_C2_1HCpW();
118833
119883
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
118834
119884
  require_alerts();
118835
119885
  var require_formatter = require_formatter_DqAKDlvN();
@@ -118853,9 +119903,10 @@ var require_dist3 = __commonJS({
118853
119903
  var require_builtins_system_config_system_config_addon = require_system_config_addon();
118854
119904
  require_system_config();
118855
119905
  var require_builtins_winston_logging_index = require_winston_logging();
118856
- var require_file_data_plane = require_file_data_plane_DUHPHa_Y();
118857
- var require_manifest_python_deps = require_manifest_python_deps_MA_BZGBz();
119906
+ var require_file_data_plane = require_file_data_plane_DO8KbxCe();
119907
+ var require_manifest_python_deps = require_manifest_python_deps_CwBbX4Ut();
118858
119908
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
119909
+ var require_lan_http_bind = require_lan_http_bind_DmgpFP6();
118859
119910
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
118860
119911
  var zod = require_zod();
118861
119912
  var node_crypto = __require("crypto");
@@ -120160,7 +121211,7 @@ var require_dist3 = __commonJS({
120160
121211
  if (node.children) for (const child of node.children) this.validateNode(child, errors, warnings);
120161
121212
  }
120162
121213
  };
120163
- var execFileAsync$4 = (0, node_util.promisify)(node_child_process.execFile);
121214
+ var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120164
121215
  var PythonEnvManager = class {
120165
121216
  venvPath;
120166
121217
  cachedProbe = null;
@@ -120170,12 +121221,12 @@ var require_dist3 = __commonJS({
120170
121221
  async probe() {
120171
121222
  if (this.cachedProbe) return this.cachedProbe;
120172
121223
  for (const cmd of ["python3", "python"]) try {
120173
- const { stdout } = await execFileAsync$4(cmd, ["--version"]);
121224
+ const { stdout } = await execFileAsync$3(cmd, ["--version"]);
120174
121225
  const version2 = stdout.trim().replace("Python ", "");
120175
121226
  const major = parseInt(version2.split(".")[0] ?? "0", 10);
120176
121227
  const minor = parseInt(version2.split(".")[1] ?? "0", 10);
120177
121228
  if (major < 3 || major === 3 && minor < 10) continue;
120178
- 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)"]);
120179
121230
  this.cachedProbe = {
120180
121231
  available: true,
120181
121232
  version: version2,
@@ -120191,13 +121242,13 @@ var require_dist3 = __commonJS({
120191
121242
  async ensure(options) {
120192
121243
  const probe = await this.probe();
120193
121244
  if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
120194
- 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, [
120195
121246
  "-m",
120196
121247
  "venv",
120197
121248
  this.venvPath
120198
121249
  ]);
120199
121250
  const venvPython = node_path.join(this.venvPath, "bin", "python");
120200
- if (options.packages.length > 0) await execFileAsync$4(venvPython, [
121251
+ if (options.packages.length > 0) await execFileAsync$3(venvPython, [
120201
121252
  "-m",
120202
121253
  "pip",
120203
121254
  "install",
@@ -120639,71 +121690,6 @@ var require_dist3 = __commonJS({
120639
121690
  };
120640
121691
  }
120641
121692
  };
120642
- var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120643
- async function ensureTlsCert(dataDir, options) {
120644
- const tlsDir = (0, node_path.join)(dataDir, "tls");
120645
- const certPath = (0, node_path.join)(tlsDir, "camstack.crt");
120646
- const keyPath = (0, node_path.join)(tlsDir, "camstack.key");
120647
- if ((0, node_fs.existsSync)(certPath) && (0, node_fs.existsSync)(keyPath)) try {
120648
- const x509 = new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath));
120649
- if (new Date(x509.validTo) > /* @__PURE__ */ new Date()) return {
120650
- certPath,
120651
- keyPath,
120652
- generated: false
120653
- };
120654
- } catch {
120655
- }
120656
- (0, node_fs.mkdirSync)(tlsDir, { recursive: true });
120657
- const cn = options?.commonName ?? "camstack.local";
120658
- const validDays = options?.validDays ?? 825;
120659
- const sanDns = /* @__PURE__ */ new Set([
120660
- "localhost",
120661
- cn,
120662
- node_os.hostname()
120663
- ]);
120664
- const sanIps = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
120665
- const interfaces = node_os.networkInterfaces();
120666
- for (const addrs of Object.values(interfaces)) {
120667
- if (!addrs) continue;
120668
- for (const addr of addrs) if (!addr.internal) sanIps.add(addr.address);
120669
- }
120670
- for (const san of options?.extraSans ?? []) if (san.match(/^\d+\.\d+\.\d+\.\d+$/) || san.includes(":")) sanIps.add(san);
120671
- else sanDns.add(san);
120672
- const sanParts = [];
120673
- for (const dns of sanDns) sanParts.push(`DNS:${dns}`);
120674
- for (const ip of sanIps) sanParts.push(`IP:${ip}`);
120675
- const sanString = sanParts.join(",");
120676
- await execFileAsync$3("openssl", [
120677
- "req",
120678
- "-x509",
120679
- "-newkey",
120680
- "rsa:2048",
120681
- "-keyout",
120682
- keyPath,
120683
- "-out",
120684
- certPath,
120685
- "-days",
120686
- String(validDays),
120687
- "-nodes",
120688
- "-subj",
120689
- `/CN=${cn}`,
120690
- "-addext",
120691
- `subjectAltName=${sanString}`
120692
- ]);
120693
- const { chmod } = await import("fs/promises");
120694
- await chmod(keyPath, 384);
120695
- return {
120696
- certPath,
120697
- keyPath,
120698
- generated: true
120699
- };
120700
- }
120701
- function loadTlsCert(certPath, keyPath) {
120702
- return {
120703
- cert: (0, node_fs.readFileSync)(certPath),
120704
- key: (0, node_fs.readFileSync)(keyPath)
120705
- };
120706
- }
120707
121693
  function serializeSetting(value) {
120708
121694
  if (typeof value === "number") return {
120709
121695
  value: String(value),
@@ -198975,6 +199961,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
198975
199961
  exports.AlertCenterAddon = require_builtins_alerts_alerts_addon.AlertCenterAddon;
198976
199962
  exports.ApiKeyManager = require_builtins_local_auth_local_auth_addon.ApiKeyManager;
198977
199963
  exports.AuthManager = require_builtins_local_auth_local_auth_addon.AuthManager;
199964
+ exports.CA_COMMON_NAME = require_lan_http_bind.CA_COMMON_NAME;
199965
+ exports.CA_VALIDITY_DAYS = require_lan_http_bind.CA_VALIDITY_DAYS;
198978
199966
  exports.CLUSTER_SECRET_MISMATCH_TYPE = CLUSTER_SECRET_MISMATCH_TYPE;
198979
199967
  exports.CLUSTER_SECRET_REJECTED_EXIT_CODE = CLUSTER_SECRET_REJECTED_EXIT_CODE;
198980
199968
  exports.CORE_CAP_SERVICE_NAME = CORE_CAP_SERVICE_NAME;
@@ -198991,6 +199979,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
198991
199979
  exports.CoreBlocksAddon = require_builtins_core_blocks_core_blocks_addon.CoreBlocksAddon;
198992
199980
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
198993
199981
  exports.DEFAULT_DATA_PATH = DEFAULT_DATA_PATH;
199982
+ exports.DEFAULT_LAN_HTTP_PORT = require_lan_http_bind.DEFAULT_LAN_HTTP_PORT;
198994
199983
  exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_dist10.DEVICE_SETTINGS_CONTRIBUTION_METHODS;
198995
199984
  exports.DEVICE_STATUS_METHOD = require_dist10.DEVICE_STATUS_METHOD;
198996
199985
  exports.DataPlaneRegistry = DataPlaneRegistry;
@@ -199021,6 +200010,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199021
200010
  exports.INFRA_CAPABILITIES = INFRA_CAPABILITIES;
199022
200011
  exports.IntegrationRegistry = IntegrationRegistry;
199023
200012
  exports.JobJournal = JobJournal;
200013
+ exports.LEAF_RENEWAL_WINDOW_DAYS = require_lan_http_bind.LEAF_RENEWAL_WINDOW_DAYS;
199024
200014
  exports.LifecycleJobEngine = LifecycleJobEngine;
199025
200015
  exports.LifecycleStateMachine = LifecycleStateMachine;
199026
200016
  exports.LivenessMonitorAddon = require_builtins_liveness_monitor_liveness_monitor_addon.LivenessMonitorAddon;
@@ -199031,6 +200021,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199031
200021
  exports.LogRingBuffer = LogRingBuffer;
199032
200022
  exports.LokiDestination = require_builtins_loki_logging_index.LokiDestination$1;
199033
200023
  exports.LokiLoggingAddon = require_builtins_loki_logging_index.LokiLoggingAddon$1;
200024
+ exports.MAX_LEAF_VALIDITY_DAYS = require_lan_http_bind.MAX_LEAF_VALIDITY_DAYS;
199034
200025
  exports.METHOD_ACCESS_MAP = require_dist10.METHOD_ACCESS_MAP;
199035
200026
  exports.ModelDownloadService = require_file_data_plane.ModelDownloadService;
199036
200027
  exports.NATIVE_PROVIDER_SERVICE_INFIX = require_manifest_python_deps.NATIVE_PROVIDER_SERVICE_INFIX;
@@ -199056,6 +200047,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199056
200047
  exports.ReadinessTimeoutError = require_dist10.ReadinessTimeoutError;
199057
200048
  exports.ReplEngine = ReplEngine;
199058
200049
  exports.RingBuffer = RingBuffer;
200050
+ exports.SERVER_AUTH_OID = require_lan_http_bind.SERVER_AUTH_OID;
199059
200051
  exports.ScopedLogger = ScopedLogger;
199060
200052
  exports.ScopedTokenManager = require_builtins_local_auth_local_auth_addon.ScopedTokenManager;
199061
200053
  exports.SocketChannel = require_manifest_python_deps.SocketChannel;
@@ -199079,6 +200071,9 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199079
200071
  exports.__resetCapUsageRegistryForTests = require_manifest_python_deps.__resetCapUsageRegistryForTests;
199080
200072
  exports.adaptBrokerToCluster = require_manifest_python_deps.adaptBrokerToCluster;
199081
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;
199082
200077
  exports.bootstrapSchema = bootstrapSchema;
199083
200078
  exports.brokerCallForCap = require_manifest_python_deps.brokerCallForCap;
199084
200079
  exports.brokerTransportLink = require_manifest_python_deps.brokerTransportLink;
@@ -199105,8 +200100,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199105
200100
  exports.classifyAddonDir = classifyAddonDir;
199106
200101
  exports.classifyCapRoute = require_manifest_python_deps.classifyCapRoute;
199107
200102
  exports.clearPendingRestart = clearPendingRestart;
200103
+ exports.closeLanHttp = require_lan_http_bind.closeLanHttp;
199108
200104
  exports.clusterEventTopic = require_manifest_python_deps.clusterEventTopic;
199109
200105
  exports.clusterSecretMatches = clusterSecretMatches;
200106
+ exports.collectCertIdentity = require_lan_http_bind.collectCertIdentity;
199110
200107
  exports.collectModelFiles = require_file_data_plane.collectModelFiles;
199111
200108
  exports.contentTypeFor = require_file_data_plane.contentTypeFor;
199112
200109
  exports.copyDirRecursive = copyDirRecursive;
@@ -199172,7 +200169,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199172
200169
  return _camstack_types_node.ensurePython;
199173
200170
  }
199174
200171
  });
199175
- exports.ensureTlsCert = ensureTlsCert;
200172
+ exports.ensureTlsCert = require_lan_http_bind.ensureTlsCert;
200173
+ exports.evaluateExistingCert = require_lan_http_bind.evaluateExistingCert;
199176
200174
  exports.expandCapMethods = require_dist10.expandCapMethods;
199177
200175
  exports.fetchJson = require_file_data_plane.fetchJson;
199178
200176
  Object.defineProperty(exports, "findInPath", {
@@ -199236,7 +200234,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199236
200234
  exports.isInfraCapability = isInfraCapability;
199237
200235
  exports.isModelDownloaded = require_file_data_plane.isModelDownloaded;
199238
200236
  exports.isSourceNewer = isSourceNewer;
199239
- exports.loadTlsCert = loadTlsCert;
200237
+ exports.loadTlsCert = require_lan_http_bind.loadTlsCert;
199240
200238
  exports.localEndpointPath = require_manifest_python_deps.localEndpointPath;
199241
200239
  exports.localProviderLink = require_manifest_python_deps.localProviderLink;
199242
200240
  exports.mountNativeCapService = require_manifest_python_deps.mountNativeCapService;
@@ -199245,9 +200243,15 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199245
200243
  exports.parseTokenizedUrl = require_file_data_plane.parseTokenizedUrl;
199246
200244
  exports.proxyToUpstream = proxyToUpstream;
199247
200245
  exports.quarantineAddonResidue = quarantineAddonResidue;
200246
+ exports.readExtraSans = require_lan_http_bind.readExtraSans;
200247
+ exports.readLanHttpState = require_lan_http_bind.readLanHttpState;
199248
200248
  exports.readPendingRestart = readPendingRestart;
200249
+ exports.readTlsAccessStatus = require_lan_http_bind.readTlsAccessStatus;
200250
+ exports.readTlsMode = require_lan_http_bind.readTlsMode;
199249
200251
  exports.readinessKey = require_dist10.readinessKey;
199250
200252
  exports.registerEventBusService = require_manifest_python_deps.registerEventBusService;
200253
+ exports.registerLanHttpHandler = require_lan_http_bind.registerLanHttpHandler;
200254
+ exports.reissueTlsLeaf = require_lan_http_bind.reissueTlsLeaf;
199251
200255
  exports.resolveFilePath = require_file_data_plane.resolveFilePath;
199252
200256
  exports.resolveHwAccel = require_manifest_python_deps.resolveHwAccel;
199253
200257
  exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation;
@@ -199268,7 +200272,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199268
200272
  exports.subscribePassthrough = require_manifest_python_deps.subscribePassthrough;
199269
200273
  exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
199270
200274
  exports.validateProviderRegistrations = require_manifest_python_deps.validateProviderRegistrations;
200275
+ exports.validateUploadedTls = require_lan_http_bind.validateUploadedTls;
200276
+ exports.writeExtraSans = require_lan_http_bind.writeExtraSans;
199271
200277
  exports.writePendingRestart = writePendingRestart;
200278
+ exports.writeTlsMode = require_lan_http_bind.writeTlsMode;
199272
200279
  }
199273
200280
  });
199274
200281
 
@@ -237936,7 +238943,7 @@ var require_enums = __commonJS({
237936
238943
  "../types/dist/enums.js"(exports) {
237937
238944
  "use strict";
237938
238945
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
237939
- var require_event_category = require_event_category_CRPORAAz();
238946
+ var require_event_category = require_event_category_EY0GNjV9();
237940
238947
  var EventSourceType = /* @__PURE__ */ (function(EventSourceType2) {
237941
238948
  EventSourceType2["Addon"] = "addon";
237942
238949
  EventSourceType2["Core"] = "core";
@@ -237956,8 +238963,8 @@ var require_dist9 = __commonJS({
237956
238963
  "../types/dist/index.js"(exports) {
237957
238964
  "use strict";
237958
238965
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
237959
- var require_event_category = require_event_category_CRPORAAz();
237960
- var require_sleep = require_sleep_CMRLJj2e();
238966
+ var require_event_category = require_event_category_EY0GNjV9();
238967
+ var require_sleep = require_sleep_C2XhJhkd();
237961
238968
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
237962
238969
  var require_enums2 = require_enums();
237963
238970
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -239483,6 +240490,16 @@ var require_dist9 = __commonJS({
239483
240490
  description: zod.z.string().optional(),
239484
240491
  icon: zod.z.string().optional()
239485
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
+ });
239486
240503
  var FORMAT_KEYS = [
239487
240504
  "onnx",
239488
240505
  "coreml",
@@ -239751,7 +240768,13 @@ var require_dist9 = __commonJS({
239751
240768
  * `id` stays the source of truth for resolution/download/persistence; grouping
239752
240769
  * is a presentation overlay resolved back to an `id`.
239753
240770
  */
239754
- 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()
239755
240778
  });
239756
240779
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
239757
240780
  format: zod.z.literal("openvino"),
@@ -239780,7 +240803,8 @@ var require_dist9 = __commonJS({
239780
240803
  "ocr",
239781
240804
  "segmentation"
239782
240805
  ]),
239783
- faceAlignment: zod.z.boolean().optional()
240806
+ faceAlignment: zod.z.boolean().optional(),
240807
+ classMap: ClassMapDefinitionSchema.optional()
239784
240808
  });
239785
240809
  var ConvertArtifactSchema = zod.z.object({
239786
240810
  format: zod.z.enum(MODEL_FORMATS),
@@ -250680,6 +251704,33 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250680
251704
  h: zod.z.number()
250681
251705
  })
250682
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
+ });
250683
251734
  var ModelFormatSchema$1 = zod.z.enum([
250684
251735
  "onnx",
250685
251736
  "coreml",
@@ -250979,7 +252030,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250979
252030
  * legacy call shape used by existing benchmark code; once all
250980
252031
  * callers pass it explicitly we make it required.
250981
252032
  *
250982
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
252033
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
250983
252034
  * `referenceImage` must be provided:
250984
252035
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
250985
252036
  * Carries the raw buffer, dimensions, and format; the executor
@@ -251001,6 +252052,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251001
252052
  steps: zod.z.array(PipelineStepInputSchema).min(1),
251002
252053
  frame: FrameInputSchema.optional(),
251003
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
+ /**
251004
252061
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
251005
252062
  * the decoded pixels live in. One more member of the one-of
251006
252063
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -251303,7 +252360,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251303
252360
  * Which source served this crop, so a quality-sensitive consumer (the native
251304
252361
  * `keyFrame`) can reject a degraded fallback:
251305
252362
  * - `native` — cut from the decode worker's retained NATIVE surface (the
251306
- * 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`).
251307
252367
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
251308
252368
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
251309
252369
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -251806,12 +252866,41 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251806
252866
  cpuCores: zod.z.number().optional()
251807
252867
  })
251808
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
+ });
251809
252897
  var RunnerLocalMetricsSchema = zod.z.object({
251810
252898
  nodeId: zod.z.string(),
251811
252899
  activeCameras: zod.z.number(),
251812
252900
  throttledCameras: zod.z.number(),
251813
252901
  avgInferenceTimeMs: zod.z.number(),
251814
- queueDepth: zod.z.number()
252902
+ queueDepth: zod.z.number(),
252903
+ frameLazy: FrameLazyMetricsSchema.optional()
251815
252904
  });
251816
252905
  var pipelineRunnerCapability = {
251817
252906
  name: "pipeline-runner",
@@ -253617,6 +254706,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253617
254706
  endDownload: require_sleep.method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
253618
254707
  }
253619
254708
  };
254709
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
254710
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
253620
254711
  var TerminalSessionInfoSchema = zod.z.object({
253621
254712
  /** Opaque session id minted by the provider on `openSession`. */
253622
254713
  sessionId: zod.z.string(),
@@ -253632,7 +254723,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253632
254723
  var TerminalProfileInfoSchema = zod.z.object({
253633
254724
  profileId: zod.z.string(),
253634
254725
  label: zod.z.string(),
253635
- 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()
253636
254734
  });
253637
254735
  var TerminalInstanceInfoSchema = zod.z.object({
253638
254736
  instanceId: zod.z.string(),
@@ -253641,7 +254739,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253641
254739
  profileId: zod.z.string(),
253642
254740
  profileLabel: zod.z.string(),
253643
254741
  name: zod.z.string(),
253644
- 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
253645
254748
  });
253646
254749
  var TerminalLegacyCameraSchema = zod.z.object({
253647
254750
  stableId: zod.z.string(),
@@ -253680,7 +254783,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253680
254783
  createInstance: require_sleep.method(zod.z.object({
253681
254784
  targetNodeId: zod.z.string().min(1),
253682
254785
  profileId: zod.z.string().min(1),
253683
- 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()
253684
254804
  }), TerminalInstanceInfoSchema, {
253685
254805
  kind: "mutation",
253686
254806
  auth: "admin"
@@ -253715,7 +254835,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253715
254835
  openSession: require_sleep.method(zod.z.object({
253716
254836
  profileId: zod.z.string(),
253717
254837
  cols: zod.z.number().int().positive(),
253718
- 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()
253719
254843
  }), TerminalSessionInfoSchema, {
253720
254844
  kind: "mutation",
253721
254845
  auth: "admin"
@@ -257441,6 +258565,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257441
258565
  /** What the ranking currently resolves to (null when nothing is reachable). */
257442
258566
  resolved: zod.z.string().nullable()
257443
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
+ });
257444
258574
  var AllowedAddressesSchema = zod.z.object({
257445
258575
  /**
257446
258576
  * Allowlist of interface addresses operators have explicitly opted
@@ -257450,6 +258580,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257450
258580
  */
257451
258581
  addresses: zod.z.array(zod.z.string()).readonly()
257452
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
+ });
257453
258597
  var localNetworkCapability = {
257454
258598
  name: "local-network",
257455
258599
  scope: "system",
@@ -257469,13 +258613,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257469
258613
  */
257470
258614
  getPreferred: require_sleep.method(zod.z.void(), PreferredSchema),
257471
258615
  /**
257472
- * Ordered candidate base URLs the SDK should try on connect.
257473
- * Includes LAN IPs (one per non-internal interface), the public
257474
- * tunnel hostname (when active), and loopback as a last-resort
257475
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
257476
- * Honours `getAllowedAddresses()` when set addresses outside
257477
- * the allowlist are dropped (the public tunnel + loopback are
257478
- * 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).
257479
258623
  *
257480
258624
  * **The port is the hub's, not the caller's** (D62 — a function's fact
257481
258625
  * belongs to whoever already owns it). This method used to take a `port`
@@ -257506,10 +258650,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257506
258650
  */
257507
258651
  port: zod.z.number().int().min(1).max(65535).optional(),
257508
258652
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
257509
- * candidate. Default `true`. */
258653
+ * candidate. Default `false` — loopback is not a client route. */
257510
258654
  includeLoopback: zod.z.boolean().optional(),
257511
- /** Skip IPv6 entries. Some legacy clients can't parse them.
257512
- * 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`. */
257513
258658
  ipv4Only: zod.z.boolean().optional(),
257514
258659
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
257515
258660
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -257538,6 +258683,19 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257538
258683
  */
257539
258684
  setNotificationEndpoint: require_sleep.method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
257540
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
+ /**
257541
258699
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
257542
258700
  * by the admin UI's address selector to seed its checkbox state.
257543
258701
  */
@@ -257555,7 +258713,34 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257555
258713
  * when the operator wants to wipe their manual edits and start
257556
258714
  * over from the auto-detected best matches.
257557
258715
  */
257558
- 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
+ })
257559
258744
  },
257560
258745
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
257561
258746
  mount: { kind: "hub-only" }
@@ -267844,6 +269029,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
267844
269029
  addonId: null,
267845
269030
  access: "create"
267846
269031
  },
269032
+ "localNetwork.downloadCa": {
269033
+ capName: "local-network",
269034
+ capScope: "system",
269035
+ addonId: null,
269036
+ access: "view"
269037
+ },
267847
269038
  "localNetwork.getAllowedAddresses": {
267848
269039
  capName: "local-network",
267849
269040
  capScope: "system",
@@ -267868,18 +269059,42 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
267868
269059
  addonId: null,
267869
269060
  access: "view"
267870
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
+ },
267871
269074
  "localNetwork.list": {
267872
269075
  capName: "local-network",
267873
269076
  capScope: "system",
267874
269077
  addonId: null,
267875
269078
  access: "view"
267876
269079
  },
269080
+ "localNetwork.regenerateCertificate": {
269081
+ capName: "local-network",
269082
+ capScope: "system",
269083
+ addonId: null,
269084
+ access: "create"
269085
+ },
267877
269086
  "localNetwork.resetAllowlistToBestMatch": {
267878
269087
  capName: "local-network",
267879
269088
  capScope: "system",
267880
269089
  addonId: null,
267881
269090
  access: "delete"
267882
269091
  },
269092
+ "localNetwork.revertToGeneratedCertificate": {
269093
+ capName: "local-network",
269094
+ capScope: "system",
269095
+ addonId: null,
269096
+ access: "create"
269097
+ },
267883
269098
  "localNetwork.setAllowedAddresses": {
267884
269099
  capName: "local-network",
267885
269100
  capScope: "system",
@@ -267892,6 +269107,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
267892
269107
  addonId: null,
267893
269108
  access: "create"
267894
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
+ },
267895
269122
  "lockControl.lock": {
267896
269123
  capName: "lock-control",
267897
269124
  capScope: "device",
@@ -270772,6 +271999,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
270772
271999
  addonId: null,
270773
272000
  access: "create"
270774
272001
  },
272002
+ "terminalSession.updateInstance": {
272003
+ capName: "terminal-session",
272004
+ capScope: "system",
272005
+ addonId: null,
272006
+ access: "create"
272007
+ },
270775
272008
  "terminalSession.writeInput": {
270776
272009
  capName: "terminal-session",
270777
272010
  capScope: "system",
@@ -274030,9 +275263,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274030
275263
  getConnectionEndpoints: (input) => dispatch("localNetwork", "getConnectionEndpoints", "query", input),
274031
275264
  getNotificationEndpoint: (input) => dispatch("localNetwork", "getNotificationEndpoint", "query", input),
274032
275265
  setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
275266
+ getViewerEndpoints: (input) => dispatch("localNetwork", "getViewerEndpoints", "query", input),
275267
+ setViewerEndpoints: (input) => dispatch("localNetwork", "setViewerEndpoints", "mutation", input),
274033
275268
  getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
274034
275269
  setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
274035
- 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)
274036
275276
  },
274037
275277
  meshNetwork: {
274038
275278
  getStatus: (input) => dispatch("meshNetwork", "getStatus", "query", input),
@@ -274314,6 +275554,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274314
275554
  listProfiles: (input) => dispatch("terminalSession", "listProfiles", "query", input),
274315
275555
  listInstances: (input) => dispatch("terminalSession", "listInstances", "query", input),
274316
275556
  createInstance: (input) => dispatch("terminalSession", "createInstance", "mutation", input),
275557
+ updateInstance: (input) => dispatch("terminalSession", "updateInstance", "mutation", input),
274317
275558
  deleteInstance: (input) => dispatch("terminalSession", "deleteInstance", "mutation", input),
274318
275559
  setInstanceEnabled: (input) => dispatch("terminalSession", "setInstanceEnabled", "mutation", input),
274319
275560
  listLegacyCameras: (input) => dispatch("terminalSession", "listLegacyCameras", "query", input),
@@ -275228,6 +276469,58 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275228
276469
  const chosen = models[stepId];
275229
276470
  return chosen !== void 0 && chosen !== "" ? chosen : step2.defaultModelId;
275230
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
+ }
275231
276524
  var DETAIL_CROP_SECTION_ID = "detail-crop";
275232
276525
  var DETAIL_CROP_PADDING_KEY = "detailCropPaddingRatio";
275233
276526
  var DETAIL_CROP_SQUARE_KEY = "detailCropSquare";
@@ -277016,8 +278309,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277016
278309
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
277017
278310
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
277018
278311
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
278312
+ exports.CLASS_MAP_MACRO_TARGETS = CLASS_MAP_MACRO_TARGETS;
277019
278313
  exports.CLUSTER_MODEL_SCOPED_STEPS = CLUSTER_MODEL_SCOPED_STEPS;
277020
278314
  exports.CLUSTER_MODEL_SECTION_ID = CLUSTER_MODEL_SECTION_ID;
278315
+ exports.CLUSTER_STEP_SETTING_FIELDS = CLUSTER_STEP_SETTING_FIELDS;
277021
278316
  exports.COCO_80_LABELS = COCO_80_LABELS;
277022
278317
  exports.COCO_TO_MACRO = COCO_TO_MACRO;
277023
278318
  exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
@@ -277061,6 +278356,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277061
278356
  exports.CapabilityBindingsSchema = CapabilityBindingsSchema;
277062
278357
  exports.CarbonMonoxideStatusSchema = CarbonMonoxideStatusSchema;
277063
278358
  exports.ChargingStatus = require_sleep.ChargingStatus;
278359
+ exports.ClassMapDefinitionSchema = ClassMapDefinitionSchema;
277064
278360
  exports.ClientNetworkStatsSchema = ClientNetworkStatsSchema;
277065
278361
  exports.ClimateControlStatusSchema = ClimateControlStatusSchema;
277066
278362
  exports.ClipPlaybackSchema = ClipPlaybackSchema;
@@ -277106,11 +278402,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277106
278402
  exports.DEFAULT_ADDON_PLACEMENT = DEFAULT_ADDON_PLACEMENT;
277107
278403
  exports.DEFAULT_AUDIO_ANALYZER_CONFIG = DEFAULT_AUDIO_ANALYZER_CONFIG;
277108
278404
  exports.DEFAULT_CLUSTER_STEP_MODELS = DEFAULT_CLUSTER_STEP_MODELS;
278405
+ exports.DEFAULT_CLUSTER_STEP_SETTINGS = DEFAULT_CLUSTER_STEP_SETTINGS;
277109
278406
  exports.DEFAULT_DECODER_HWACCEL_CONFIG = DEFAULT_DECODER_HWACCEL_CONFIG;
277110
278407
  exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
277111
278408
  exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
277112
278409
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
277113
278410
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
278411
+ exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
277114
278412
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
277115
278413
  exports.DEFAULT_POOL_MEMORY_POLICY = DEFAULT_POOL_MEMORY_POLICY;
277116
278414
  exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
@@ -277234,6 +278532,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277234
278532
  exports.FrameHandleFormatSchema = require_sleep.FrameHandleFormatSchema;
277235
278533
  exports.FrameHandleSchema = require_sleep.FrameHandleSchema;
277236
278534
  exports.FrameInputSchema = FrameInputSchema;
278535
+ exports.FrameLazyCountersSchema = FrameLazyCountersSchema;
278536
+ exports.FrameLazyMetricsSchema = FrameLazyMetricsSchema;
277237
278537
  exports.GasStatusSchema = GasStatusSchema;
277238
278538
  exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
277239
278539
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
@@ -277888,6 +279188,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277888
279188
  exports.classifyStreams = classifyStreams;
277889
279189
  exports.climateControlCapability = climateControlCapability;
277890
279190
  exports.clusterModelSettingKey = clusterModelSettingKey;
279191
+ exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
279192
+ exports.clusterStepSettingKey = clusterStepSettingKey;
277891
279193
  exports.collectHydratedFieldEntries = require_sleep.collectHydratedFieldEntries;
277892
279194
  exports.collectHydratedFieldValues = require_sleep.collectHydratedFieldValues;
277893
279195
  exports.colorCapability = colorCapability;
@@ -278078,6 +279380,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278078
279380
  exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
278079
279381
  exports.osdCapability = osdCapability;
278080
279382
  exports.osdManagerCapability = osdManagerCapability;
279383
+ exports.overlayClusterStepSettings = overlayClusterStepSettings;
278081
279384
  exports.parseCameraStreamConfig = parseCameraStreamConfig;
278082
279385
  exports.parseExpression = parseExpression;
278083
279386
  exports.parseJsonArray = require_sleep.parseJsonArray;
@@ -278091,6 +279394,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278091
279394
  exports.petFeederCapability = petFeederCapability;
278092
279395
  exports.pickAccessoryControl = pickAccessoryControl;
278093
279396
  exports.pickClusterStepModels = pickClusterStepModels;
279397
+ exports.pickClusterStepSettings = pickClusterStepSettings;
278094
279398
  exports.pickDetailCropConvention = pickDetailCropConvention;
278095
279399
  exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
278096
279400
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
@@ -278115,6 +279419,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278115
279419
  exports.ptzCapability = ptzCapability;
278116
279420
  exports.pythonScriptForBackend = pythonScriptForBackend;
278117
279421
  exports.readClusterStepModels = readClusterStepModels;
279422
+ exports.readClusterStepSettings = readClusterStepSettings;
278118
279423
  exports.readDetailCropConvention = readDetailCropConvention;
278119
279424
  exports.readDeviceStateFrom = readDeviceStateFrom;
278120
279425
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
@@ -394643,18 +395948,26 @@ var require_session_cookie = __commonJS({
394643
395948
  exports.isEmbedRedirectTarget = isEmbedRedirectTarget;
394644
395949
  exports.isSessionGradeJwtPayload = isSessionGradeJwtPayload;
394645
395950
  exports.SESSION_COOKIE = "camstack_session";
394646
- function buildSessionCookie(token2, ttlSec) {
395951
+ function buildSessionCookie(token2, ttlSec, opts = {}) {
394647
395952
  return {
394648
395953
  name: exports.SESSION_COOKIE,
394649
395954
  value: token2,
394650
- 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
+ }
394651
395964
  };
394652
395965
  }
394653
- function clearSessionCookie() {
395966
+ function clearSessionCookie(opts = {}) {
394654
395967
  return {
394655
395968
  name: exports.SESSION_COOKIE,
394656
395969
  value: "",
394657
- options: { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: 0 }
395970
+ options: { httpOnly: true, sameSite: "lax", secure: opts.secure ?? true, path: "/", maxAge: 0 }
394658
395971
  };
394659
395972
  }
394660
395973
  function readSessionCookieFromHeader(header) {
@@ -394819,6 +396132,25 @@ var require_health_routes = __commonJS({
394819
396132
  }
394820
396133
  });
394821
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
+
394822
396154
  // ../../server/backend/dist/api/model-distributor.js
394823
396155
  var require_model_distributor = __commonJS({
394824
396156
  "../../server/backend/dist/api/model-distributor.js"(exports) {
@@ -399394,7 +400726,7 @@ var require_post_boot_service = __commonJS({
399394
400726
  return entry.payload;
399395
400727
  }
399396
400728
  async run(context) {
399397
- const { port, host, dataPath, trpcRegistered } = context;
400729
+ const { port, host, dataPath, trpcRegistered, tlsCert } = context;
399398
400730
  this.eventBus.emit({
399399
400731
  id: (0, node_crypto_1.randomUUID)(),
399400
400732
  timestamp: /* @__PURE__ */ new Date(),
@@ -399403,6 +400735,7 @@ var require_post_boot_service = __commonJS({
399403
400735
  data: { port, host, trpcRegistered, dataPath }
399404
400736
  });
399405
400737
  this.emitRestartCompletedIfPending(dataPath);
400738
+ this.emitTlsCertChangedIfReissued(tlsCert);
399406
400739
  await this.reconcileLifecycleJobsIfAny();
399407
400740
  }
399408
400741
  async reconcileLifecycleJobsIfAny() {
@@ -399411,6 +400744,27 @@ var require_post_boot_service = __commonJS({
399411
400744
  this.logger.info("Lifecycle jobs reconciled at boot", { meta: { resumed, failed } });
399412
400745
  }
399413
400746
  }
400747
+ emitTlsCertChangedIfReissued(tlsCert) {
400748
+ if (tlsCert === void 0 || !tlsCert.generated)
400749
+ return;
400750
+ const payload = {
400751
+ reason: tlsCert.reason ?? "unknown",
400752
+ fingerprintSha256: tlsCert.fingerprintSha256,
400753
+ caFingerprintSha256: tlsCert.caFingerprintSha256,
400754
+ caRotated: tlsCert.caRotated,
400755
+ caCertPath: tlsCert.caCertPath,
400756
+ validTo: tlsCert.validTo,
400757
+ sans: tlsCert.sans
400758
+ };
400759
+ this.logger.warn("TLS certificate reissued", { meta: payload });
400760
+ this.eventBus.emit({
400761
+ id: (0, node_crypto_1.randomUUID)(),
400762
+ timestamp: /* @__PURE__ */ new Date(),
400763
+ source: { type: "core", id: "system" },
400764
+ category: types_1.EventCategory.SystemTlsCertChanged,
400765
+ data: payload
400766
+ });
400767
+ }
399414
400768
  emitRestartCompletedIfPending(dataDir) {
399415
400769
  const marker = (0, system_1.readPendingRestart)(dataDir);
399416
400770
  if (marker === null)
@@ -401763,19 +403117,8 @@ var require_trpc_router = __commonJS({
401763
403117
  const relayOnly = FORCE_RELAY_REMOTE ? (0, client_ip_js_1.deriveRelayOnly)(clientClass) : false;
401764
403118
  return { ...input, relayOnly };
401765
403119
  }
401766
- var REMOTE_INITIAL_ADAPTIVE_TIER = "low";
401767
- function enrichHintsWithClientClass(input, clientClass) {
401768
- if (clientClass !== "remote")
401769
- return input;
401770
- const isAdaptive = input.target === void 0 || input.target.kind === "adaptive";
401771
- if (!isAdaptive)
401772
- return input;
401773
- if (input.hints?.prefersTier !== void 0)
401774
- return input;
401775
- return {
401776
- ...input,
401777
- hints: { ...input.hints, prefersTier: REMOTE_INITIAL_ADAPTIVE_TIER }
401778
- };
403120
+ function enrichHintsWithClientClass(input, _clientClass) {
403121
+ return input;
401779
403122
  }
401780
403123
  function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
401781
403124
  const userAgent = (0, client_ip_js_1.extractUserAgent)(ctx.req);
@@ -401980,11 +403323,11 @@ var require_boot_config = __commonJS({
401980
403323
  exports.loadBootstrapConfig = loadBootstrapConfig;
401981
403324
  exports.autoGenerateJwtSecret = autoGenerateJwtSecret;
401982
403325
  exports.setupInfra = setupInfra;
403326
+ var node_crypto_1 = __require("crypto");
401983
403327
  var fs = __importStar(__require("fs"));
401984
403328
  var path = __importStar(__require("path"));
401985
- var yaml = __importStar(require_js_yaml());
401986
- var node_crypto_1 = __require("crypto");
401987
403329
  var types_1 = require_dist9();
403330
+ var yaml = __importStar(require_js_yaml());
401988
403331
  var config_schema_1 = require_config_schema();
401989
403332
  var storage_location_manager_1 = require_storage_location_manager();
401990
403333
  var CONFIG_DEFAULTS = {
@@ -402104,6 +403447,7 @@ var require_boot_config = __commonJS({
402104
403447
  console.log(`[Phase2] Location "${name}": ${available ? "OK" : "UNAVAILABLE"} \u2192 ${locPath}`);
402105
403448
  }
402106
403449
  let tlsOptions;
403450
+ let tlsCert;
402107
403451
  if (config.tls.enabled) {
402108
403452
  const core = require_dist3();
402109
403453
  const { ensureTlsCert, loadTlsCert } = core;
@@ -402112,12 +403456,10 @@ var require_boot_config = __commonJS({
402112
403456
  const pair = loadTlsCert(config.tls.certPath, config.tls.keyPath);
402113
403457
  tlsOptions = { key: pair.key, cert: pair.cert };
402114
403458
  } else {
402115
- const tlsResult = await ensureTlsCert(dataPath);
402116
- if (tlsResult.generated) {
402117
- console.log(`[Phase2c] Generated self-signed TLS cert at ${tlsResult.certPath}`);
402118
- } else {
402119
- console.log(`[Phase2c] Using existing TLS cert at ${tlsResult.certPath}`);
402120
- }
403459
+ const extraSans = [...core.readExtraSans?.(dataPath) ?? []];
403460
+ const tlsResult = await ensureTlsCert(dataPath, extraSans.length > 0 ? { extraSans } : void 0);
403461
+ tlsCert = tlsResult;
403462
+ logTlsCert(tlsResult);
402121
403463
  const pair = loadTlsCert(tlsResult.certPath, tlsResult.keyPath);
402122
403464
  tlsOptions = { key: pair.key, cert: pair.cert };
402123
403465
  }
@@ -402126,9 +403468,20 @@ var require_boot_config = __commonJS({
402126
403468
  bootstrapConfig: config,
402127
403469
  dataPath,
402128
403470
  locationManager,
402129
- tlsOptions
403471
+ tlsOptions,
403472
+ tlsCert
402130
403473
  };
402131
403474
  }
403475
+ function logTlsCert(result) {
403476
+ if (!result.generated) {
403477
+ console.log(`[Phase2c] TLS cert unchanged \u2014 ${result.certPath} (leaf ${result.fingerprintSha256}, valid to ${result.validTo})`);
403478
+ return;
403479
+ }
403480
+ console.log(`[Phase2c] TLS CERTIFICATE REISSUED \u2014 reason=${result.reason}, caRotated=${result.caRotated}`);
403481
+ console.log(`[Phase2c] leaf ${result.previousFingerprintSha256 ?? "(none)"} \u2192 ${result.fingerprintSha256}`);
403482
+ console.log(`[Phase2c] valid to ${result.validTo}, names: ${result.sans.join(", ")}`);
403483
+ console.log(result.caRotated ? `[Phase2c] ACTION REQUIRED: the local CA changed. Install ${result.caCertPath} (SHA-256 ${result.caFingerprintSha256}) on every device that trusted the previous certificate.` : `[Phase2c] Local CA unchanged (${result.caFingerprintSha256}) \u2014 devices that trust ${result.caCertPath} keep working.`);
403484
+ }
402132
403485
  }
402133
403486
  });
402134
403487
 
@@ -409428,7 +410781,13 @@ var require_manual_boot = __commonJS({
409428
410781
  });
409429
410782
  },
409430
410783
  async listen(port, host) {
409431
- 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
+ });
409432
410791
  },
409433
410792
  close
409434
410793
  };
@@ -409493,6 +410852,7 @@ var require_main4 = __commonJS({
409493
410852
  var addon_upload_1 = require_addon_upload();
409494
410853
  var auth_whoami_1 = require_auth_whoami();
409495
410854
  var health_routes_1 = require_health_routes();
410855
+ var adaptive_probe_routes_1 = require_adaptive_probe_routes();
409496
410856
  var model_distributor_js_1 = require_model_distributor();
409497
410857
  var oauth2_routes_js_1 = require_oauth2_routes();
409498
410858
  var server_upload_1 = require_server_upload();
@@ -409611,7 +410971,7 @@ var require_main4 = __commonJS({
409611
410971
  const configPath = process.env.CONFIG_PATH ?? path.join(process.env.CAMSTACK_DATA ?? path.join(process.cwd(), "camstack-data"), "config.yaml");
409612
410972
  const bootstrapConfig = (0, boot_config_1.loadBootstrapConfig)(configPath);
409613
410973
  const infra = await (0, boot_config_1.setupInfra)(configPath, bootstrapConfig);
409614
- const { dataPath, tlsOptions } = infra;
410974
+ const { dataPath, tlsOptions, tlsCert } = infra;
409615
410975
  const port = infra.bootstrapConfig.server.port;
409616
410976
  const host = infra.bootstrapConfig.server.host;
409617
410977
  const fastifyOpts = tlsOptions ? { https: tlsOptions } : {};
@@ -409730,6 +411090,7 @@ var require_main4 = __commonJS({
409730
411090
  verifyToken: (token2) => app.get(auth_service_1.AuthService).verifyToken(token2)
409731
411091
  });
409732
411092
  console.log(`[bootstrap] Health routes registered (hub v${hubVersion})`);
411093
+ (0, adaptive_probe_routes_1.registerAdaptiveProbeRoute)(fastify);
409733
411094
  } catch (err) {
409734
411095
  console.warn("[bootstrap] Failed to register health routes:", err);
409735
411096
  }
@@ -409967,12 +411328,12 @@ var require_main4 = __commonJS({
409967
411328
  } catch {
409968
411329
  return reply.status(401).send({ error: "invalid token" });
409969
411330
  }
409970
- 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" });
409971
411332
  reply.setCookie(c.name, c.value, c.options);
409972
411333
  return reply.send({ ok: true });
409973
411334
  });
409974
- fastify.delete("/api/auth/session", async (_request, reply) => {
409975
- 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" });
409976
411337
  reply.setCookie(c.name, c.value, c.options);
409977
411338
  return reply.send({ ok: true });
409978
411339
  });
@@ -409992,7 +411353,7 @@ var require_main4 = __commonJS({
409992
411353
  } catch {
409993
411354
  return reply.status(401).send({ error: "invalid token" });
409994
411355
  }
409995
- 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" });
409996
411357
  reply.setCookie(c.name, c.value, c.options);
409997
411358
  return reply.redirect(next);
409998
411359
  });
@@ -410257,7 +411618,7 @@ var require_main4 = __commonJS({
410257
411618
  const url = request.url;
410258
411619
  if ((0, spa_static_1.isRetiredPublicPath)(url))
410259
411620
  return reply.callNotFound();
410260
- 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")) {
410261
411622
  return reply.callNotFound();
410262
411623
  }
410263
411624
  const { staticDir, indexPath } = adminUiState;
@@ -410347,7 +411708,16 @@ var require_main4 = __commonJS({
410347
411708
  }
410348
411709
  };
410349
411710
  try {
410350
- 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
+ }
410351
411721
  } catch (listenErr) {
410352
411722
  if (listenErr !== null && typeof listenErr === "object" && "code" in listenErr && listenErr.code === "EADDRINUSE") {
410353
411723
  console.error(`[bootstrap] FATAL: Port ${port} is already in use. Stop the other process or change server.port in config.yaml.`);
@@ -410358,9 +411728,29 @@ var require_main4 = __commonJS({
410358
411728
  const logger = app.get(logging_service_1.LoggingService).createLogger("System");
410359
411729
  const protocol = tlsOptions ? "https" : "http";
410360
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
+ }
410361
411751
  void Promise.all([resolveAdminUi(), resolveViewerUi()]);
410362
411752
  const postBoot = app.get(post_boot_service_1.PostBootService);
410363
- await postBoot.run({ port, host, dataPath, trpcRegistered });
411753
+ await postBoot.run({ port, host, dataPath, trpcRegistered, tlsCert });
410364
411754
  try {
410365
411755
  const confirm = app.get(server_update_service_1.ServerUpdateService).confirmBootHealthy();
410366
411756
  if (confirm.promoted !== null) {