camstack 1.2.38 → 1.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23631,9 +23631,9 @@ var require_zod = __commonJS({
23631
23631
  }
23632
23632
  });
23633
23633
 
23634
- // ../system/dist/dist-iAwSA2_f.js
23635
- var require_dist_iAwSA2_f = __commonJS({
23636
- "../system/dist/dist-iAwSA2_f.js"(exports) {
23634
+ // ../system/dist/dist-DnhGRFEn.js
23635
+ var require_dist_DnhGRFEn = __commonJS({
23636
+ "../system/dist/dist-DnhGRFEn.js"(exports) {
23637
23637
  "use strict";
23638
23638
  var zod = require_zod();
23639
23639
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -24111,6 +24111,13 @@ var require_dist_iAwSA2_f = __commonJS({
24111
24111
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
24112
24112
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
24113
24113
  _registeredCapNames = [];
24114
+ /**
24115
+ * True only after `readAddonStore` actually answered. Constructor
24116
+ * defaults look like stored config when the store is down — a forked
24117
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
24118
+ * mode, 2026-08-25) is not "the operator chose this".
24119
+ */
24120
+ settingsStoreReady = false;
24114
24121
  /** Default config values. Provided via constructor. */
24115
24122
  defaults;
24116
24123
  constructor(defaults) {
@@ -24516,7 +24523,9 @@ var require_dist_iAwSA2_f = __commonJS({
24516
24523
  ];
24517
24524
  let lastErr;
24518
24525
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
24519
- return await settings.readAddonStore() ?? {};
24526
+ const stored = await settings.readAddonStore() ?? {};
24527
+ this.settingsStoreReady = true;
24528
+ return stored;
24520
24529
  } catch (err) {
24521
24530
  lastErr = err;
24522
24531
  const msg = err instanceof Error ? err.message : String(err);
@@ -24524,6 +24533,7 @@ var require_dist_iAwSA2_f = __commonJS({
24524
24533
  if (attempt === delaysMs.length) break;
24525
24534
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
24526
24535
  }
24536
+ this.settingsStoreReady = false;
24527
24537
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries \u2014 using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
24528
24538
  return {};
24529
24539
  }
@@ -26256,6 +26266,15 @@ var require_dist_iAwSA2_f = __commonJS({
26256
26266
  description: zod.z.string().optional(),
26257
26267
  icon: zod.z.string().optional()
26258
26268
  });
26269
+ var ClassMapDefinitionSchema = zod.z.object({
26270
+ mapping: zod.z.record(zod.z.string(), zod.z.enum([
26271
+ "person",
26272
+ "vehicle",
26273
+ "animal",
26274
+ "package"
26275
+ ])),
26276
+ preserveOriginal: zod.z.boolean()
26277
+ });
26259
26278
  var MODEL_FORMATS = [
26260
26279
  "onnx",
26261
26280
  "coreml",
@@ -26309,6 +26328,12 @@ var require_dist_iAwSA2_f = __commonJS({
26309
26328
  */
26310
26329
  resolution: zod.z.number().int().positive().optional()
26311
26330
  });
26331
+ var ModelProviderIdSchema = zod.z.enum([
26332
+ "camstack",
26333
+ "frigate",
26334
+ "scrypted",
26335
+ "custom"
26336
+ ]);
26312
26337
  var ModelCatalogEntrySchema = zod.z.object({
26313
26338
  id: zod.z.string(),
26314
26339
  name: zod.z.string(),
@@ -26404,7 +26429,19 @@ var require_dist_iAwSA2_f = __commonJS({
26404
26429
  * `id` stays the source of truth for resolution/download/persistence; grouping
26405
26430
  * is a presentation overlay resolved back to an `id`.
26406
26431
  */
26407
- group: ModelVariantGroupSchema.optional()
26432
+ group: ModelVariantGroupSchema.optional(),
26433
+ /**
26434
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
26435
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
26436
+ * persisted before this field existed (`inferModelProvider` fills those).
26437
+ */
26438
+ provider: ModelProviderIdSchema.optional(),
26439
+ /**
26440
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
26441
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
26442
+ * labels already ARE the CamStack macros (Scrypted identity map).
26443
+ */
26444
+ classMap: ClassMapDefinitionSchema.optional()
26408
26445
  });
26409
26446
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
26410
26447
  format: zod.z.literal("openvino"),
@@ -26433,7 +26470,8 @@ var require_dist_iAwSA2_f = __commonJS({
26433
26470
  "ocr",
26434
26471
  "segmentation"
26435
26472
  ]),
26436
- faceAlignment: zod.z.boolean().optional()
26473
+ faceAlignment: zod.z.boolean().optional(),
26474
+ classMap: ClassMapDefinitionSchema.optional()
26437
26475
  });
26438
26476
  var ConvertArtifactSchema = zod.z.object({
26439
26477
  format: zod.z.enum(MODEL_FORMATS),
@@ -33167,14 +33205,22 @@ var require_dist_iAwSA2_f = __commonJS({
33167
33205
  sustainSeconds: zod.z.number().int().min(0).max(3600).default(15)
33168
33206
  });
33169
33207
  var NcAudioConditionSchema = zod.z.object({
33170
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
33208
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
33171
33209
  labels: zod.z.array(zod.z.string().min(1)).min(1).optional(),
33172
33210
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
33173
33211
  dbThreshold: zod.z.number().min(-96).max(0).optional(),
33174
33212
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
33175
33213
  hitPercent: zod.z.number().int().min(1).max(100).default(60),
33176
33214
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
33177
- samplingSeconds: zod.z.number().int().min(1).max(300).default(10)
33215
+ samplingSeconds: zod.z.number().int().min(1).max(300).default(10),
33216
+ /**
33217
+ * LABEL MODE: how many labelled frames must land inside
33218
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
33219
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
33220
+ */
33221
+ confirmHits: zod.z.number().int().min(1).max(20).optional(),
33222
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
33223
+ confirmWindowSec: zod.z.number().int().min(1).max(60).optional()
33178
33224
  });
33179
33225
  var NcCrossingSchema = zod.z.enum([
33180
33226
  "enter",
@@ -34992,6 +35038,46 @@ var require_dist_iAwSA2_f = __commonJS({
34992
35038
  /** Cursor for the next page, or null when this page is the last. */
34993
35039
  nextCursor: zod.z.string().nullable()
34994
35040
  });
35041
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
35042
+ var LIST_GROUPS_MAX_LIMIT = 100;
35043
+ var AnalyticsGroupRecordSchema = zod.z.object({
35044
+ id: zod.z.string(),
35045
+ deviceId: zod.z.number().int(),
35046
+ openedAt: zod.z.number().int(),
35047
+ closedAt: zod.z.number().int(),
35048
+ timestamp: zod.z.number().int(),
35049
+ memberCount: zod.z.number().int(),
35050
+ memberTrackIds: zod.z.array(zod.z.string()).readonly(),
35051
+ className: zod.z.string(),
35052
+ classes: zod.z.array(zod.z.string()).readonly(),
35053
+ /** Relative event-media path, or null when the group has no picture yet. */
35054
+ mediaUrl: zod.z.string().nullable(),
35055
+ singleton: zod.z.boolean()
35056
+ });
35057
+ var AnalyticsGroupMemberSchema = zod.z.object({
35058
+ trackId: zod.z.string(),
35059
+ deviceId: zod.z.number().int(),
35060
+ className: zod.z.string(),
35061
+ firstSeen: zod.z.number().int(),
35062
+ lastSeen: zod.z.number().int(),
35063
+ mediaUrl: zod.z.string().nullable()
35064
+ });
35065
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
35066
+ var ListGroupsQueryInput = zod.z.object({
35067
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
35068
+ deviceIds: zod.z.array(zod.z.number()),
35069
+ /** Window lower bound on `closedAt` (inclusive). */
35070
+ since: zod.z.number().optional(),
35071
+ /** Window upper bound on `openedAt` (inclusive). */
35072
+ until: zod.z.number().optional(),
35073
+ limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
35074
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
35075
+ cursor: zod.z.string().optional()
35076
+ });
35077
+ var ListGroupsPageSchema = zod.z.object({
35078
+ groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
35079
+ nextCursor: zod.z.string().nullable()
35080
+ });
34995
35081
  var KeyEventQueryInput = zod.z.object({
34996
35082
  deviceId: zod.z.number(),
34997
35083
  /** Window lower bound (track firstSeen ≥ since). */
@@ -35067,7 +35153,9 @@ var require_dist_iAwSA2_f = __commonJS({
35067
35153
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
35068
35154
  plates: zod.z.number().int(),
35069
35155
  /** Per-track CLIP search vectors removed (best-effort). */
35070
- embeddings: zod.z.number().int()
35156
+ embeddings: zod.z.number().int(),
35157
+ /** Group membership + group rows removed with their last member (best-effort). */
35158
+ groups: zod.z.number().int()
35071
35159
  });
35072
35160
  var DiskReconcileCountsSchema = zod.z.object({
35073
35161
  mediaDropped: zod.z.number().int(),
@@ -35209,6 +35297,16 @@ var require_dist_iAwSA2_f = __commonJS({
35209
35297
  * are not included (same contract as `listTracks`).
35210
35298
  */
35211
35299
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
35300
+ /**
35301
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
35302
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
35303
+ * one session; `getGroup` is the detail with members.
35304
+ */
35305
+ listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
35306
+ getGroup: method(zod.z.object({
35307
+ deviceId: zod.z.number(),
35308
+ groupId: zod.z.string().min(1)
35309
+ }), AnalyticsGroupDetailSchema.nullable()),
35212
35310
  clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
35213
35311
  kind: "mutation",
35214
35312
  auth: "admin"
@@ -35797,6 +35895,33 @@ var require_dist_iAwSA2_f = __commonJS({
35797
35895
  h: zod.z.number()
35798
35896
  })
35799
35897
  });
35898
+ zod.z.object({
35899
+ crop: zod.z.object({
35900
+ left: zod.z.number(),
35901
+ top: zod.z.number(),
35902
+ width: zod.z.number().positive(),
35903
+ height: zod.z.number().positive()
35904
+ }).optional(),
35905
+ content: zod.z.object({
35906
+ width: zod.z.number().int().positive(),
35907
+ height: zod.z.number().int().positive()
35908
+ }),
35909
+ fit: zod.z.enum(["stretch", "contain"]),
35910
+ format: zod.z.enum([
35911
+ "rgb",
35912
+ "gray",
35913
+ "jpeg"
35914
+ ])
35915
+ });
35916
+ var FrameRefSchema = zod.z.object({
35917
+ registryId: zod.z.string().min(1),
35918
+ id: zod.z.string().min(1),
35919
+ width: zod.z.number().int().positive(),
35920
+ height: zod.z.number().int().positive(),
35921
+ format: zod.z.enum(["rgb", "gray"]),
35922
+ timestamp: zod.z.number(),
35923
+ capturedAt: zod.z.number().optional()
35924
+ });
35800
35925
  var ModelFormatSchema$1 = zod.z.enum([
35801
35926
  "onnx",
35802
35927
  "coreml",
@@ -35863,7 +35988,8 @@ var require_dist_iAwSA2_f = __commonJS({
35863
35988
  sizeMB: zod.z.number()
35864
35989
  })),
35865
35990
  group: ModelVariantGroupSchema.optional(),
35866
- legacy: zod.z.boolean().optional()
35991
+ legacy: zod.z.boolean().optional(),
35992
+ provider: ModelProviderIdSchema.optional()
35867
35993
  });
35868
35994
  var ConfigFieldBridge = zod.z.custom();
35869
35995
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -36096,7 +36222,7 @@ var require_dist_iAwSA2_f = __commonJS({
36096
36222
  * legacy call shape used by existing benchmark code; once all
36097
36223
  * callers pass it explicitly we make it required.
36098
36224
  *
36099
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
36225
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
36100
36226
  * `referenceImage` must be provided:
36101
36227
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
36102
36228
  * Carries the raw buffer, dimensions, and format; the executor
@@ -36118,6 +36244,12 @@ var require_dist_iAwSA2_f = __commonJS({
36118
36244
  steps: zod.z.array(PipelineStepInputSchema).min(1),
36119
36245
  frame: FrameInputSchema.optional(),
36120
36246
  /**
36247
+ * Process-local lazy frame. Valid only when caller and provider resolve
36248
+ * in the same execution-group process; split/cross-node callers use
36249
+ * `frame`/`image` inline compatibility instead.
36250
+ */
36251
+ frameRef: FrameRefSchema.optional(),
36252
+ /**
36121
36253
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
36122
36254
  * the decoded pixels live in. One more member of the one-of
36123
36255
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -36420,7 +36552,10 @@ var require_dist_iAwSA2_f = __commonJS({
36420
36552
  * Which source served this crop, so a quality-sensitive consumer (the native
36421
36553
  * `keyFrame`) can reject a degraded fallback:
36422
36554
  * - `native` — cut from the decode worker's retained NATIVE surface (the
36423
- * quality path).
36555
+ * quality path). A subject-tile serve is also native-resolution and stays
36556
+ * `native` here: the public enum cannot name `tile` without a breaking cap
36557
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
36558
+ * internal crop result (`nativeHits` vs `tileHits`).
36424
36559
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
36425
36560
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
36426
36561
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -36780,12 +36915,41 @@ var require_dist_iAwSA2_f = __commonJS({
36780
36915
  cpuCores: zod.z.number().optional()
36781
36916
  })
36782
36917
  });
36918
+ var FrameLazyCountersSchema = zod.z.object({
36919
+ framesDecoded: zod.z.number(),
36920
+ framesAdmitted: zod.z.number(),
36921
+ framesDroppedPixelFree: zod.z.number(),
36922
+ viewsMaterialized: zod.z.number(),
36923
+ viewsSkipped: zod.z.number(),
36924
+ workerToRunnerBytes: zod.z.number(),
36925
+ runnerToPoolRawBytes: zod.z.number(),
36926
+ runnerToPoolJpegBytes: zod.z.number(),
36927
+ onDemandFullFrameRequests: zod.z.number(),
36928
+ onDemandCropRequests: zod.z.number(),
36929
+ nativeHits: zod.z.number(),
36930
+ nativeMisses: zod.z.number(),
36931
+ tileHits: zod.z.number(),
36932
+ tileMisses: zod.z.number(),
36933
+ fallbackHits: zod.z.number(),
36934
+ fallbackMisses: zod.z.number(),
36935
+ retainedWritesAvoided: zod.z.number(),
36936
+ residentRefs: zod.z.number(),
36937
+ residentBytes: zod.z.number(),
36938
+ releases: zod.z.number(),
36939
+ evictions: zod.z.number(),
36940
+ staleMisses: zod.z.number()
36941
+ });
36942
+ var FrameLazyMetricsSchema = zod.z.object({
36943
+ node: FrameLazyCountersSchema,
36944
+ cameras: zod.z.array(FrameLazyCountersSchema.extend({ deviceId: zod.z.number() }))
36945
+ });
36783
36946
  var RunnerLocalMetricsSchema = zod.z.object({
36784
36947
  nodeId: zod.z.string(),
36785
36948
  activeCameras: zod.z.number(),
36786
36949
  throttledCameras: zod.z.number(),
36787
36950
  avgInferenceTimeMs: zod.z.number(),
36788
- queueDepth: zod.z.number()
36951
+ queueDepth: zod.z.number(),
36952
+ frameLazy: FrameLazyMetricsSchema.optional()
36789
36953
  });
36790
36954
  var pipelineRunnerCapability = {
36791
36955
  name: "pipeline-runner",
@@ -38570,6 +38734,8 @@ var require_dist_iAwSA2_f = __commonJS({
38570
38734
  endDownload: method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
38571
38735
  }
38572
38736
  };
38737
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
38738
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
38573
38739
  var TerminalSessionInfoSchema = zod.z.object({
38574
38740
  /** Opaque session id minted by the provider on `openSession`. */
38575
38741
  sessionId: zod.z.string(),
@@ -38585,7 +38751,14 @@ var require_dist_iAwSA2_f = __commonJS({
38585
38751
  var TerminalProfileInfoSchema = zod.z.object({
38586
38752
  profileId: zod.z.string(),
38587
38753
  label: zod.z.string(),
38588
- description: zod.z.string().optional()
38754
+ description: zod.z.string().optional(),
38755
+ /** Spawn defaults the instance form copies on create. */
38756
+ executable: zod.z.string().optional(),
38757
+ args: zod.z.array(zod.z.string()).readonly().optional(),
38758
+ cwd: zod.z.string().optional(),
38759
+ environment: zod.z.array(zod.z.string()).readonly().optional(),
38760
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
38761
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
38589
38762
  });
38590
38763
  var TerminalInstanceInfoSchema = zod.z.object({
38591
38764
  instanceId: zod.z.string(),
@@ -38594,7 +38767,12 @@ var require_dist_iAwSA2_f = __commonJS({
38594
38767
  profileId: zod.z.string(),
38595
38768
  profileLabel: zod.z.string(),
38596
38769
  name: zod.z.string(),
38597
- enabled: zod.z.boolean()
38770
+ enabled: zod.z.boolean(),
38771
+ executable: zod.z.string(),
38772
+ args: zod.z.array(zod.z.string()).readonly(),
38773
+ cwd: zod.z.string(),
38774
+ environment: zod.z.array(zod.z.string()).readonly(),
38775
+ profileSettings: ProfileSettingsBagSchema
38598
38776
  });
38599
38777
  var TerminalLegacyCameraSchema = zod.z.object({
38600
38778
  stableId: zod.z.string(),
@@ -38633,7 +38811,24 @@ var require_dist_iAwSA2_f = __commonJS({
38633
38811
  createInstance: method(zod.z.object({
38634
38812
  targetNodeId: zod.z.string().min(1),
38635
38813
  profileId: zod.z.string().min(1),
38636
- name: zod.z.string().trim().min(1).max(160).optional()
38814
+ name: zod.z.string().trim().min(1).max(160).optional(),
38815
+ executable: zod.z.string().max(1024).optional(),
38816
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38817
+ cwd: zod.z.string().max(1024).optional(),
38818
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
38819
+ profileSettings: ProfileSettingsBagSchema.optional()
38820
+ }), TerminalInstanceInfoSchema, {
38821
+ kind: "mutation",
38822
+ auth: "admin"
38823
+ }),
38824
+ updateInstance: method(zod.z.object({
38825
+ instanceId: zod.z.string().min(1),
38826
+ name: zod.z.string().trim().min(1).max(160).optional(),
38827
+ executable: zod.z.string().max(1024).optional(),
38828
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38829
+ cwd: zod.z.string().max(1024).optional(),
38830
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
38831
+ profileSettings: ProfileSettingsBagSchema.optional()
38637
38832
  }), TerminalInstanceInfoSchema, {
38638
38833
  kind: "mutation",
38639
38834
  auth: "admin"
@@ -38668,7 +38863,11 @@ var require_dist_iAwSA2_f = __commonJS({
38668
38863
  openSession: method(zod.z.object({
38669
38864
  profileId: zod.z.string(),
38670
38865
  cols: zod.z.number().int().positive(),
38671
- rows: zod.z.number().int().positive()
38866
+ rows: zod.z.number().int().positive(),
38867
+ executable: zod.z.string().max(1024).optional(),
38868
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
38869
+ cwd: zod.z.string().max(1024).optional(),
38870
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional()
38672
38871
  }), TerminalSessionInfoSchema, {
38673
38872
  kind: "mutation",
38674
38873
  auth: "admin"
@@ -42391,6 +42590,12 @@ var require_dist_iAwSA2_f = __commonJS({
42391
42590
  /** What the ranking currently resolves to (null when nothing is reachable). */
42392
42591
  resolved: zod.z.string().nullable()
42393
42592
  });
42593
+ var ViewerEndpointsSchema = zod.z.object({
42594
+ /** The operator's explicit race set, or empty for AUTO. */
42595
+ baseUrls: zod.z.array(zod.z.string()).readonly(),
42596
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
42597
+ resolved: zod.z.array(zod.z.string()).readonly()
42598
+ });
42394
42599
  var AllowedAddressesSchema = zod.z.object({
42395
42600
  /**
42396
42601
  * Allowlist of interface addresses operators have explicitly opted
@@ -42400,6 +42605,20 @@ var require_dist_iAwSA2_f = __commonJS({
42400
42605
  */
42401
42606
  addresses: zod.z.array(zod.z.string()).readonly()
42402
42607
  });
42608
+ var TlsStatusSchema = zod.z.object({
42609
+ mode: zod.z.enum([
42610
+ "generated",
42611
+ "uploaded",
42612
+ "disabled"
42613
+ ]),
42614
+ leafFingerprintSha256: zod.z.string().nullable(),
42615
+ caFingerprintSha256: zod.z.string().nullable(),
42616
+ validTo: zod.z.string().nullable(),
42617
+ sans: zod.z.array(zod.z.string()),
42618
+ caCertPem: zod.z.string().nullable(),
42619
+ reissueError: zod.z.string().nullable(),
42620
+ restartRequired: zod.z.boolean()
42621
+ });
42403
42622
  var localNetworkCapability = {
42404
42623
  name: "local-network",
42405
42624
  scope: "system",
@@ -42419,13 +42638,13 @@ var require_dist_iAwSA2_f = __commonJS({
42419
42638
  */
42420
42639
  getPreferred: method(zod.z.void(), PreferredSchema),
42421
42640
  /**
42422
- * Ordered candidate base URLs the SDK should try on connect.
42423
- * Includes LAN IPs (one per non-internal interface), the public
42424
- * tunnel hostname (when active), and loopback as a last-resort
42425
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
42426
- * Honours `getAllowedAddresses()` when set addresses outside
42427
- * the allowlist are dropped (the public tunnel + loopback are
42428
- * always included as escape hatches).
42641
+ * Ordered candidate base URLs (the palette the Network tab shows).
42642
+ * Includes LAN IPv4, stable LAN IPv6, the public tunnel, and mesh when
42643
+ * joined. Loopback is off by default. The SDK races the subset from
42644
+ * `getViewerEndpoints`, not this full list — IPv6 stays here because
42645
+ * WebRTC ICE gathers dual-stack regardless of the HTTP race. Honours
42646
+ * `getAllowedAddresses()` when set addresses outside the allowlist
42647
+ * are dropped (the public tunnel is still included as an escape hatch).
42429
42648
  *
42430
42649
  * **The port is the hub's, not the caller's** (D62 — a function's fact
42431
42650
  * belongs to whoever already owns it). This method used to take a `port`
@@ -42456,10 +42675,11 @@ var require_dist_iAwSA2_f = __commonJS({
42456
42675
  */
42457
42676
  port: zod.z.number().int().min(1).max(65535).optional(),
42458
42677
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
42459
- * candidate. Default `true`. */
42678
+ * candidate. Default `false` — loopback is not a client route. */
42460
42679
  includeLoopback: zod.z.boolean().optional(),
42461
- /** Skip IPv6 entries. Some legacy clients can't parse them.
42462
- * Default `false`. */
42680
+ /** Skip IPv6 entries. Default `false` the palette includes stable
42681
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
42682
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
42463
42683
  ipv4Only: zod.z.boolean().optional(),
42464
42684
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
42465
42685
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -42488,6 +42708,19 @@ var require_dist_iAwSA2_f = __commonJS({
42488
42708
  */
42489
42709
  setNotificationEndpoint: method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
42490
42710
  /**
42711
+ * The endpoints the SDK / viewer races for API access. Empty `baseUrls`
42712
+ * means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
42713
+ * never mesh, never loopback. `resolved` is that set (or the operator's
42714
+ * explicit subset) as it stands right now.
42715
+ */
42716
+ getViewerEndpoints: method(zod.z.void(), ViewerEndpointsSchema),
42717
+ /**
42718
+ * Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
42719
+ * verbatim (not indices) so a temporarily-down tunnel is not silently
42720
+ * dropped from the operator's choice.
42721
+ */
42722
+ setViewerEndpoints: method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
42723
+ /**
42491
42724
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
42492
42725
  * by the admin UI's address selector to seed its checkbox state.
42493
42726
  */
@@ -42505,7 +42738,34 @@ var require_dist_iAwSA2_f = __commonJS({
42505
42738
  * when the operator wants to wipe their manual edits and start
42506
42739
  * over from the auto-detected best matches.
42507
42740
  */
42508
- resetAllowlistToBestMatch: method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" })
42741
+ resetAllowlistToBestMatch: method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" }),
42742
+ /**
42743
+ * Live TLS material for the Network → Local access certificate card.
42744
+ * LAN HTTP / hostname are addon settings (`globalSettingsSchema`), not
42745
+ * a second store — this query is status, not configuration.
42746
+ */
42747
+ getTlsStatus: method(zod.z.void(), TlsStatusSchema),
42748
+ /** Issue a new leaf under the existing local CA. Disabled in uploaded mode. */
42749
+ regenerateCertificate: method(zod.z.object({ reason: zod.z.string().optional() }), TlsStatusSchema, {
42750
+ kind: "mutation",
42751
+ auth: "admin"
42752
+ }),
42753
+ /** Replace the served material with operator-supplied PEMs. */
42754
+ uploadCertificate: method(zod.z.object({
42755
+ certPem: zod.z.string().min(1),
42756
+ keyPem: zod.z.string().min(1),
42757
+ caPem: zod.z.string().optional()
42758
+ }), TlsStatusSchema, {
42759
+ kind: "mutation",
42760
+ auth: "admin"
42761
+ }),
42762
+ /** The local CA PEM, or empty when there is none to download. */
42763
+ downloadCa: method(zod.z.void(), zod.z.object({ pem: zod.z.string() })),
42764
+ /** Drop uploaded material and return to the generated local CA. */
42765
+ revertToGeneratedCertificate: method(zod.z.void(), TlsStatusSchema, {
42766
+ kind: "mutation",
42767
+ auth: "admin"
42768
+ })
42509
42769
  },
42510
42770
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
42511
42771
  mount: { kind: "hub-only" }
@@ -44038,7 +44298,12 @@ var require_dist_iAwSA2_f = __commonJS({
44038
44298
  plateBbox: BoundingBoxSchema.optional(),
44039
44299
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
44040
44300
  keyFrameMediaKey: zod.z.string().optional(),
44041
- base64: zod.z.string().optional()
44301
+ base64: zod.z.string().optional(),
44302
+ /**
44303
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
44304
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
44305
+ */
44306
+ cropUrl: zod.z.string().optional()
44042
44307
  });
44043
44308
  var MediaFileLiteSchema = zod.z.object({
44044
44309
  key: zod.z.string(),
@@ -49869,6 +50134,12 @@ var require_dist_iAwSA2_f = __commonJS({
49869
50134
  addonId: null,
49870
50135
  access: "create"
49871
50136
  },
50137
+ "localNetwork.downloadCa": {
50138
+ capName: "local-network",
50139
+ capScope: "system",
50140
+ addonId: null,
50141
+ access: "view"
50142
+ },
49872
50143
  "localNetwork.getAllowedAddresses": {
49873
50144
  capName: "local-network",
49874
50145
  capScope: "system",
@@ -49893,18 +50164,42 @@ var require_dist_iAwSA2_f = __commonJS({
49893
50164
  addonId: null,
49894
50165
  access: "view"
49895
50166
  },
50167
+ "localNetwork.getTlsStatus": {
50168
+ capName: "local-network",
50169
+ capScope: "system",
50170
+ addonId: null,
50171
+ access: "view"
50172
+ },
50173
+ "localNetwork.getViewerEndpoints": {
50174
+ capName: "local-network",
50175
+ capScope: "system",
50176
+ addonId: null,
50177
+ access: "view"
50178
+ },
49896
50179
  "localNetwork.list": {
49897
50180
  capName: "local-network",
49898
50181
  capScope: "system",
49899
50182
  addonId: null,
49900
50183
  access: "view"
49901
50184
  },
50185
+ "localNetwork.regenerateCertificate": {
50186
+ capName: "local-network",
50187
+ capScope: "system",
50188
+ addonId: null,
50189
+ access: "create"
50190
+ },
49902
50191
  "localNetwork.resetAllowlistToBestMatch": {
49903
50192
  capName: "local-network",
49904
50193
  capScope: "system",
49905
50194
  addonId: null,
49906
50195
  access: "delete"
49907
50196
  },
50197
+ "localNetwork.revertToGeneratedCertificate": {
50198
+ capName: "local-network",
50199
+ capScope: "system",
50200
+ addonId: null,
50201
+ access: "create"
50202
+ },
49908
50203
  "localNetwork.setAllowedAddresses": {
49909
50204
  capName: "local-network",
49910
50205
  capScope: "system",
@@ -49917,6 +50212,18 @@ var require_dist_iAwSA2_f = __commonJS({
49917
50212
  addonId: null,
49918
50213
  access: "create"
49919
50214
  },
50215
+ "localNetwork.setViewerEndpoints": {
50216
+ capName: "local-network",
50217
+ capScope: "system",
50218
+ addonId: null,
50219
+ access: "create"
50220
+ },
50221
+ "localNetwork.uploadCertificate": {
50222
+ capName: "local-network",
50223
+ capScope: "system",
50224
+ addonId: null,
50225
+ access: "create"
50226
+ },
49920
50227
  "lockControl.lock": {
49921
50228
  capName: "lock-control",
49922
50229
  capScope: "device",
@@ -50715,6 +51022,12 @@ var require_dist_iAwSA2_f = __commonJS({
50715
51022
  addonId: null,
50716
51023
  access: "view"
50717
51024
  },
51025
+ "pipelineAnalytics.getGroup": {
51026
+ capName: "pipeline-analytics",
51027
+ capScope: "device",
51028
+ addonId: null,
51029
+ access: "view"
51030
+ },
50718
51031
  "pipelineAnalytics.getKeyEvents": {
50719
51032
  capName: "pipeline-analytics",
50720
51033
  capScope: "device",
@@ -50799,6 +51112,12 @@ var require_dist_iAwSA2_f = __commonJS({
50799
51112
  addonId: null,
50800
51113
  access: "view"
50801
51114
  },
51115
+ "pipelineAnalytics.listGroups": {
51116
+ capName: "pipeline-analytics",
51117
+ capScope: "device",
51118
+ addonId: null,
51119
+ access: "view"
51120
+ },
50802
51121
  "pipelineAnalytics.listOpsLog": {
50803
51122
  capName: "pipeline-analytics",
50804
51123
  capScope: "device",
@@ -52797,6 +53116,12 @@ var require_dist_iAwSA2_f = __commonJS({
52797
53116
  addonId: null,
52798
53117
  access: "create"
52799
53118
  },
53119
+ "terminalSession.updateInstance": {
53120
+ capName: "terminal-session",
53121
+ capScope: "system",
53122
+ addonId: null,
53123
+ access: "create"
53124
+ },
52800
53125
  "terminalSession.writeInput": {
52801
53126
  capName: "terminal-session",
52802
53127
  capScope: "system",
@@ -54212,6 +54537,11 @@ var require_dist_iAwSA2_f = __commonJS({
54212
54537
  form: "single",
54213
54538
  optional: false
54214
54539
  }],
54540
+ "pipelineAnalytics.getGroup": [{
54541
+ name: "deviceId",
54542
+ form: "single",
54543
+ optional: false
54544
+ }],
54215
54545
  "pipelineAnalytics.getKeyEvents": [{
54216
54546
  name: "deviceId",
54217
54547
  form: "single",
@@ -54267,6 +54597,11 @@ var require_dist_iAwSA2_f = __commonJS({
54267
54597
  form: "array",
54268
54598
  optional: false
54269
54599
  }],
54600
+ "pipelineAnalytics.listGroups": [{
54601
+ name: "deviceIds",
54602
+ form: "array",
54603
+ optional: false
54604
+ }],
54270
54605
  "pipelineAnalytics.listOpsLog": [{
54271
54606
  name: "deviceId",
54272
54607
  form: "single",
@@ -55425,6 +55760,35 @@ var require_dist_iAwSA2_f = __commonJS({
55425
55760
  }]
55426
55761
  }].map((s) => [s.stepId, s.defaultModelId])));
55427
55762
  zod.z.string().min(1);
55763
+ var CLUSTER_STEP_SETTING_FIELDS = [{
55764
+ stepId: "face-embedding",
55765
+ key: "minLandmarkFaceSize",
55766
+ label: "Min face size for recognition (detection px)",
55767
+ 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.",
55768
+ type: "slider",
55769
+ min: 0,
55770
+ max: 64,
55771
+ step: 2,
55772
+ default: 24
55773
+ }];
55774
+ function clusterStepSettingKey(stepId, fieldKey) {
55775
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
55776
+ }
55777
+ var ClusterSettingNumberSchema = zod.z.number().finite();
55778
+ function readClusterStepSettings(config) {
55779
+ const out = {};
55780
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
55781
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
55782
+ const value = parsed.success ? parsed.data : field.default;
55783
+ const existing = out[field.stepId] ?? {};
55784
+ out[field.stepId] = {
55785
+ ...existing,
55786
+ [field.key]: value
55787
+ };
55788
+ }
55789
+ return out;
55790
+ }
55791
+ readClusterStepSettings({});
55428
55792
  zod.z.object({
55429
55793
  /**
55430
55794
  * Fraction of the box's own size added on EACH side before cutting.
@@ -56256,7 +56620,7 @@ var require_alerts_addon = __commonJS({
56256
56620
  [Symbol.toStringTag]: { value: "Module" }
56257
56621
  });
56258
56622
  require_chunk_Cek0wNdY();
56259
- var require_dist10 = require_dist_iAwSA2_f();
56623
+ var require_dist10 = require_dist_DnhGRFEn();
56260
56624
  function selectExpired(alerts, cutoffMs) {
56261
56625
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
56262
56626
  }
@@ -57075,7 +57439,7 @@ var require_console_logging = __commonJS({
57075
57439
  [Symbol.toStringTag]: { value: "Module" }
57076
57440
  });
57077
57441
  require_chunk_Cek0wNdY();
57078
- var require_dist10 = require_dist_iAwSA2_f();
57442
+ var require_dist10 = require_dist_DnhGRFEn();
57079
57443
  var require_formatter = require_formatter_DqAKDlvN();
57080
57444
  var LEVEL_RANK = {
57081
57445
  debug: 0,
@@ -57169,7 +57533,7 @@ var require_core_blocks_addon = __commonJS({
57169
57533
  "use strict";
57170
57534
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
57171
57535
  var require_chunk = require_chunk_Cek0wNdY();
57172
- var require_dist10 = require_dist_iAwSA2_f();
57536
+ var require_dist10 = require_dist_DnhGRFEn();
57173
57537
  var node_crypto = __require("crypto");
57174
57538
  var node_fs_promises = __require("fs/promises");
57175
57539
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -58066,11 +58430,11 @@ var require_core_blocks = __commonJS({
58066
58430
  }
58067
58431
  });
58068
58432
 
58069
- // ../system/dist/retired-settings-keys-OfhqQio4.js
58070
- var require_retired_settings_keys_OfhqQio4 = __commonJS({
58071
- "../system/dist/retired-settings-keys-OfhqQio4.js"(exports) {
58433
+ // ../system/dist/retired-settings-keys-D6Jy_SsO.js
58434
+ var require_retired_settings_keys_D6Jy_SsO = __commonJS({
58435
+ "../system/dist/retired-settings-keys-D6Jy_SsO.js"(exports) {
58072
58436
  "use strict";
58073
- var require_dist10 = require_dist_iAwSA2_f();
58437
+ var require_dist10 = require_dist_DnhGRFEn();
58074
58438
  function settingsStoreIsAuthoritativeHere(env) {
58075
58439
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
58076
58440
  return raw === "" || raw === "hub";
@@ -60113,8 +60477,8 @@ var require_device_manager_addon = __commonJS({
60113
60477
  [Symbol.toStringTag]: { value: "Module" }
60114
60478
  });
60115
60479
  require_chunk_Cek0wNdY();
60116
- var require_dist10 = require_dist_iAwSA2_f();
60117
- var require_retired_settings_keys = require_retired_settings_keys_OfhqQio4();
60480
+ var require_dist10 = require_dist_DnhGRFEn();
60481
+ var require_retired_settings_keys = require_retired_settings_keys_D6Jy_SsO();
60118
60482
  var node_crypto = __require("crypto");
60119
60483
  var _camstack_types_node = require_node();
60120
60484
  var JOB_HISTORY = 20;
@@ -64441,7 +64805,7 @@ var require_hub_forwarder = __commonJS({
64441
64805
  [Symbol.toStringTag]: { value: "Module" }
64442
64806
  });
64443
64807
  require_chunk_Cek0wNdY();
64444
- var require_dist10 = require_dist_iAwSA2_f();
64808
+ var require_dist10 = require_dist_DnhGRFEn();
64445
64809
  var require_formatter = require_formatter_DqAKDlvN();
64446
64810
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
64447
64811
  var HubForwarderDestination = class {
@@ -64578,7 +64942,7 @@ var require_liveness_monitor_addon = __commonJS({
64578
64942
  "use strict";
64579
64943
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
64580
64944
  require_chunk_Cek0wNdY();
64581
- var require_dist10 = require_dist_iAwSA2_f();
64945
+ var require_dist10 = require_dist_DnhGRFEn();
64582
64946
  var NO_DEVICES = "liveness:no-devices";
64583
64947
  var ALL_OFFLINE = "liveness:all-devices-offline";
64584
64948
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -64768,7 +65132,7 @@ var require_local_auth_addon = __commonJS({
64768
65132
  [Symbol.toStringTag]: { value: "Module" }
64769
65133
  });
64770
65134
  var require_chunk = require_chunk_Cek0wNdY();
64771
- var require_dist10 = require_dist_iAwSA2_f();
65135
+ var require_dist10 = require_dist_DnhGRFEn();
64772
65136
  var node_crypto = __require("crypto");
64773
65137
  node_crypto = require_chunk.__toESM(node_crypto);
64774
65138
  var crypto$1 = __require("crypto");
@@ -72452,7 +72816,7 @@ var require_loki_logging = __commonJS({
72452
72816
  [Symbol.toStringTag]: { value: "Module" }
72453
72817
  });
72454
72818
  require_chunk_Cek0wNdY();
72455
- var require_dist10 = require_dist_iAwSA2_f();
72819
+ var require_dist10 = require_dist_DnhGRFEn();
72456
72820
  function sanitizeLabelName(raw) {
72457
72821
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
72458
72822
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -73017,7 +73381,7 @@ var require_native_metrics_addon = __commonJS({
73017
73381
  [Symbol.toStringTag]: { value: "Module" }
73018
73382
  });
73019
73383
  var require_chunk = require_chunk_Cek0wNdY();
73020
- var require_dist10 = require_dist_iAwSA2_f();
73384
+ var require_dist10 = require_dist_DnhGRFEn();
73021
73385
  var node_child_process = __require("child_process");
73022
73386
  var node_util = __require("util");
73023
73387
  var node_os = __require("os");
@@ -73959,7 +74323,7 @@ var require_filesystem_storage_addon = __commonJS({
73959
74323
  [Symbol.toStringTag]: { value: "Module" }
73960
74324
  });
73961
74325
  var require_chunk = require_chunk_Cek0wNdY();
73962
- var require_dist10 = require_dist_iAwSA2_f();
74326
+ var require_dist10 = require_dist_DnhGRFEn();
73963
74327
  var node_crypto = __require("crypto");
73964
74328
  var node_fs_promises = __require("fs/promises");
73965
74329
  var node_path = __require("path");
@@ -75075,8 +75439,8 @@ var require_sqlite_settings_addon = __commonJS({
75075
75439
  [Symbol.toStringTag]: { value: "Module" }
75076
75440
  });
75077
75441
  var require_chunk = require_chunk_Cek0wNdY();
75078
- var require_dist10 = require_dist_iAwSA2_f();
75079
- var require_retired_settings_keys = require_retired_settings_keys_OfhqQio4();
75442
+ var require_dist10 = require_dist_DnhGRFEn();
75443
+ var require_retired_settings_keys = require_retired_settings_keys_D6Jy_SsO();
75080
75444
  var node_crypto = __require("crypto");
75081
75445
  var node_fs = __require("fs");
75082
75446
  var node_module = __require("module");
@@ -76420,6 +76784,17 @@ var require_sqlite_settings_addon = __commonJS({
76420
76784
  constructor() {
76421
76785
  super({});
76422
76786
  }
76787
+ /**
76788
+ * The engine behind `settings-store` cannot read that door during
76789
+ * `initialize()`. `BaseAddon` always `await`s `resolveConfig()` first;
76790
+ * on an isolated sqlite that round-trip is a UDS call to the parent,
76791
+ * and the parent is waiting for THIS child's post-init handshake before
76792
+ * it builds the door (D233). Live 1.2.152: 30 s hang, timeout, every
76793
+ * in-process builtin skipped, then this addon finished one second later.
76794
+ * Constructor defaults (`{}`) are the whole config this addon has.
76795
+ */
76796
+ async resolveConfig() {
76797
+ }
76423
76798
  async onInitialize() {
76424
76799
  const addonId = require_dist10.bareAddonId(this.ctx.id);
76425
76800
  const path = await import("path");
@@ -76535,6 +76910,7 @@ var require_sqlite_settings_addon = __commonJS({
76535
76910
  exports.WAL_IDLE_QUIET_MS = WAL_IDLE_QUIET_MS;
76536
76911
  exports.WAL_MAINTENANCE_INTERVAL_MS = WAL_MAINTENANCE_INTERVAL_MS;
76537
76912
  exports.WalMaintenance = WalMaintenance;
76913
+ exports.prefixRange = prefixRange;
76538
76914
  }
76539
76915
  });
76540
76916
 
@@ -76620,7 +76996,7 @@ var require_storage_orchestrator_addon = __commonJS({
76620
76996
  [Symbol.toStringTag]: { value: "Module" }
76621
76997
  });
76622
76998
  var require_chunk = require_chunk_Cek0wNdY();
76623
- var require_dist10 = require_dist_iAwSA2_f();
76999
+ var require_dist10 = require_dist_DnhGRFEn();
76624
77000
  var node_crypto = __require("crypto");
76625
77001
  var node_fs_promises = __require("fs/promises");
76626
77002
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -78499,7 +78875,7 @@ var require_system_config_addon = __commonJS({
78499
78875
  [Symbol.toStringTag]: { value: "Module" }
78500
78876
  });
78501
78877
  require_chunk_Cek0wNdY();
78502
- var require_dist10 = require_dist_iAwSA2_f();
78878
+ var require_dist10 = require_dist_DnhGRFEn();
78503
78879
  var SECTION_TITLES = {
78504
78880
  server: "Server",
78505
78881
  auth: "Authentication"
@@ -96560,7 +96936,7 @@ var require_winston_logging = __commonJS({
96560
96936
  [Symbol.toStringTag]: { value: "Module" }
96561
96937
  });
96562
96938
  var require_chunk = require_chunk_Cek0wNdY();
96563
- var require_dist10 = require_dist_iAwSA2_f();
96939
+ var require_dist10 = require_dist_DnhGRFEn();
96564
96940
  var require_formatter = require_formatter_DqAKDlvN();
96565
96941
  var node_path = __require("path");
96566
96942
  node_path = require_chunk.__toESM(node_path);
@@ -96697,9 +97073,9 @@ var require_winston_logging = __commonJS({
96697
97073
  }
96698
97074
  });
96699
97075
 
96700
- // ../system/dist/file-data-plane-DUHPHa-Y.js
96701
- var require_file_data_plane_DUHPHa_Y = __commonJS({
96702
- "../system/dist/file-data-plane-DUHPHa-Y.js"(exports) {
97076
+ // ../system/dist/file-data-plane-DO8KbxCe.js
97077
+ var require_file_data_plane_DO8KbxCe = __commonJS({
97078
+ "../system/dist/file-data-plane-DO8KbxCe.js"(exports) {
96703
97079
  "use strict";
96704
97080
  var require_chunk = require_chunk_Cek0wNdY();
96705
97081
  var node_crypto = __require("crypto");
@@ -96732,15 +97108,56 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96732
97108
  if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
96733
97109
  return headers;
96734
97110
  }
96735
- async function downloadFile(url, destPath, onProgress) {
97111
+ var DEFAULT_MAX_REDIRECTS = 5;
97112
+ function normalizeDownloadOptions(third) {
97113
+ if (typeof third === "function") return { onProgress: third };
97114
+ return third ?? {};
97115
+ }
97116
+ function isRedirectStatus(status) {
97117
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
97118
+ }
97119
+ function resolveRedirectUrl(current, location) {
97120
+ return new URL(location, current);
97121
+ }
97122
+ async function downloadFile(url, destPath, onProgressOrOptions) {
96736
97123
  if (node_fs.existsSync(destPath)) return destPath;
97124
+ const opts = normalizeDownloadOptions(onProgressOrOptions);
97125
+ const fetchImpl = opts.fetchImpl ?? fetch;
97126
+ const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
96737
97127
  node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
96738
97128
  const tmpPath = destPath + ".downloading";
96739
97129
  try {
96740
- const response = await fetch(url, {
96741
- redirect: "follow",
96742
- headers: buildHeaders(url)
96743
- });
97130
+ let current = url;
97131
+ const seen = /* @__PURE__ */ new Set();
97132
+ let response;
97133
+ const manual = opts.redirectPolicy !== void 0;
97134
+ for (let hop = 0; hop <= maxRedirects; hop++) {
97135
+ const parsed = new URL(current);
97136
+ if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
97137
+ if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
97138
+ seen.add(parsed.href);
97139
+ const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
97140
+ const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
97141
+ try {
97142
+ response = await fetchImpl(current, {
97143
+ redirect: manual ? "manual" : "follow",
97144
+ headers: buildHeaders(current),
97145
+ ...controller ? { signal: controller.signal } : {}
97146
+ });
97147
+ } finally {
97148
+ if (timer) clearTimeout(timer);
97149
+ }
97150
+ if (manual && isRedirectStatus(response.status)) {
97151
+ const location = response.headers.get("location");
97152
+ if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
97153
+ if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
97154
+ current = resolveRedirectUrl(current, location).href;
97155
+ continue;
97156
+ }
97157
+ break;
97158
+ }
97159
+ if (!response) throw new Error(`No response downloading ${url}`);
97160
+ if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
96744
97161
  if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
96745
97162
  if (!response.body) throw new Error(`No response body from ${url}`);
96746
97163
  const total = parseInt(response.headers.get("content-length") ?? "0", 10);
@@ -96751,9 +97168,10 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
96751
97168
  for (; ; ) {
96752
97169
  const { done, value } = await reader.read();
96753
97170
  if (done || !value) break;
96754
- fileStream.write(value);
96755
97171
  downloaded += value.length;
96756
- onProgress?.(downloaded, total);
97172
+ if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
97173
+ fileStream.write(value);
97174
+ opts.onProgress?.(downloaded, total);
96757
97175
  }
96758
97176
  } finally {
96759
97177
  fileStream.end();
@@ -97715,9 +98133,9 @@ var require_event_category_EY0GNjV9 = __commonJS({
97715
98133
  }
97716
98134
  });
97717
98135
 
97718
- // ../types/dist/sleep-C2XhJhkd.js
97719
- var require_sleep_C2XhJhkd = __commonJS({
97720
- "../types/dist/sleep-C2XhJhkd.js"(exports) {
98136
+ // ../types/dist/sleep-CizGYrCD.js
98137
+ var require_sleep_CizGYrCD = __commonJS({
98138
+ "../types/dist/sleep-CizGYrCD.js"(exports) {
97721
98139
  "use strict";
97722
98140
  var require_event_category = require_event_category_EY0GNjV9();
97723
98141
  var zod = require_zod();
@@ -98088,6 +98506,13 @@ var require_sleep_C2XhJhkd = __commonJS({
98088
98506
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
98089
98507
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
98090
98508
  _registeredCapNames = [];
98509
+ /**
98510
+ * True only after `readAddonStore` actually answered. Constructor
98511
+ * defaults look like stored config when the store is down — a forked
98512
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
98513
+ * mode, 2026-08-25) is not "the operator chose this".
98514
+ */
98515
+ settingsStoreReady = false;
98091
98516
  /** Default config values. Provided via constructor. */
98092
98517
  defaults;
98093
98518
  constructor(defaults) {
@@ -98493,7 +98918,9 @@ var require_sleep_C2XhJhkd = __commonJS({
98493
98918
  ];
98494
98919
  let lastErr;
98495
98920
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
98496
- return await settings.readAddonStore() ?? {};
98921
+ const stored = await settings.readAddonStore() ?? {};
98922
+ this.settingsStoreReady = true;
98923
+ return stored;
98497
98924
  } catch (err) {
98498
98925
  lastErr = err;
98499
98926
  const msg = err instanceof Error ? err.message : String(err);
@@ -98501,6 +98928,7 @@ var require_sleep_C2XhJhkd = __commonJS({
98501
98928
  if (attempt === delaysMs.length) break;
98502
98929
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
98503
98930
  }
98931
+ this.settingsStoreReady = false;
98504
98932
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries \u2014 using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
98505
98933
  return {};
98506
98934
  }
@@ -99759,6 +100187,73 @@ var require_sleep_C2XhJhkd = __commonJS({
99759
100187
  }
99760
100188
  };
99761
100189
  }
100190
+ function createEventBusSliceSource(deps) {
100191
+ const { eventBus, api } = deps;
100192
+ const cache2 = /* @__PURE__ */ new Map();
100193
+ const listeners = /* @__PURE__ */ new Map();
100194
+ let offBus = null;
100195
+ const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
100196
+ const fanOut = (deviceId, capName, slice) => {
100197
+ const k = keyOf(deviceId, capName);
100198
+ cache2.set(k, slice);
100199
+ const set = listeners.get(k);
100200
+ if (!set) return;
100201
+ for (const cb of set) try {
100202
+ cb(slice);
100203
+ } catch {
100204
+ }
100205
+ };
100206
+ const ensureBridge = () => {
100207
+ if (offBus) return;
100208
+ offBus = eventBus.subscribe({ category: DEVICE_STATE_EVENT_CATEGORY }, (event2) => {
100209
+ const data = event2.data;
100210
+ if (typeof data !== "object" || data === null) return;
100211
+ const deviceId = Reflect.get(data, "deviceId");
100212
+ const capName = Reflect.get(data, "capName");
100213
+ if (typeof deviceId !== "number" || typeof capName !== "string") return;
100214
+ fanOut(deviceId, capName, Reflect.get(data, "slice"));
100215
+ });
100216
+ };
100217
+ const closeBridgeIfIdle = () => {
100218
+ if (offBus === null) return;
100219
+ if (listeners.size > 0) return;
100220
+ offBus();
100221
+ offBus = null;
100222
+ };
100223
+ return {
100224
+ read(deviceId, capName) {
100225
+ return cache2.get(keyOf(deviceId, capName));
100226
+ },
100227
+ async refresh(deviceId, capName) {
100228
+ fanOut(deviceId, capName, await api.deviceState.getCapSlice.query({
100229
+ deviceId,
100230
+ capName
100231
+ }) ?? void 0);
100232
+ },
100233
+ watch(deviceId, capName, cb) {
100234
+ const k = keyOf(deviceId, capName);
100235
+ let set = listeners.get(k);
100236
+ if (!set) {
100237
+ set = /* @__PURE__ */ new Set();
100238
+ listeners.set(k, set);
100239
+ }
100240
+ set.add(cb);
100241
+ ensureBridge();
100242
+ return () => {
100243
+ set.delete(cb);
100244
+ if (set.size === 0) listeners.delete(k);
100245
+ closeBridgeIfIdle();
100246
+ };
100247
+ },
100248
+ async write(deviceId, capName, slice) {
100249
+ await api.deviceState.setCapSlice.mutate({
100250
+ deviceId,
100251
+ capName,
100252
+ slice
100253
+ });
100254
+ }
100255
+ };
100256
+ }
99762
100257
  function createMirrorSource(mirror, listeners, api) {
99763
100258
  const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
99764
100259
  return {
@@ -100178,6 +100673,8 @@ var require_sleep_C2XhJhkd = __commonJS({
100178
100673
  getTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrack", "query", input),
100179
100674
  listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
100180
100675
  listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
100676
+ listGroups: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listGroups", "query", input),
100677
+ getGroup: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getGroup", "query", input),
100181
100678
  clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
100182
100679
  getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
100183
100680
  getObjectEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getObjectEvents", "query", input),
@@ -100956,6 +101453,12 @@ var require_sleep_C2XhJhkd = __commonJS({
100956
101453
  return createEvent;
100957
101454
  }
100958
101455
  });
101456
+ Object.defineProperty(exports, "createEventBusSliceSource", {
101457
+ enumerable: true,
101458
+ get: function() {
101459
+ return createEventBusSliceSource;
101460
+ }
101461
+ });
100959
101462
  Object.defineProperty(exports, "createLazyTrpcSource", {
100960
101463
  enumerable: true,
100961
101464
  get: function() {
@@ -101157,7 +101660,7 @@ var require_addon = __commonJS({
101157
101660
  "use strict";
101158
101661
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
101159
101662
  var require_event_category = require_event_category_EY0GNjV9();
101160
- var require_sleep = require_sleep_C2XhJhkd();
101663
+ var require_sleep = require_sleep_CizGYrCD();
101161
101664
  var require_err_msg = require_err_msg_COpsHMw2();
101162
101665
  var CAP_INPUT_DEFAULTS = Object.freeze({
101163
101666
  "addons": { "getLogs": { "limit": 100 } },
@@ -101270,6 +101773,7 @@ var require_addon = __commonJS({
101270
101773
  "getMotionEvents": { "limit": 1e3 },
101271
101774
  "getObjectEvents": { "limit": 1e3 },
101272
101775
  "getSensorEvents": { "limit": 1e3 },
101776
+ "listGroups": { "limit": 40 },
101273
101777
  "listRecentTracks": { "limit": 200 },
101274
101778
  "searchObjectEvents": {
101275
101779
  "limit": 50,
@@ -101477,6 +101981,7 @@ var require_addon = __commonJS({
101477
101981
  exports.asJsonObject = require_sleep.asJsonObject;
101478
101982
  exports.asString = require_sleep.asString;
101479
101983
  exports.createDeviceProxy = require_sleep.createDeviceProxy;
101984
+ exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
101480
101985
  exports.deviceOpsCapability = require_sleep.deviceOpsCapability;
101481
101986
  exports.emitReadiness = require_sleep.emitReadiness;
101482
101987
  exports.errMsg = require_err_msg.errMsg;
@@ -108031,9 +108536,9 @@ var require_dist2 = __commonJS({
108031
108536
  }
108032
108537
  });
108033
108538
 
108034
- // ../system/dist/manifest-python-deps-CwBbX4Ut.js
108035
- var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108036
- "../system/dist/manifest-python-deps-CwBbX4Ut.js"(exports) {
108539
+ // ../system/dist/manifest-python-deps-B3_4YiDK.js
108540
+ var require_manifest_python_deps_B3_4YiDK = __commonJS({
108541
+ "../system/dist/manifest-python-deps-B3_4YiDK.js"(exports) {
108037
108542
  "use strict";
108038
108543
  var require_chunk = require_chunk_Cek0wNdY();
108039
108544
  var node_crypto = __require("crypto");
@@ -108049,6 +108554,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108049
108554
  var node_fs = __require("fs");
108050
108555
  node_fs = require_chunk.__toESM(node_fs);
108051
108556
  var node_http = __require("http");
108557
+ var node_perf_hooks = __require("perf_hooks");
108052
108558
  var node_v8 = __require("v8");
108053
108559
  node_v8 = require_chunk.__toESM(node_v8);
108054
108560
  var node_vm = __require("vm");
@@ -108066,6 +108572,41 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108066
108572
  }
108067
108573
  var HEAP_RECLAIM_TRIGGER_MB = 1024;
108068
108574
  var HEAP_RECLAIM_MIN_INTERVAL_MS = 12e4;
108575
+ var ZERO_LOOP_DELAY = {
108576
+ p50Ms: 0,
108577
+ p99Ms: 0,
108578
+ maxMs: 0
108579
+ };
108580
+ function createLoopDelayMeter(resolutionMs = 20) {
108581
+ try {
108582
+ const histogram = (0, node_perf_hooks.monitorEventLoopDelay)({ resolution: resolutionMs });
108583
+ histogram.enable();
108584
+ return {
108585
+ read: () => {
108586
+ try {
108587
+ if (histogram.count === 0) return ZERO_LOOP_DELAY;
108588
+ const sample = {
108589
+ p50Ms: Math.round(histogram.percentile(50) / 1e6),
108590
+ p99Ms: Math.round(histogram.percentile(99) / 1e6),
108591
+ maxMs: Math.round(histogram.max / 1e6)
108592
+ };
108593
+ histogram.reset();
108594
+ return sample;
108595
+ } catch {
108596
+ return ZERO_LOOP_DELAY;
108597
+ }
108598
+ },
108599
+ stop: () => {
108600
+ histogram.disable();
108601
+ }
108602
+ };
108603
+ } catch {
108604
+ return;
108605
+ }
108606
+ }
108607
+ function heapCeilingOrigin(execArgv = process.execArgv) {
108608
+ return execArgv.some((arg) => /^--max[-_]old[-_]space[-_]size(=|$)/.test(arg)) ? "explicit" : "v8-default";
108609
+ }
108069
108610
  var MB = (bytes) => Math.round(bytes / 1048576);
108070
108611
  function buildHeapSample(mem, heapLimitBytes, warnRatio = HEAP_WATCH_WARN_RATIO) {
108071
108612
  const usedRatio = heapLimitBytes > 0 ? mem.heapUsed / heapLimitBytes : 0;
@@ -108107,10 +108648,12 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108107
108648
  return;
108108
108649
  }
108109
108650
  }
108110
- function format2(label, s) {
108111
- return `[mem] ${label} rss=${s.rssMb}MB heapUsed=${s.heapUsedMb}MB heapTotal=${s.heapTotalMb}MB heapLimit=${s.heapLimitMb}MB used=${Math.round(s.usedRatio * 100)}% external=${s.externalMb}MB arrayBuffers=${s.arrayBuffersMb}MB`;
108651
+ function format2(label, s, loop) {
108652
+ const line = `[mem] ${label} rss=${s.rssMb}MB heapUsed=${s.heapUsedMb}MB heapTotal=${s.heapTotalMb}MB heapLimit=${s.heapLimitMb}MB used=${Math.round(s.usedRatio * 100)}% external=${s.externalMb}MB arrayBuffers=${s.arrayBuffersMb}MB`;
108653
+ if (loop === void 0) return line;
108654
+ return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms`;
108112
108655
  }
108113
- function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions) {
108656
+ function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv) {
108114
108657
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
108115
108658
  const now = reclaimOptions?.now ?? (() => Date.now());
108116
108659
  const triggerMb = reclaimOptions?.triggerMb ?? 1024;
@@ -108119,14 +108662,22 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108119
108662
  const escalateRatio = reclaimOptions?.escalateRatio ?? 0.7;
108120
108663
  const deescalateRatio = reclaimOptions?.deescalateRatio ?? 0.6;
108121
108664
  let lastReclaimAt = Number.NEGATIVE_INFINITY;
108665
+ let passesAtFloor = 0;
108666
+ let steadyStateAnnounced = false;
108122
108667
  const read = () => {
108123
108668
  const limit = reclaimOptions?.heapLimitBytes ?? node_v8.getHeapStatistics().heap_size_limit;
108124
108669
  return buildHeapSample(readMemory(), limit);
108125
108670
  };
108126
108671
  const maybeReclaim = (sample) => {
108127
108672
  if (reclaimOptions === void 0) return;
108128
- if (!shouldReclaim(sample, triggerMb)) return;
108129
- if (now() - lastReclaimAt < minIntervalMs) return;
108673
+ if (!shouldReclaim(sample, triggerMb)) {
108674
+ passesAtFloor = 0;
108675
+ steadyStateAnnounced = false;
108676
+ return;
108677
+ }
108678
+ const sinceLast = now() - lastReclaimAt;
108679
+ if (sinceLast < minIntervalMs) return;
108680
+ passesAtFloor = sinceLast <= minIntervalMs * 2 ? passesAtFloor + 1 : 1;
108130
108681
  lastReclaimAt = now();
108131
108682
  const startedAt = now();
108132
108683
  try {
@@ -108137,6 +108688,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108137
108688
  }
108138
108689
  const after = read();
108139
108690
  sink.info(`[mem] reclaim ${label} stranded=${strandedMb(sample)}MB rss=${sample.rssMb}MB\u2192${after.rssMb}MB freed=${sample.rssMb - after.rssMb}MB arrayBuffers=${sample.arrayBuffersMb}MB\u2192${after.arrayBuffersMb}MB took=${now() - startedAt}ms`);
108691
+ if (passesAtFloor >= 6 && !steadyStateAnnounced) {
108692
+ steadyStateAnnounced = true;
108693
+ sink.warn(`[mem] reclaim ${label} has run at the floor for ${passesAtFloor} consecutive passes (every ${minIntervalMs}ms) \u2014 the stop-the-world is now STEADY STATE, not a rescue. The allocation source is what needs the fix; this pass only bounds its peak.`);
108694
+ }
108140
108695
  };
108141
108696
  let mode = "steady";
108142
108697
  let lastLoggedAt = Number.NEGATIVE_INFINITY;
@@ -108150,7 +108705,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108150
108705
  const due = at - lastLoggedAt >= intervalMs;
108151
108706
  if (mode === "escalated" || due) {
108152
108707
  lastLoggedAt = at;
108153
- const line = format2(label, sample);
108708
+ const line = format2(label, sample, loopDelay?.read());
108154
108709
  if (sample.nearLimit) sink.warn(`${line} \u2014 APPROACHING HEAP LIMIT`);
108155
108710
  else if (mode === "escalated") sink.warn(`${line} \u2014 heap elevated, sampling every ${probeIntervalMs}ms`);
108156
108711
  else sink.info(line);
@@ -108163,11 +108718,13 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108163
108718
  const timer = setInterval(tick, probeIntervalMs);
108164
108719
  timer.unref?.();
108165
108720
  tick();
108721
+ if (heapCeilingOrigin(execArgv) === "v8-default") sink.info(`[mem] ${label} heap ceiling is V8's DEFAULT (${read().heapLimitMb}MB) \u2014 no --max-old-space-size on argv. Nothing here CHOSE that number; it is derived from host RAM and moves with it.`);
108166
108722
  let stopped = false;
108167
108723
  return () => {
108168
108724
  if (stopped) return;
108169
108725
  stopped = true;
108170
108726
  clearInterval(timer);
108727
+ loopDelay?.stop();
108171
108728
  };
108172
108729
  }
108173
108730
  var RUNNER_HEAP_WATCH_INTERVAL_MS = 3e5;
@@ -109259,6 +109816,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
109259
109816
  }
109260
109817
  function createBrokerDeviceManagerApi(opts) {
109261
109818
  const { api, addonId, nodeId, eventBus, registry } = opts;
109819
+ const deviceSliceSource = (0, _camstack_types_addon.createEventBusSliceSource)({
109820
+ eventBus,
109821
+ api
109822
+ });
109262
109823
  let selfApi;
109263
109824
  const deviceRebuildFactories = /* @__PURE__ */ new Map();
109264
109825
  const buildContext = (stableId, id, parentDeviceId = null, initialRuntimeState = {}, persistedConfig = {}, deviceMeta = null) => {
@@ -109303,7 +109864,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
109303
109864
  metadata: null
109304
109865
  },
109305
109866
  fetchDevice: async (deviceId) => {
109306
- return (0, _camstack_types_addon.createDeviceProxy)(api, await api.deviceManager.getBindings.query({ deviceId }));
109867
+ return (0, _camstack_types_addon.createDeviceProxy)(api, await api.deviceManager.getBindings.query({ deviceId }), { stateSource: deviceSliceSource });
109307
109868
  },
109308
109869
  get devices() {
109309
109870
  return selfApi;
@@ -114202,6 +114763,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
114202
114763
  const api = (0, _trpc_client.createTRPCClient)({ links });
114203
114764
  const scopedLogger = options?.createLogger?.(addonId) ?? (runtime.mode === "broker" ? createRemoteLogger(runtime.broker, addonId) : createUdsLogger(runtime.client, addonId, nodeId));
114204
114765
  const scopedEventBus = runtime.mode === "broker" ? createBrokerEventBus(runtime.broker, addonId) : createUdsEventBus(runtime.client, addonId);
114766
+ const deviceSliceSource = (0, _camstack_types_addon.createEventBusSliceSource)({
114767
+ eventBus: scopedEventBus,
114768
+ api
114769
+ });
114205
114770
  const workerDisposerChain = new _camstack_types_addon.DisposerChain({ onError: (err, index) => {
114206
114771
  scopedLogger.error(`Disposer #${index} threw during teardown`, { meta: { error: err instanceof Error ? err.message : String(err) } });
114207
114772
  } });
@@ -114437,10 +115002,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
114437
115002
  },
114438
115003
  fetchDevice: async (deviceId) => {
114439
115004
  const cached = bindingCache.get(deviceId);
114440
- if (cached) return (0, _camstack_types_addon.createDeviceProxy)(api, cached);
115005
+ if (cached) return (0, _camstack_types_addon.createDeviceProxy)(api, cached, { stateSource: deviceSliceSource });
114441
115006
  const binding = await api.deviceManager.getBindings.query({ deviceId });
114442
115007
  bindingCache.set(deviceId, binding);
114443
- return (0, _camstack_types_addon.createDeviceProxy)(api, binding);
115008
+ return (0, _camstack_types_addon.createDeviceProxy)(api, binding, { stateSource: deviceSliceSource });
114444
115009
  },
114445
115010
  useCapability(capName, scope = { type: "global" }) {
114446
115011
  return getOrCreateHandle(capName, scope, Number.POSITIVE_INFINITY);
@@ -115038,6 +115603,752 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
115038
115603
  }
115039
115604
  });
115040
115605
 
115606
+ // ../system/dist/lan-http-bind-DmgpFP6_.js
115607
+ var require_lan_http_bind_DmgpFP6 = __commonJS({
115608
+ "../system/dist/lan-http-bind-DmgpFP6_.js"(exports) {
115609
+ "use strict";
115610
+ var require_chunk = require_chunk_Cek0wNdY();
115611
+ var node_crypto = __require("crypto");
115612
+ var node_fs_promises = __require("fs/promises");
115613
+ var node_path = __require("path");
115614
+ var node_child_process = __require("child_process");
115615
+ var node_util = __require("util");
115616
+ var node_os = __require("os");
115617
+ node_os = require_chunk.__toESM(node_os);
115618
+ var node_fs = __require("fs");
115619
+ var node_http = __require("http");
115620
+ var node_net = __require("net");
115621
+ var SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
115622
+ var MAX_LEAF_VALIDITY_DAYS = 397;
115623
+ var LEAF_RENEWAL_WINDOW_DAYS = 30;
115624
+ var CA_VALIDITY_DAYS = 3650;
115625
+ var MS_PER_DAY = 864e5;
115626
+ var REASONS_REQUIRING_NEW_CA = [
115627
+ "missing",
115628
+ "unreadable",
115629
+ "no-local-ca",
115630
+ "ca-expiring"
115631
+ ];
115632
+ function reasonRequiresNewCa(reason) {
115633
+ return REASONS_REQUIRING_NEW_CA.includes(reason);
115634
+ }
115635
+ function parse4(pem) {
115636
+ try {
115637
+ return new node_crypto.X509Certificate(pem);
115638
+ } catch {
115639
+ return null;
115640
+ }
115641
+ }
115642
+ function daysBetween(from, to) {
115643
+ return (to.getTime() - from.getTime()) / MS_PER_DAY;
115644
+ }
115645
+ function hasServerAuthEku(leaf) {
115646
+ const eku = leaf.keyUsage;
115647
+ return eku !== void 0 && eku.length === 1 && eku[0] === "1.3.6.1.5.5.7.3.1";
115648
+ }
115649
+ function keyMatches(leaf, keyPem) {
115650
+ try {
115651
+ return leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem));
115652
+ } catch {
115653
+ return false;
115654
+ }
115655
+ }
115656
+ function coversIdentity(leaf, identity) {
115657
+ for (const name of identity.requiredDnsNames) if (leaf.checkHost(name) === void 0) return false;
115658
+ for (const ip of identity.requiredIpAddresses) if (leaf.checkIP(ip) === void 0) return false;
115659
+ return true;
115660
+ }
115661
+ function evaluateExistingCert(input) {
115662
+ const leaf = parse4(input.chainPem);
115663
+ const ca = parse4(input.caPem);
115664
+ if (leaf === null || ca === null) return "unreadable";
115665
+ if (daysBetween(input.now, new Date(ca.validTo)) < 427) return "ca-expiring";
115666
+ if (!keyMatches(leaf, input.keyPem)) return "key-mismatch";
115667
+ if (daysBetween(input.now, new Date(leaf.validTo)) < 30) return "expiring";
115668
+ if (!hasServerAuthEku(leaf)) return "missing-server-auth-eku";
115669
+ if (leaf.ca || !leaf.checkIssued(ca) || !leaf.verify(ca.publicKey)) return "not-issued-by-local-ca";
115670
+ if (daysBetween(new Date(leaf.validFrom), new Date(leaf.validTo)) > 398) return "validity-too-long";
115671
+ if (!coversIdentity(leaf, input.identity)) return "san-coverage-gap";
115672
+ return null;
115673
+ }
115674
+ var VOLATILE_INTERFACE_PREFIXES = [
115675
+ "docker",
115676
+ "br-",
115677
+ "veth",
115678
+ "virbr",
115679
+ "cni",
115680
+ "flannel",
115681
+ "tun",
115682
+ "utun",
115683
+ "tap",
115684
+ "wg",
115685
+ "zt",
115686
+ "tailscale",
115687
+ "ppp",
115688
+ "awdl",
115689
+ "llw"
115690
+ ];
115691
+ var DNS_NAME_PATTERN = /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/;
115692
+ function isIpv4(value) {
115693
+ return (0, node_net.isIP)(value) === 4;
115694
+ }
115695
+ function isIpv6(value) {
115696
+ return (0, node_net.isIP)(value) === 6;
115697
+ }
115698
+ function isLinkLocal(value) {
115699
+ if (isIpv4(value)) return value.startsWith("169.254.");
115700
+ if (!isIpv6(value)) return false;
115701
+ const firstGroup = value.split(":")[0] ?? "";
115702
+ if (firstGroup === "") return false;
115703
+ const parsed = Number.parseInt(firstGroup, 16);
115704
+ return Number.isFinite(parsed) && (parsed & 65472) === 65152;
115705
+ }
115706
+ function isUniqueLocalIpv6(value) {
115707
+ if (!isIpv6(value)) return false;
115708
+ const firstGroup = value.split(":")[0] ?? "";
115709
+ const parsed = Number.parseInt(firstGroup, 16);
115710
+ return Number.isFinite(parsed) && (parsed & 65024) === 64512;
115711
+ }
115712
+ function isVolatileInterface(name) {
115713
+ const lower = name.toLowerCase();
115714
+ return VOLATILE_INTERFACE_PREFIXES.some((prefix) => lower.startsWith(prefix));
115715
+ }
115716
+ function isStableGateAddress(address) {
115717
+ if (isLinkLocal(address)) return false;
115718
+ if (isIpv4(address)) return true;
115719
+ return isUniqueLocalIpv6(address);
115720
+ }
115721
+ function addSan(dns, ips, value) {
115722
+ const trimmed = value.trim();
115723
+ if (trimmed === "") return;
115724
+ if ((0, node_net.isIP)(trimmed) !== 0) {
115725
+ if (!isLinkLocal(trimmed)) ips.add(trimmed);
115726
+ return;
115727
+ }
115728
+ if (DNS_NAME_PATTERN.test(trimmed)) dns.add(trimmed);
115729
+ }
115730
+ function collectCertIdentity(options) {
115731
+ const dnsNames = /* @__PURE__ */ new Set();
115732
+ const ipAddresses = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
115733
+ const requiredDnsNames = /* @__PURE__ */ new Set();
115734
+ const requiredIpAddresses = /* @__PURE__ */ new Set(["127.0.0.1"]);
115735
+ for (const name of [
115736
+ "localhost",
115737
+ options.commonName,
115738
+ node_os.hostname()
115739
+ ]) {
115740
+ addSan(dnsNames, ipAddresses, name);
115741
+ addSan(requiredDnsNames, requiredIpAddresses, name);
115742
+ }
115743
+ for (const [ifaceName, addrs] of Object.entries(node_os.networkInterfaces())) for (const addr of addrs ?? []) {
115744
+ if (addr.internal) continue;
115745
+ if (isLinkLocal(addr.address)) continue;
115746
+ ipAddresses.add(addr.address);
115747
+ if (isVolatileInterface(ifaceName)) continue;
115748
+ if (isStableGateAddress(addr.address)) requiredIpAddresses.add(addr.address);
115749
+ }
115750
+ for (const san of options.extraSans) {
115751
+ addSan(dnsNames, ipAddresses, san);
115752
+ addSan(requiredDnsNames, requiredIpAddresses, san);
115753
+ }
115754
+ return {
115755
+ dnsNames: [...dnsNames],
115756
+ ipAddresses: [...ipAddresses],
115757
+ requiredDnsNames: [...requiredDnsNames],
115758
+ requiredIpAddresses: [...requiredIpAddresses]
115759
+ };
115760
+ }
115761
+ var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
115762
+ var CA_COMMON_NAME = "CamStack Local CA";
115763
+ function sanValue(identity) {
115764
+ const parts = [];
115765
+ for (const dns of identity.dnsNames) parts.push(`DNS:${dns}`);
115766
+ for (const ip of identity.ipAddresses) if ((0, node_net.isIP)(ip) !== 0) parts.push(`IP:${ip}`);
115767
+ return parts.join(",");
115768
+ }
115769
+ async function generateCa(tmpDir) {
115770
+ const caCertPath = (0, node_path.join)(tmpDir, "ca.crt");
115771
+ const caKeyPath = (0, node_path.join)(tmpDir, "ca.key");
115772
+ await execFileAsync("openssl", [
115773
+ "req",
115774
+ "-x509",
115775
+ "-newkey",
115776
+ "rsa:2048",
115777
+ "-nodes",
115778
+ "-sha256",
115779
+ "-days",
115780
+ String(CA_VALIDITY_DAYS),
115781
+ "-keyout",
115782
+ caKeyPath,
115783
+ "-out",
115784
+ caCertPath,
115785
+ "-subj",
115786
+ `/CN=${CA_COMMON_NAME}`,
115787
+ "-addext",
115788
+ "basicConstraints=critical,CA:TRUE,pathlen:0",
115789
+ "-addext",
115790
+ "keyUsage=critical,keyCertSign,cRLSign",
115791
+ "-addext",
115792
+ "subjectKeyIdentifier=hash"
115793
+ ]);
115794
+ await (0, node_fs_promises.chmod)(caKeyPath, 384);
115795
+ return {
115796
+ caCertPath,
115797
+ caKeyPath
115798
+ };
115799
+ }
115800
+ async function issueLeaf(tmpDir, ca, identity, commonName, validDays) {
115801
+ const keyPath = (0, node_path.join)(tmpDir, "leaf.key");
115802
+ const csrPath = (0, node_path.join)(tmpDir, "leaf.csr");
115803
+ const certPath = (0, node_path.join)(tmpDir, "leaf.crt");
115804
+ const extPath = (0, node_path.join)(tmpDir, "leaf.ext");
115805
+ await (0, node_fs_promises.writeFile)(extPath, [
115806
+ "basicConstraints=critical,CA:FALSE",
115807
+ "keyUsage=critical,digitalSignature,keyEncipherment",
115808
+ "extendedKeyUsage=serverAuth",
115809
+ "subjectKeyIdentifier=hash",
115810
+ "authorityKeyIdentifier=keyid,issuer",
115811
+ `subjectAltName=${sanValue(identity)}`,
115812
+ ""
115813
+ ].join("\n"), "utf-8");
115814
+ await execFileAsync("openssl", [
115815
+ "req",
115816
+ "-new",
115817
+ "-newkey",
115818
+ "rsa:2048",
115819
+ "-nodes",
115820
+ "-sha256",
115821
+ "-keyout",
115822
+ keyPath,
115823
+ "-out",
115824
+ csrPath,
115825
+ "-subj",
115826
+ `/CN=${commonName}`
115827
+ ]);
115828
+ await execFileAsync("openssl", [
115829
+ "x509",
115830
+ "-req",
115831
+ "-in",
115832
+ csrPath,
115833
+ "-CA",
115834
+ ca.caCertPath,
115835
+ "-CAkey",
115836
+ ca.caKeyPath,
115837
+ "-set_serial",
115838
+ `0x00${(0, node_crypto.randomBytes)(16).toString("hex")}`,
115839
+ "-days",
115840
+ String(validDays),
115841
+ "-sha256",
115842
+ "-extfile",
115843
+ extPath,
115844
+ "-out",
115845
+ certPath
115846
+ ]);
115847
+ await (0, node_fs_promises.chmod)(keyPath, 384);
115848
+ await (0, node_fs_promises.rm)(csrPath, { force: true });
115849
+ await (0, node_fs_promises.rm)(extPath, { force: true });
115850
+ return {
115851
+ certPath,
115852
+ keyPath
115853
+ };
115854
+ }
115855
+ var DEFAULT_COMMON_NAME = "camstack.local";
115856
+ async function ensureTlsCert(dataDir, options) {
115857
+ const tlsDir2 = (0, node_path.join)(dataDir, "tls");
115858
+ const paths = {
115859
+ certPath: (0, node_path.join)(tlsDir2, "camstack.crt"),
115860
+ keyPath: (0, node_path.join)(tlsDir2, "camstack.key"),
115861
+ caCertPath: (0, node_path.join)(tlsDir2, "camstack-ca.crt"),
115862
+ caKeyPath: (0, node_path.join)(tlsDir2, "camstack-ca.key")
115863
+ };
115864
+ const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
115865
+ const validDays = Math.min(options?.validDays ?? 397, 397);
115866
+ const identity = collectCertIdentity({
115867
+ commonName,
115868
+ extraSans: options?.extraSans ?? []
115869
+ });
115870
+ const reason = decideRegeneration(paths, identity);
115871
+ if (reason === null) return describe(paths, false, null, false, null, null);
115872
+ const previousFingerprint = readFingerprint(paths.certPath);
115873
+ const caRotated = reasonRequiresNewCa(reason);
115874
+ (0, node_fs.mkdirSync)(tlsDir2, { recursive: true });
115875
+ try {
115876
+ await regenerate(paths, identity, commonName, validDays, caRotated);
115877
+ } catch (err) {
115878
+ const message = err instanceof Error ? err.message : String(err);
115879
+ if (!canKeepServing(paths)) throw err;
115880
+ return describe(paths, false, null, false, null, message);
115881
+ }
115882
+ return describe(paths, true, reason, caRotated, previousFingerprint, null);
115883
+ }
115884
+ async function reissueTlsLeaf(dataDir, options) {
115885
+ const tlsDir2 = (0, node_path.join)(dataDir, "tls");
115886
+ const paths = {
115887
+ certPath: (0, node_path.join)(tlsDir2, "camstack.crt"),
115888
+ keyPath: (0, node_path.join)(tlsDir2, "camstack.key"),
115889
+ caCertPath: (0, node_path.join)(tlsDir2, "camstack-ca.crt"),
115890
+ caKeyPath: (0, node_path.join)(tlsDir2, "camstack-ca.key")
115891
+ };
115892
+ if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return ensureTlsCert(dataDir, options);
115893
+ const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
115894
+ const validDays = Math.min(options?.validDays ?? 397, 397);
115895
+ const identity = collectCertIdentity({
115896
+ commonName,
115897
+ extraSans: options?.extraSans ?? []
115898
+ });
115899
+ const previousFingerprint = readFingerprint(paths.certPath);
115900
+ (0, node_fs.mkdirSync)(tlsDir2, { recursive: true });
115901
+ await regenerate(paths, identity, commonName, validDays, false);
115902
+ return describe(paths, true, "san-coverage-gap", false, previousFingerprint, null);
115903
+ }
115904
+ function canKeepServing(paths) {
115905
+ if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return false;
115906
+ if (!(0, node_fs.existsSync)(paths.caCertPath)) return false;
115907
+ return readFingerprint(paths.certPath) !== null;
115908
+ }
115909
+ function readFingerprint(certPath) {
115910
+ try {
115911
+ return new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath)).fingerprint256;
115912
+ } catch {
115913
+ return null;
115914
+ }
115915
+ }
115916
+ function decideRegeneration(paths, identity) {
115917
+ if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return "missing";
115918
+ if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return "no-local-ca";
115919
+ try {
115920
+ return evaluateExistingCert({
115921
+ chainPem: (0, node_fs.readFileSync)(paths.certPath, "utf-8"),
115922
+ keyPem: (0, node_fs.readFileSync)(paths.keyPath, "utf-8"),
115923
+ caPem: (0, node_fs.readFileSync)(paths.caCertPath, "utf-8"),
115924
+ identity,
115925
+ now: /* @__PURE__ */ new Date()
115926
+ });
115927
+ } catch {
115928
+ return "unreadable";
115929
+ }
115930
+ }
115931
+ async function regenerate(paths, identity, commonName, validDays, newCa) {
115932
+ const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "camstack-tls-"));
115933
+ try {
115934
+ const ca = newCa ? await generateCa(scratch) : {
115935
+ caCertPath: paths.caCertPath,
115936
+ caKeyPath: paths.caKeyPath
115937
+ };
115938
+ const leaf = await issueLeaf(scratch, ca, identity, commonName, validDays);
115939
+ const chainPath = (0, node_path.join)(scratch, "chain.crt");
115940
+ await (0, node_fs_promises.writeFile)(chainPath, `${(0, node_fs.readFileSync)(leaf.certPath, "utf-8").trimEnd()}
115941
+ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
115942
+ `, "utf-8");
115943
+ if (newCa) {
115944
+ await (0, node_fs_promises.copyFile)(ca.caCertPath, `${paths.caCertPath}.new`);
115945
+ await (0, node_fs_promises.copyFile)(ca.caKeyPath, `${paths.caKeyPath}.new`);
115946
+ (0, node_fs.renameSync)(`${paths.caCertPath}.new`, paths.caCertPath);
115947
+ (0, node_fs.renameSync)(`${paths.caKeyPath}.new`, paths.caKeyPath);
115948
+ await (0, node_fs_promises.chmod)(paths.caKeyPath, 384);
115949
+ }
115950
+ await (0, node_fs_promises.copyFile)(leaf.keyPath, `${paths.keyPath}.new`);
115951
+ await (0, node_fs_promises.copyFile)(chainPath, `${paths.certPath}.new`);
115952
+ (0, node_fs.renameSync)(`${paths.keyPath}.new`, paths.keyPath);
115953
+ (0, node_fs.renameSync)(`${paths.certPath}.new`, paths.certPath);
115954
+ await (0, node_fs_promises.chmod)(paths.keyPath, 384);
115955
+ } finally {
115956
+ await (0, node_fs_promises.rm)(scratch, {
115957
+ recursive: true,
115958
+ force: true
115959
+ });
115960
+ }
115961
+ }
115962
+ function describe(paths, generated, reason, caRotated, previousFingerprintSha256, reissueError) {
115963
+ const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.certPath));
115964
+ const ca = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.caCertPath));
115965
+ const san = leaf.subjectAltName ?? "";
115966
+ return {
115967
+ ...paths,
115968
+ generated,
115969
+ reason,
115970
+ caRotated,
115971
+ fingerprintSha256: leaf.fingerprint256,
115972
+ previousFingerprintSha256,
115973
+ caFingerprintSha256: ca.fingerprint256,
115974
+ validTo: new Date(leaf.validTo).toISOString(),
115975
+ sans: san === "" ? [] : san.split(", "),
115976
+ reissueError
115977
+ };
115978
+ }
115979
+ function loadTlsCert(certPath, keyPath) {
115980
+ return {
115981
+ cert: (0, node_fs.readFileSync)(certPath),
115982
+ key: (0, node_fs.readFileSync)(keyPath)
115983
+ };
115984
+ }
115985
+ function validateUploadedTls(certPem, keyPem) {
115986
+ let leaf;
115987
+ try {
115988
+ leaf = new node_crypto.X509Certificate(certPem);
115989
+ } catch {
115990
+ return {
115991
+ ok: false,
115992
+ error: "Certificate PEM could not be parsed."
115993
+ };
115994
+ }
115995
+ try {
115996
+ if (!leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem))) return {
115997
+ ok: false,
115998
+ error: "Private key does not match the certificate."
115999
+ };
116000
+ } catch {
116001
+ return {
116002
+ ok: false,
116003
+ error: "Private key PEM could not be parsed."
116004
+ };
116005
+ }
116006
+ const eku = leaf.keyUsage;
116007
+ if (eku === void 0 || !eku.includes("1.3.6.1.5.5.7.3.1")) return {
116008
+ ok: false,
116009
+ error: "Certificate is missing extendedKeyUsage = serverAuth."
116010
+ };
116011
+ return {
116012
+ ok: true,
116013
+ fingerprintSha256: leaf.fingerprint256,
116014
+ validTo: new Date(leaf.validTo).toISOString()
116015
+ };
116016
+ }
116017
+ function tlsDir(dataDir) {
116018
+ return (0, node_path.join)(dataDir, "tls");
116019
+ }
116020
+ function readTlsMode(dataDir) {
116021
+ const marker = (0, node_path.join)(tlsDir(dataDir), "mode");
116022
+ if ((0, node_fs.existsSync)(marker)) {
116023
+ const raw = (0, node_fs.readFileSync)(marker, "utf-8").trim();
116024
+ if (raw === "uploaded") return "uploaded";
116025
+ if (raw === "disabled") return "disabled";
116026
+ }
116027
+ return (0, node_fs.existsSync)((0, node_path.join)(tlsDir(dataDir), "camstack.crt")) ? "generated" : "disabled";
116028
+ }
116029
+ function writeTlsMode(dataDir, mode) {
116030
+ (0, node_fs.mkdirSync)(tlsDir(dataDir), { recursive: true });
116031
+ (0, node_fs.writeFileSync)((0, node_path.join)(tlsDir(dataDir), "mode"), `${mode}
116032
+ `, "utf-8");
116033
+ }
116034
+ function readExtraSans(dataDir) {
116035
+ const path = (0, node_path.join)(tlsDir(dataDir), "extra-sans.json");
116036
+ if (!(0, node_fs.existsSync)(path)) return [];
116037
+ try {
116038
+ const parsed = JSON.parse((0, node_fs.readFileSync)(path, "utf-8"));
116039
+ if (!Array.isArray(parsed)) return [];
116040
+ return parsed.filter((entry) => typeof entry === "string" && entry.length > 0);
116041
+ } catch {
116042
+ return [];
116043
+ }
116044
+ }
116045
+ function writeExtraSans(dataDir, sans) {
116046
+ (0, node_fs.mkdirSync)(tlsDir(dataDir), { recursive: true });
116047
+ (0, node_fs.writeFileSync)((0, node_path.join)(tlsDir(dataDir), "extra-sans.json"), `${JSON.stringify(sans)}
116048
+ `, "utf-8");
116049
+ }
116050
+ function readTlsAccessStatus(dataDir, restartRequired = false) {
116051
+ const dir = tlsDir(dataDir);
116052
+ const certPath = (0, node_path.join)(dir, "camstack.crt");
116053
+ const caPath = (0, node_path.join)(dir, "camstack-ca.crt");
116054
+ const mode = readTlsMode(dataDir);
116055
+ if (!(0, node_fs.existsSync)(certPath)) return {
116056
+ mode: "disabled",
116057
+ leafFingerprintSha256: null,
116058
+ caFingerprintSha256: null,
116059
+ validTo: null,
116060
+ sans: [],
116061
+ caCertPem: (0, node_fs.existsSync)(caPath) ? (0, node_fs.readFileSync)(caPath, "utf-8") : null,
116062
+ reissueError: null,
116063
+ restartRequired
116064
+ };
116065
+ try {
116066
+ const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath));
116067
+ const caPem = (0, node_fs.existsSync)(caPath) ? (0, node_fs.readFileSync)(caPath, "utf-8") : null;
116068
+ const ca = caPem !== null ? new node_crypto.X509Certificate(caPem) : null;
116069
+ const san = leaf.subjectAltName ?? "";
116070
+ return {
116071
+ mode,
116072
+ leafFingerprintSha256: leaf.fingerprint256,
116073
+ caFingerprintSha256: ca?.fingerprint256 ?? null,
116074
+ validTo: new Date(leaf.validTo).toISOString(),
116075
+ sans: san === "" ? [] : san.split(", "),
116076
+ caCertPem: caPem,
116077
+ reissueError: null,
116078
+ restartRequired
116079
+ };
116080
+ } catch {
116081
+ return {
116082
+ mode,
116083
+ leafFingerprintSha256: null,
116084
+ caFingerprintSha256: null,
116085
+ validTo: null,
116086
+ sans: [],
116087
+ caCertPem: null,
116088
+ reissueError: "Certificate on disk could not be parsed.",
116089
+ restartRequired
116090
+ };
116091
+ }
116092
+ }
116093
+ var DEFAULT_HTTP_PORT = 4480;
116094
+ var handlers = null;
116095
+ var server = null;
116096
+ var pending = null;
116097
+ var state = {
116098
+ listening: false,
116099
+ error: null,
116100
+ port: DEFAULT_HTTP_PORT
116101
+ };
116102
+ var boundRequestedHost = null;
116103
+ var DEFAULT_LAN_HTTP_PORT = DEFAULT_HTTP_PORT;
116104
+ function allFamiliesListenHost(host) {
116105
+ if (host === "0.0.0.0" || host === "*" || host === "") return {
116106
+ host: "::",
116107
+ ipv6Only: false
116108
+ };
116109
+ return {
116110
+ host,
116111
+ ipv6Only: false
116112
+ };
116113
+ }
116114
+ function registerLanHttpHandler(next) {
116115
+ handlers = next;
116116
+ }
116117
+ function readLanHttpState() {
116118
+ return state;
116119
+ }
116120
+ async function applyLanHttp(options) {
116121
+ pending = options;
116122
+ if (!options.enabled) {
116123
+ await closeLanHttp();
116124
+ state = {
116125
+ listening: false,
116126
+ error: null,
116127
+ port: options.port
116128
+ };
116129
+ return state;
116130
+ }
116131
+ if (handlers === null) {
116132
+ state = {
116133
+ listening: false,
116134
+ error: "HTTP listener is not registered yet",
116135
+ port: options.port
116136
+ };
116137
+ return state;
116138
+ }
116139
+ if (server !== null && state.listening && (options.port === 0 || state.port === options.port) && boundRequestedHost === options.host) return state;
116140
+ await closeLanHttp();
116141
+ try {
116142
+ const bound = await listenHttp(options.port, options.host, handlers);
116143
+ server = bound;
116144
+ boundRequestedHost = options.host;
116145
+ const addr = bound.address();
116146
+ state = {
116147
+ listening: true,
116148
+ error: null,
116149
+ port: typeof addr === "object" && addr !== null ? addr.port : options.port
116150
+ };
116151
+ return state;
116152
+ } catch (err) {
116153
+ server = null;
116154
+ state = {
116155
+ listening: false,
116156
+ error: err instanceof Error ? err.message : String(err),
116157
+ port: options.port
116158
+ };
116159
+ return state;
116160
+ }
116161
+ }
116162
+ async function bindPendingLanHttp() {
116163
+ if (pending === null) return applyLanHttp({
116164
+ enabled: true,
116165
+ port: DEFAULT_HTTP_PORT,
116166
+ host: "0.0.0.0"
116167
+ });
116168
+ return applyLanHttp(pending);
116169
+ }
116170
+ async function closeLanHttp() {
116171
+ const current = server;
116172
+ server = null;
116173
+ boundRequestedHost = null;
116174
+ if (current === null) return;
116175
+ await new Promise((resolve) => {
116176
+ current.close(() => resolve());
116177
+ });
116178
+ }
116179
+ function listenHttp(port, host, next) {
116180
+ const resolved = allFamiliesListenHost(host);
116181
+ return listenOn(port, resolved, next).catch((err) => {
116182
+ if (resolved.host === "::" && host !== "::") return listenOn(port, {
116183
+ host: "0.0.0.0",
116184
+ ipv6Only: false
116185
+ }, next);
116186
+ throw err;
116187
+ });
116188
+ }
116189
+ function listenOn(port, bind, next) {
116190
+ return new Promise((resolve, reject) => {
116191
+ const created = (0, node_http.createServer)(next.onRequest);
116192
+ created.on("upgrade", next.onUpgrade);
116193
+ const onError = (err) => {
116194
+ created.off("listening", onListening);
116195
+ created.close();
116196
+ reject(err);
116197
+ };
116198
+ const onListening = () => {
116199
+ created.off("error", onError);
116200
+ resolve(created);
116201
+ };
116202
+ created.once("error", onError);
116203
+ created.once("listening", onListening);
116204
+ created.listen({
116205
+ port,
116206
+ host: bind.host,
116207
+ ipv6Only: bind.ipv6Only
116208
+ });
116209
+ });
116210
+ }
116211
+ Object.defineProperty(exports, "CA_COMMON_NAME", {
116212
+ enumerable: true,
116213
+ get: function() {
116214
+ return CA_COMMON_NAME;
116215
+ }
116216
+ });
116217
+ Object.defineProperty(exports, "CA_VALIDITY_DAYS", {
116218
+ enumerable: true,
116219
+ get: function() {
116220
+ return CA_VALIDITY_DAYS;
116221
+ }
116222
+ });
116223
+ Object.defineProperty(exports, "DEFAULT_LAN_HTTP_PORT", {
116224
+ enumerable: true,
116225
+ get: function() {
116226
+ return DEFAULT_LAN_HTTP_PORT;
116227
+ }
116228
+ });
116229
+ Object.defineProperty(exports, "LEAF_RENEWAL_WINDOW_DAYS", {
116230
+ enumerable: true,
116231
+ get: function() {
116232
+ return LEAF_RENEWAL_WINDOW_DAYS;
116233
+ }
116234
+ });
116235
+ Object.defineProperty(exports, "MAX_LEAF_VALIDITY_DAYS", {
116236
+ enumerable: true,
116237
+ get: function() {
116238
+ return MAX_LEAF_VALIDITY_DAYS;
116239
+ }
116240
+ });
116241
+ Object.defineProperty(exports, "SERVER_AUTH_OID", {
116242
+ enumerable: true,
116243
+ get: function() {
116244
+ return SERVER_AUTH_OID;
116245
+ }
116246
+ });
116247
+ Object.defineProperty(exports, "allFamiliesListenHost", {
116248
+ enumerable: true,
116249
+ get: function() {
116250
+ return allFamiliesListenHost;
116251
+ }
116252
+ });
116253
+ Object.defineProperty(exports, "applyLanHttp", {
116254
+ enumerable: true,
116255
+ get: function() {
116256
+ return applyLanHttp;
116257
+ }
116258
+ });
116259
+ Object.defineProperty(exports, "bindPendingLanHttp", {
116260
+ enumerable: true,
116261
+ get: function() {
116262
+ return bindPendingLanHttp;
116263
+ }
116264
+ });
116265
+ Object.defineProperty(exports, "closeLanHttp", {
116266
+ enumerable: true,
116267
+ get: function() {
116268
+ return closeLanHttp;
116269
+ }
116270
+ });
116271
+ Object.defineProperty(exports, "collectCertIdentity", {
116272
+ enumerable: true,
116273
+ get: function() {
116274
+ return collectCertIdentity;
116275
+ }
116276
+ });
116277
+ Object.defineProperty(exports, "ensureTlsCert", {
116278
+ enumerable: true,
116279
+ get: function() {
116280
+ return ensureTlsCert;
116281
+ }
116282
+ });
116283
+ Object.defineProperty(exports, "evaluateExistingCert", {
116284
+ enumerable: true,
116285
+ get: function() {
116286
+ return evaluateExistingCert;
116287
+ }
116288
+ });
116289
+ Object.defineProperty(exports, "loadTlsCert", {
116290
+ enumerable: true,
116291
+ get: function() {
116292
+ return loadTlsCert;
116293
+ }
116294
+ });
116295
+ Object.defineProperty(exports, "readExtraSans", {
116296
+ enumerable: true,
116297
+ get: function() {
116298
+ return readExtraSans;
116299
+ }
116300
+ });
116301
+ Object.defineProperty(exports, "readLanHttpState", {
116302
+ enumerable: true,
116303
+ get: function() {
116304
+ return readLanHttpState;
116305
+ }
116306
+ });
116307
+ Object.defineProperty(exports, "readTlsAccessStatus", {
116308
+ enumerable: true,
116309
+ get: function() {
116310
+ return readTlsAccessStatus;
116311
+ }
116312
+ });
116313
+ Object.defineProperty(exports, "readTlsMode", {
116314
+ enumerable: true,
116315
+ get: function() {
116316
+ return readTlsMode;
116317
+ }
116318
+ });
116319
+ Object.defineProperty(exports, "registerLanHttpHandler", {
116320
+ enumerable: true,
116321
+ get: function() {
116322
+ return registerLanHttpHandler;
116323
+ }
116324
+ });
116325
+ Object.defineProperty(exports, "reissueTlsLeaf", {
116326
+ enumerable: true,
116327
+ get: function() {
116328
+ return reissueTlsLeaf;
116329
+ }
116330
+ });
116331
+ Object.defineProperty(exports, "validateUploadedTls", {
116332
+ enumerable: true,
116333
+ get: function() {
116334
+ return validateUploadedTls;
116335
+ }
116336
+ });
116337
+ Object.defineProperty(exports, "writeExtraSans", {
116338
+ enumerable: true,
116339
+ get: function() {
116340
+ return writeExtraSans;
116341
+ }
116342
+ });
116343
+ Object.defineProperty(exports, "writeTlsMode", {
116344
+ enumerable: true,
116345
+ get: function() {
116346
+ return writeTlsMode;
116347
+ }
116348
+ });
116349
+ }
116350
+ });
116351
+
115041
116352
  // ../system/dist/custom-action-registry-jY0NOZK8.js
115042
116353
  var require_custom_action_registry_jY0NOZK8 = __commonJS({
115043
116354
  "../system/dist/custom-action-registry-jY0NOZK8.js"(exports) {
@@ -118837,7 +120148,7 @@ var require_dist3 = __commonJS({
118837
120148
  "use strict";
118838
120149
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
118839
120150
  var require_chunk = require_chunk_Cek0wNdY();
118840
- var require_dist10 = require_dist_iAwSA2_f();
120151
+ var require_dist10 = require_dist_DnhGRFEn();
118841
120152
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
118842
120153
  require_alerts();
118843
120154
  var require_formatter = require_formatter_DqAKDlvN();
@@ -118861,9 +120172,10 @@ var require_dist3 = __commonJS({
118861
120172
  var require_builtins_system_config_system_config_addon = require_system_config_addon();
118862
120173
  require_system_config();
118863
120174
  var require_builtins_winston_logging_index = require_winston_logging();
118864
- var require_file_data_plane = require_file_data_plane_DUHPHa_Y();
118865
- var require_manifest_python_deps = require_manifest_python_deps_CwBbX4Ut();
120175
+ var require_file_data_plane = require_file_data_plane_DO8KbxCe();
120176
+ var require_manifest_python_deps = require_manifest_python_deps_B3_4YiDK();
118866
120177
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
120178
+ var require_lan_http_bind = require_lan_http_bind_DmgpFP6();
118867
120179
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
118868
120180
  var zod = require_zod();
118869
120181
  var node_crypto = __require("crypto");
@@ -118883,7 +120195,6 @@ var require_dist3 = __commonJS({
118883
120195
  var node_vm = __require("vm");
118884
120196
  node_vm = require_chunk.__toESM(node_vm);
118885
120197
  var _camstack_types_addon = require_addon();
118886
- var node_net = __require("net");
118887
120198
  var node_url = __require("url");
118888
120199
  var node_events = __require("events");
118889
120200
  var node_stream = __require("stream");
@@ -120169,7 +121480,7 @@ var require_dist3 = __commonJS({
120169
121480
  if (node.children) for (const child of node.children) this.validateNode(child, errors, warnings);
120170
121481
  }
120171
121482
  };
120172
- var execFileAsync$4 = (0, node_util.promisify)(node_child_process.execFile);
121483
+ var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120173
121484
  var PythonEnvManager = class {
120174
121485
  venvPath;
120175
121486
  cachedProbe = null;
@@ -120179,12 +121490,12 @@ var require_dist3 = __commonJS({
120179
121490
  async probe() {
120180
121491
  if (this.cachedProbe) return this.cachedProbe;
120181
121492
  for (const cmd of ["python3", "python"]) try {
120182
- const { stdout } = await execFileAsync$4(cmd, ["--version"]);
121493
+ const { stdout } = await execFileAsync$3(cmd, ["--version"]);
120183
121494
  const version2 = stdout.trim().replace("Python ", "");
120184
121495
  const major = parseInt(version2.split(".")[0] ?? "0", 10);
120185
121496
  const minor = parseInt(version2.split(".")[1] ?? "0", 10);
120186
121497
  if (major < 3 || major === 3 && minor < 10) continue;
120187
- const { stdout: pathOut } = await execFileAsync$4(cmd, ["-c", "import sys; print(sys.executable)"]);
121498
+ const { stdout: pathOut } = await execFileAsync$3(cmd, ["-c", "import sys; print(sys.executable)"]);
120188
121499
  this.cachedProbe = {
120189
121500
  available: true,
120190
121501
  version: version2,
@@ -120200,13 +121511,13 @@ var require_dist3 = __commonJS({
120200
121511
  async ensure(options) {
120201
121512
  const probe = await this.probe();
120202
121513
  if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
120203
- if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$4(probe.path, [
121514
+ if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$3(probe.path, [
120204
121515
  "-m",
120205
121516
  "venv",
120206
121517
  this.venvPath
120207
121518
  ]);
120208
121519
  const venvPython = node_path.join(this.venvPath, "bin", "python");
120209
- if (options.packages.length > 0) await execFileAsync$4(venvPython, [
121520
+ if (options.packages.length > 0) await execFileAsync$3(venvPython, [
120210
121521
  "-m",
120211
121522
  "pip",
120212
121523
  "install",
@@ -120648,338 +121959,6 @@ var require_dist3 = __commonJS({
120648
121959
  };
120649
121960
  }
120650
121961
  };
120651
- var SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
120652
- var MAX_LEAF_VALIDITY_DAYS = 397;
120653
- var LEAF_RENEWAL_WINDOW_DAYS = 30;
120654
- var CA_VALIDITY_DAYS = 3650;
120655
- var MS_PER_DAY = 864e5;
120656
- var REASONS_REQUIRING_NEW_CA = [
120657
- "missing",
120658
- "unreadable",
120659
- "no-local-ca",
120660
- "ca-expiring"
120661
- ];
120662
- function reasonRequiresNewCa(reason) {
120663
- return REASONS_REQUIRING_NEW_CA.includes(reason);
120664
- }
120665
- function parse$1(pem) {
120666
- try {
120667
- return new node_crypto.X509Certificate(pem);
120668
- } catch {
120669
- return null;
120670
- }
120671
- }
120672
- function daysBetween(from, to) {
120673
- return (to.getTime() - from.getTime()) / MS_PER_DAY;
120674
- }
120675
- function hasServerAuthEku(leaf) {
120676
- const eku = leaf.keyUsage;
120677
- return eku !== void 0 && eku.length === 1 && eku[0] === "1.3.6.1.5.5.7.3.1";
120678
- }
120679
- function keyMatches(leaf, keyPem) {
120680
- try {
120681
- return leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem));
120682
- } catch {
120683
- return false;
120684
- }
120685
- }
120686
- function coversIdentity(leaf, identity) {
120687
- for (const name2 of identity.requiredDnsNames) if (leaf.checkHost(name2) === void 0) return false;
120688
- for (const ip of identity.requiredIpAddresses) if (leaf.checkIP(ip) === void 0) return false;
120689
- return true;
120690
- }
120691
- function evaluateExistingCert(input) {
120692
- const leaf = parse$1(input.chainPem);
120693
- const ca = parse$1(input.caPem);
120694
- if (leaf === null || ca === null) return "unreadable";
120695
- if (daysBetween(input.now, new Date(ca.validTo)) < 427) return "ca-expiring";
120696
- if (!keyMatches(leaf, input.keyPem)) return "key-mismatch";
120697
- if (daysBetween(input.now, new Date(leaf.validTo)) < 30) return "expiring";
120698
- if (!hasServerAuthEku(leaf)) return "missing-server-auth-eku";
120699
- if (leaf.ca || !leaf.checkIssued(ca) || !leaf.verify(ca.publicKey)) return "not-issued-by-local-ca";
120700
- if (daysBetween(new Date(leaf.validFrom), new Date(leaf.validTo)) > 398) return "validity-too-long";
120701
- if (!coversIdentity(leaf, input.identity)) return "san-coverage-gap";
120702
- return null;
120703
- }
120704
- var VOLATILE_INTERFACE_PREFIXES = [
120705
- "docker",
120706
- "br-",
120707
- "veth",
120708
- "virbr",
120709
- "cni",
120710
- "flannel",
120711
- "tun",
120712
- "utun",
120713
- "tap",
120714
- "wg",
120715
- "zt",
120716
- "tailscale",
120717
- "ppp",
120718
- "awdl",
120719
- "llw"
120720
- ];
120721
- var DNS_NAME_PATTERN = /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/;
120722
- function isIpv4(value) {
120723
- return (0, node_net.isIP)(value) === 4;
120724
- }
120725
- function isIpv6(value) {
120726
- return (0, node_net.isIP)(value) === 6;
120727
- }
120728
- function isLinkLocal(value) {
120729
- if (isIpv4(value)) return value.startsWith("169.254.");
120730
- if (!isIpv6(value)) return false;
120731
- const firstGroup = value.split(":")[0] ?? "";
120732
- if (firstGroup === "") return false;
120733
- const parsed = Number.parseInt(firstGroup, 16);
120734
- return Number.isFinite(parsed) && (parsed & 65472) === 65152;
120735
- }
120736
- function isUniqueLocalIpv6(value) {
120737
- if (!isIpv6(value)) return false;
120738
- const firstGroup = value.split(":")[0] ?? "";
120739
- const parsed = Number.parseInt(firstGroup, 16);
120740
- return Number.isFinite(parsed) && (parsed & 65024) === 64512;
120741
- }
120742
- function isVolatileInterface(name2) {
120743
- const lower = name2.toLowerCase();
120744
- return VOLATILE_INTERFACE_PREFIXES.some((prefix) => lower.startsWith(prefix));
120745
- }
120746
- function isStableGateAddress(address) {
120747
- if (isLinkLocal(address)) return false;
120748
- if (isIpv4(address)) return true;
120749
- return isUniqueLocalIpv6(address);
120750
- }
120751
- function addSan(dns, ips, value) {
120752
- const trimmed = value.trim();
120753
- if (trimmed === "") return;
120754
- if ((0, node_net.isIP)(trimmed) !== 0) {
120755
- if (!isLinkLocal(trimmed)) ips.add(trimmed);
120756
- return;
120757
- }
120758
- if (DNS_NAME_PATTERN.test(trimmed)) dns.add(trimmed);
120759
- }
120760
- function collectCertIdentity(options) {
120761
- const dnsNames = /* @__PURE__ */ new Set();
120762
- const ipAddresses = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
120763
- const requiredDnsNames = /* @__PURE__ */ new Set();
120764
- const requiredIpAddresses = /* @__PURE__ */ new Set(["127.0.0.1"]);
120765
- for (const name2 of [
120766
- "localhost",
120767
- options.commonName,
120768
- node_os.hostname()
120769
- ]) {
120770
- addSan(dnsNames, ipAddresses, name2);
120771
- addSan(requiredDnsNames, requiredIpAddresses, name2);
120772
- }
120773
- for (const [ifaceName, addrs] of Object.entries(node_os.networkInterfaces())) for (const addr of addrs ?? []) {
120774
- if (addr.internal) continue;
120775
- if (isLinkLocal(addr.address)) continue;
120776
- ipAddresses.add(addr.address);
120777
- if (isVolatileInterface(ifaceName)) continue;
120778
- if (isStableGateAddress(addr.address)) requiredIpAddresses.add(addr.address);
120779
- }
120780
- for (const san of options.extraSans) {
120781
- addSan(dnsNames, ipAddresses, san);
120782
- addSan(requiredDnsNames, requiredIpAddresses, san);
120783
- }
120784
- return {
120785
- dnsNames: [...dnsNames],
120786
- ipAddresses: [...ipAddresses],
120787
- requiredDnsNames: [...requiredDnsNames],
120788
- requiredIpAddresses: [...requiredIpAddresses]
120789
- };
120790
- }
120791
- var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
120792
- var CA_COMMON_NAME = "CamStack Local CA";
120793
- function sanValue(identity) {
120794
- const parts = [];
120795
- for (const dns of identity.dnsNames) parts.push(`DNS:${dns}`);
120796
- for (const ip of identity.ipAddresses) if ((0, node_net.isIP)(ip) !== 0) parts.push(`IP:${ip}`);
120797
- return parts.join(",");
120798
- }
120799
- async function generateCa(tmpDir) {
120800
- const caCertPath = (0, node_path.join)(tmpDir, "ca.crt");
120801
- const caKeyPath = (0, node_path.join)(tmpDir, "ca.key");
120802
- await execFileAsync$3("openssl", [
120803
- "req",
120804
- "-x509",
120805
- "-newkey",
120806
- "rsa:2048",
120807
- "-nodes",
120808
- "-sha256",
120809
- "-days",
120810
- String(CA_VALIDITY_DAYS),
120811
- "-keyout",
120812
- caKeyPath,
120813
- "-out",
120814
- caCertPath,
120815
- "-subj",
120816
- `/CN=${CA_COMMON_NAME}`,
120817
- "-addext",
120818
- "basicConstraints=critical,CA:TRUE,pathlen:0",
120819
- "-addext",
120820
- "keyUsage=critical,keyCertSign,cRLSign",
120821
- "-addext",
120822
- "subjectKeyIdentifier=hash"
120823
- ]);
120824
- await (0, node_fs_promises.chmod)(caKeyPath, 384);
120825
- return {
120826
- caCertPath,
120827
- caKeyPath
120828
- };
120829
- }
120830
- async function issueLeaf(tmpDir, ca, identity, commonName, validDays) {
120831
- const keyPath = (0, node_path.join)(tmpDir, "leaf.key");
120832
- const csrPath = (0, node_path.join)(tmpDir, "leaf.csr");
120833
- const certPath = (0, node_path.join)(tmpDir, "leaf.crt");
120834
- const extPath = (0, node_path.join)(tmpDir, "leaf.ext");
120835
- await (0, node_fs_promises.writeFile)(extPath, [
120836
- "basicConstraints=critical,CA:FALSE",
120837
- "keyUsage=critical,digitalSignature,keyEncipherment",
120838
- "extendedKeyUsage=serverAuth",
120839
- "subjectKeyIdentifier=hash",
120840
- "authorityKeyIdentifier=keyid,issuer",
120841
- `subjectAltName=${sanValue(identity)}`,
120842
- ""
120843
- ].join("\n"), "utf-8");
120844
- await execFileAsync$3("openssl", [
120845
- "req",
120846
- "-new",
120847
- "-newkey",
120848
- "rsa:2048",
120849
- "-nodes",
120850
- "-sha256",
120851
- "-keyout",
120852
- keyPath,
120853
- "-out",
120854
- csrPath,
120855
- "-subj",
120856
- `/CN=${commonName}`
120857
- ]);
120858
- await execFileAsync$3("openssl", [
120859
- "x509",
120860
- "-req",
120861
- "-in",
120862
- csrPath,
120863
- "-CA",
120864
- ca.caCertPath,
120865
- "-CAkey",
120866
- ca.caKeyPath,
120867
- "-set_serial",
120868
- `0x00${(0, node_crypto.randomBytes)(16).toString("hex")}`,
120869
- "-days",
120870
- String(validDays),
120871
- "-sha256",
120872
- "-extfile",
120873
- extPath,
120874
- "-out",
120875
- certPath
120876
- ]);
120877
- await (0, node_fs_promises.chmod)(keyPath, 384);
120878
- await (0, node_fs_promises.rm)(csrPath, { force: true });
120879
- await (0, node_fs_promises.rm)(extPath, { force: true });
120880
- return {
120881
- certPath,
120882
- keyPath
120883
- };
120884
- }
120885
- var DEFAULT_COMMON_NAME = "camstack.local";
120886
- async function ensureTlsCert(dataDir, options) {
120887
- const tlsDir = (0, node_path.join)(dataDir, "tls");
120888
- const paths = {
120889
- certPath: (0, node_path.join)(tlsDir, "camstack.crt"),
120890
- keyPath: (0, node_path.join)(tlsDir, "camstack.key"),
120891
- caCertPath: (0, node_path.join)(tlsDir, "camstack-ca.crt"),
120892
- caKeyPath: (0, node_path.join)(tlsDir, "camstack-ca.key")
120893
- };
120894
- const commonName = options?.commonName ?? DEFAULT_COMMON_NAME;
120895
- const validDays = Math.min(options?.validDays ?? 397, 397);
120896
- const identity = collectCertIdentity({
120897
- commonName,
120898
- extraSans: options?.extraSans ?? []
120899
- });
120900
- const reason = decideRegeneration(paths, identity);
120901
- if (reason === null) return describe(paths, false, null, false, null);
120902
- const previousFingerprint = readFingerprint(paths.certPath);
120903
- const caRotated = reasonRequiresNewCa(reason);
120904
- (0, node_fs.mkdirSync)(tlsDir, { recursive: true });
120905
- await regenerate(paths, identity, commonName, validDays, caRotated);
120906
- return describe(paths, true, reason, caRotated, previousFingerprint);
120907
- }
120908
- function readFingerprint(certPath) {
120909
- try {
120910
- return new node_crypto.X509Certificate((0, node_fs.readFileSync)(certPath)).fingerprint256;
120911
- } catch {
120912
- return null;
120913
- }
120914
- }
120915
- function decideRegeneration(paths, identity) {
120916
- if (!(0, node_fs.existsSync)(paths.certPath) || !(0, node_fs.existsSync)(paths.keyPath)) return "missing";
120917
- if (!(0, node_fs.existsSync)(paths.caCertPath) || !(0, node_fs.existsSync)(paths.caKeyPath)) return "no-local-ca";
120918
- try {
120919
- return evaluateExistingCert({
120920
- chainPem: (0, node_fs.readFileSync)(paths.certPath, "utf-8"),
120921
- keyPem: (0, node_fs.readFileSync)(paths.keyPath, "utf-8"),
120922
- caPem: (0, node_fs.readFileSync)(paths.caCertPath, "utf-8"),
120923
- identity,
120924
- now: /* @__PURE__ */ new Date()
120925
- });
120926
- } catch {
120927
- return "unreadable";
120928
- }
120929
- }
120930
- async function regenerate(paths, identity, commonName, validDays, newCa) {
120931
- const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "camstack-tls-"));
120932
- try {
120933
- const ca = newCa ? await generateCa(scratch) : {
120934
- caCertPath: paths.caCertPath,
120935
- caKeyPath: paths.caKeyPath
120936
- };
120937
- const leaf = await issueLeaf(scratch, ca, identity, commonName, validDays);
120938
- const chainPath = (0, node_path.join)(scratch, "chain.crt");
120939
- await (0, node_fs_promises.writeFile)(chainPath, `${(0, node_fs.readFileSync)(leaf.certPath, "utf-8").trimEnd()}
120940
- ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
120941
- `, "utf-8");
120942
- if (newCa) {
120943
- await (0, node_fs_promises.copyFile)(ca.caCertPath, `${paths.caCertPath}.new`);
120944
- await (0, node_fs_promises.copyFile)(ca.caKeyPath, `${paths.caKeyPath}.new`);
120945
- (0, node_fs.renameSync)(`${paths.caCertPath}.new`, paths.caCertPath);
120946
- (0, node_fs.renameSync)(`${paths.caKeyPath}.new`, paths.caKeyPath);
120947
- await (0, node_fs_promises.chmod)(paths.caKeyPath, 384);
120948
- }
120949
- await (0, node_fs_promises.copyFile)(leaf.keyPath, `${paths.keyPath}.new`);
120950
- await (0, node_fs_promises.copyFile)(chainPath, `${paths.certPath}.new`);
120951
- (0, node_fs.renameSync)(`${paths.keyPath}.new`, paths.keyPath);
120952
- (0, node_fs.renameSync)(`${paths.certPath}.new`, paths.certPath);
120953
- await (0, node_fs_promises.chmod)(paths.keyPath, 384);
120954
- } finally {
120955
- await (0, node_fs_promises.rm)(scratch, {
120956
- recursive: true,
120957
- force: true
120958
- });
120959
- }
120960
- }
120961
- function describe(paths, generated, reason, caRotated, previousFingerprintSha256) {
120962
- const leaf = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.certPath));
120963
- const ca = new node_crypto.X509Certificate((0, node_fs.readFileSync)(paths.caCertPath));
120964
- const san = leaf.subjectAltName ?? "";
120965
- return {
120966
- ...paths,
120967
- generated,
120968
- reason,
120969
- caRotated,
120970
- fingerprintSha256: leaf.fingerprint256,
120971
- previousFingerprintSha256,
120972
- caFingerprintSha256: ca.fingerprint256,
120973
- validTo: new Date(leaf.validTo).toISOString(),
120974
- sans: san === "" ? [] : san.split(", ")
120975
- };
120976
- }
120977
- function loadTlsCert(certPath, keyPath) {
120978
- return {
120979
- cert: (0, node_fs.readFileSync)(certPath),
120980
- key: (0, node_fs.readFileSync)(keyPath)
120981
- };
120982
- }
120983
121962
  function serializeSetting(value) {
120984
121963
  if (typeof value === "number") return {
120985
121964
  value: String(value),
@@ -121418,7 +122397,7 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
121418
122397
  if (missing.length > 0) throw new Error(`${options.addonName} \u2014 required native module(s) missing a compiled .node after install (bundled-copy + prebuild-fetch both failed): ${missing.join(", ")}`);
121419
122398
  return results;
121420
122399
  }
121421
- function isRecord$1(value) {
122400
+ function isRecord$2(value) {
121422
122401
  return typeof value === "object" && value !== null && !Array.isArray(value);
121423
122402
  }
121424
122403
  var PACKAGE_JSON_LOOKUP_DEPTH = 4;
@@ -121458,9 +122437,9 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
121458
122437
  return import(`${(0, node_url.pathToFileURL)(entryPath).href}?v=${encodeURIComponent(bust)}`);
121459
122438
  }
121460
122439
  function toAddonPackageManifest(value) {
121461
- if (!isRecord$1(value)) return void 0;
122440
+ if (!isRecord$2(value)) return void 0;
121462
122441
  if (!Array.isArray(value.addons)) return void 0;
121463
- if (!value.addons.every((a) => isRecord$1(a) && typeof a.id === "string")) return void 0;
122442
+ if (!value.addons.every((a) => isRecord$2(a) && typeof a.id === "string")) return void 0;
121464
122443
  return value;
121465
122444
  }
121466
122445
  var noopLogger$1 = {
@@ -121602,7 +122581,7 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
121602
122581
  }
121603
122582
  if (!node_fs.existsSync(entryPath)) throw new Error(`Entry not found: ${entryPath}`);
121604
122583
  const modUnknown = await importAddonModuleFresh(entryPath);
121605
- const mod = isRecord$1(modUnknown) ? modUnknown : {};
122584
+ const mod = isRecord$2(modUnknown) ? modUnknown : {};
121606
122585
  const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
121607
122586
  if (!AddonClass) throw new Error(`No addon class in ${entryPath}`);
121608
122587
  this.addons.set(declaration.id, {
@@ -121618,7 +122597,7 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
121618
122597
  /** Load addon from a direct path (for development/testing) */
121619
122598
  async loadFromPath(addonId, modulePath, packageName, declaration, packageVersion = "0.0.0") {
121620
122599
  const modUnknown = await importAddonModuleFresh(modulePath);
121621
- const mod = isRecord$1(modUnknown) ? modUnknown : {};
122600
+ const mod = isRecord$2(modUnknown) ? modUnknown : {};
121622
122601
  const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
121623
122602
  if (!AddonClass) throw new Error(`Module ${modulePath} has no default export`);
121624
122603
  this.addons.set(addonId, {
@@ -124981,6 +125960,143 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
124981
125960
  function isInfraCapability(name2) {
124982
125961
  return infraNames.has(name2);
124983
125962
  }
125963
+ var INFRA_NAMES = new Set(INFRA_CAPABILITIES.map((c) => c.name));
125964
+ function isolatedBuiltinPhase(capabilities) {
125965
+ return capabilities.some((c) => INFRA_NAMES.has(c.name)) ? "infra" : "consumer";
125966
+ }
125967
+ function partitionIsolatedBuiltinIds(ids, capabilitiesOf) {
125968
+ const infra = [];
125969
+ const consumers = [];
125970
+ for (const id of ids) if (isolatedBuiltinPhase(capabilitiesOf(id)) === "infra") infra.push(id);
125971
+ else consumers.push(id);
125972
+ return {
125973
+ infra,
125974
+ consumers
125975
+ };
125976
+ }
125977
+ async function waitUntilReady(isReady, options) {
125978
+ const deadline = Date.now() + options.timeoutMs;
125979
+ for (; ; ) {
125980
+ if (isReady()) return;
125981
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${options.what}`);
125982
+ await new Promise((resolve) => {
125983
+ setTimeout(resolve, options.intervalMs);
125984
+ });
125985
+ }
125986
+ }
125987
+ async function runHubAddonBoot(steps) {
125988
+ await steps.spawnIsolatedInfra();
125989
+ await steps.waitForDataStoreProvider();
125990
+ await steps.bootInProcessInfra();
125991
+ await steps.spawnForkedAddons();
125992
+ await steps.bootInProcessConsumers();
125993
+ await steps.spawnIsolatedConsumers();
125994
+ }
125995
+ function isRecord$1(value) {
125996
+ return typeof value === "object" && value !== null && !Array.isArray(value);
125997
+ }
125998
+ function asBlob(value) {
125999
+ return isRecord$1(value) ? value : {};
126000
+ }
126001
+ function unwrapValue(parsed) {
126002
+ if (!isRecord$1(parsed) || !("value" in parsed)) return parsed;
126003
+ return parsed.value;
126004
+ }
126005
+ async function loadPrefixed(door, collection, prefix) {
126006
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(prefix);
126007
+ const rows = await door.query({
126008
+ collection,
126009
+ ...range !== null ? { filter: { whereBetween: { id: [range.lo, range.hi] } } } : {}
126010
+ });
126011
+ const result = {};
126012
+ for (const row of rows) {
126013
+ if (range !== null && (row.id < range.lo || row.id >= range.hi)) continue;
126014
+ if (!row.id.startsWith(prefix)) continue;
126015
+ result[row.id.slice(prefix.length)] = unwrapValue(row.data);
126016
+ }
126017
+ return result;
126018
+ }
126019
+ async function replacePrefixed(door, collection, prefix, values, wrap3) {
126020
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(prefix);
126021
+ if (range !== null) await door.deleteWhere({
126022
+ collection,
126023
+ filter: { whereBetween: { id: [range.lo, range.hi] } }
126024
+ });
126025
+ for (const [key, value] of Object.entries(values)) {
126026
+ if (value === void 0) continue;
126027
+ await door.set({
126028
+ collection,
126029
+ key: `${prefix}${key}`,
126030
+ value: wrap3(key, value)
126031
+ });
126032
+ }
126033
+ }
126034
+ function createDoorSettingsView(addonId, door, sections) {
126035
+ const addonPrefix = `${addonId}.`;
126036
+ return {
126037
+ async readAddonStore() {
126038
+ return loadPrefixed(door, "addon-settings", addonPrefix);
126039
+ },
126040
+ async writeAddonStore(patch) {
126041
+ await replacePrefixed(door, "addon-settings", addonPrefix, {
126042
+ ...await loadPrefixed(door, "addon-settings", addonPrefix),
126043
+ ...patch
126044
+ }, (key, value) => ({
126045
+ addonId,
126046
+ key,
126047
+ value
126048
+ }));
126049
+ },
126050
+ async readDeviceStore(deviceId) {
126051
+ return loadPrefixed(door, "addon-device-settings", `${addonId}:${String(deviceId)}.`);
126052
+ },
126053
+ async writeDeviceStore(deviceId, patch) {
126054
+ const scope = `${addonId}:${String(deviceId)}.`;
126055
+ await replacePrefixed(door, "addon-device-settings", scope, {
126056
+ ...await loadPrefixed(door, "addon-device-settings", scope),
126057
+ ...patch
126058
+ }, (key, value) => ({
126059
+ addonId,
126060
+ deviceId: String(deviceId),
126061
+ key,
126062
+ value
126063
+ }));
126064
+ },
126065
+ async clearDeviceStore(deviceId) {
126066
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(`${addonId}:${String(deviceId)}.`);
126067
+ if (range === null) return;
126068
+ await door.deleteWhere({
126069
+ collection: "addon-device-settings",
126070
+ filter: { whereBetween: { id: [range.lo, range.hi] } }
126071
+ });
126072
+ },
126073
+ async readDeviceRuntimeState(deviceId) {
126074
+ return asBlob(await door.get({
126075
+ collection: "device-runtime-state",
126076
+ key: String(deviceId)
126077
+ }));
126078
+ },
126079
+ async writeDeviceRuntimeState(deviceId, data) {
126080
+ await door.set({
126081
+ collection: "device-runtime-state",
126082
+ key: String(deviceId),
126083
+ value: data
126084
+ });
126085
+ },
126086
+ async clearDeviceRuntimeState(deviceId) {
126087
+ await door.delete({
126088
+ collection: "device-runtime-state",
126089
+ key: String(deviceId)
126090
+ });
126091
+ },
126092
+ async getSection(section) {
126093
+ return sections.getSection(section);
126094
+ },
126095
+ async setSection(section, patch) {
126096
+ await sections.setSection(section, patch);
126097
+ }
126098
+ };
126099
+ }
124984
126100
  var __create = Object.create;
124985
126101
  var __defProp = Object.defineProperty;
124986
126102
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -127460,6 +128576,7 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
127460
128576
  configPath;
127461
128577
  bootstrapConfig;
127462
128578
  settingsStore = null;
128579
+ settingsDoor = null;
127463
128580
  runtimeState;
127464
128581
  runtimeStatePath;
127465
128582
  constructor(configPath) {
@@ -127480,6 +128597,14 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
127480
128597
  setSettingsStore(store) {
127481
128598
  this.settingsStore = store;
127482
128599
  }
128600
+ /**
128601
+ * Wire the async `settings-store` door. Used when the engine is isolated
128602
+ * (no sync `ISettingsStore` handle on hub-main). {@link createSettingsView}
128603
+ * prefers the sync store when both are present.
128604
+ */
128605
+ setSettingsDoor(door) {
128606
+ this.settingsDoor = door;
128607
+ }
127483
128608
  get(configPath) {
127484
128609
  return this.resolveConfigValue(configPath);
127485
128610
  }
@@ -127500,8 +128625,21 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
127500
128625
  * Throws if the settings store is not yet wired.
127501
128626
  */
127502
128627
  set(key, value) {
127503
- if (this.settingsStore === null) throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
127504
- this.settingsStore.setSystem(key, value);
128628
+ if (this.settingsStore !== null) {
128629
+ this.settingsStore.setSystem(key, value);
128630
+ return;
128631
+ }
128632
+ if (this.settingsDoor !== null) {
128633
+ this.settingsDoor.set({
128634
+ collection: "system-settings",
128635
+ key,
128636
+ value
128637
+ }).catch((err) => {
128638
+ console.error("[ConfigManager] isolated settings-store write failed", err);
128639
+ });
128640
+ return;
128641
+ }
128642
+ throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
127505
128643
  }
127506
128644
  /**
127507
128645
  * Bulk-read all keys that belong to a logical section.
@@ -127622,6 +128760,19 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
127622
128760
  this.settingsStore.clearDeviceRuntimeState(deviceId);
127623
128761
  }
127624
128762
  createSettingsView(addonId) {
128763
+ if (this.settingsStore === null && this.settingsDoor !== null) {
128764
+ const door = this.settingsDoor;
128765
+ return createDoorSettingsView(addonId, door, {
128766
+ getSection: (section) => this.getSection(section),
128767
+ setSection: async (section, patch) => {
128768
+ for (const [key, value] of Object.entries(patch)) await door.set({
128769
+ collection: "system-settings",
128770
+ key: `${section}.${key}`,
128771
+ value
128772
+ });
128773
+ }
128774
+ });
128775
+ }
127625
128776
  const cm = this;
127626
128777
  return {
127627
128778
  async readAddonStore() {
@@ -199251,8 +200402,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199251
200402
  exports.AlertCenterAddon = require_builtins_alerts_alerts_addon.AlertCenterAddon;
199252
200403
  exports.ApiKeyManager = require_builtins_local_auth_local_auth_addon.ApiKeyManager;
199253
200404
  exports.AuthManager = require_builtins_local_auth_local_auth_addon.AuthManager;
199254
- exports.CA_COMMON_NAME = CA_COMMON_NAME;
199255
- exports.CA_VALIDITY_DAYS = CA_VALIDITY_DAYS;
200405
+ exports.CA_COMMON_NAME = require_lan_http_bind.CA_COMMON_NAME;
200406
+ exports.CA_VALIDITY_DAYS = require_lan_http_bind.CA_VALIDITY_DAYS;
199256
200407
  exports.CLUSTER_SECRET_MISMATCH_TYPE = CLUSTER_SECRET_MISMATCH_TYPE;
199257
200408
  exports.CLUSTER_SECRET_REJECTED_EXIT_CODE = CLUSTER_SECRET_REJECTED_EXIT_CODE;
199258
200409
  exports.CORE_CAP_SERVICE_NAME = CORE_CAP_SERVICE_NAME;
@@ -199269,6 +200420,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199269
200420
  exports.CoreBlocksAddon = require_builtins_core_blocks_core_blocks_addon.CoreBlocksAddon;
199270
200421
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
199271
200422
  exports.DEFAULT_DATA_PATH = DEFAULT_DATA_PATH;
200423
+ exports.DEFAULT_LAN_HTTP_PORT = require_lan_http_bind.DEFAULT_LAN_HTTP_PORT;
199272
200424
  exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_dist10.DEVICE_SETTINGS_CONTRIBUTION_METHODS;
199273
200425
  exports.DEVICE_STATUS_METHOD = require_dist10.DEVICE_STATUS_METHOD;
199274
200426
  exports.DataPlaneRegistry = DataPlaneRegistry;
@@ -199299,7 +200451,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199299
200451
  exports.INFRA_CAPABILITIES = INFRA_CAPABILITIES;
199300
200452
  exports.IntegrationRegistry = IntegrationRegistry;
199301
200453
  exports.JobJournal = JobJournal;
199302
- exports.LEAF_RENEWAL_WINDOW_DAYS = LEAF_RENEWAL_WINDOW_DAYS;
200454
+ exports.LEAF_RENEWAL_WINDOW_DAYS = require_lan_http_bind.LEAF_RENEWAL_WINDOW_DAYS;
199303
200455
  exports.LifecycleJobEngine = LifecycleJobEngine;
199304
200456
  exports.LifecycleStateMachine = LifecycleStateMachine;
199305
200457
  exports.LivenessMonitorAddon = require_builtins_liveness_monitor_liveness_monitor_addon.LivenessMonitorAddon;
@@ -199310,7 +200462,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199310
200462
  exports.LogRingBuffer = LogRingBuffer;
199311
200463
  exports.LokiDestination = require_builtins_loki_logging_index.LokiDestination$1;
199312
200464
  exports.LokiLoggingAddon = require_builtins_loki_logging_index.LokiLoggingAddon$1;
199313
- exports.MAX_LEAF_VALIDITY_DAYS = MAX_LEAF_VALIDITY_DAYS;
200465
+ exports.MAX_LEAF_VALIDITY_DAYS = require_lan_http_bind.MAX_LEAF_VALIDITY_DAYS;
199314
200466
  exports.METHOD_ACCESS_MAP = require_dist10.METHOD_ACCESS_MAP;
199315
200467
  exports.ModelDownloadService = require_file_data_plane.ModelDownloadService;
199316
200468
  exports.NATIVE_PROVIDER_SERVICE_INFIX = require_manifest_python_deps.NATIVE_PROVIDER_SERVICE_INFIX;
@@ -199336,7 +200488,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199336
200488
  exports.ReadinessTimeoutError = require_dist10.ReadinessTimeoutError;
199337
200489
  exports.ReplEngine = ReplEngine;
199338
200490
  exports.RingBuffer = RingBuffer;
199339
- exports.SERVER_AUTH_OID = SERVER_AUTH_OID;
200491
+ exports.SERVER_AUTH_OID = require_lan_http_bind.SERVER_AUTH_OID;
199340
200492
  exports.ScopedLogger = ScopedLogger;
199341
200493
  exports.ScopedTokenManager = require_builtins_local_auth_local_auth_addon.ScopedTokenManager;
199342
200494
  exports.SocketChannel = require_manifest_python_deps.SocketChannel;
@@ -199360,6 +200512,9 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199360
200512
  exports.__resetCapUsageRegistryForTests = require_manifest_python_deps.__resetCapUsageRegistryForTests;
199361
200513
  exports.adaptBrokerToCluster = require_manifest_python_deps.adaptBrokerToCluster;
199362
200514
  exports.addonSettingsCapability = require_dist10.addonSettingsCapability;
200515
+ exports.allFamiliesListenHost = require_lan_http_bind.allFamiliesListenHost;
200516
+ exports.applyLanHttp = require_lan_http_bind.applyLanHttp;
200517
+ exports.bindPendingLanHttp = require_lan_http_bind.bindPendingLanHttp;
199363
200518
  exports.bootstrapSchema = bootstrapSchema;
199364
200519
  exports.brokerCallForCap = require_manifest_python_deps.brokerCallForCap;
199365
200520
  exports.brokerTransportLink = require_manifest_python_deps.brokerTransportLink;
@@ -199386,9 +200541,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199386
200541
  exports.classifyAddonDir = classifyAddonDir;
199387
200542
  exports.classifyCapRoute = require_manifest_python_deps.classifyCapRoute;
199388
200543
  exports.clearPendingRestart = clearPendingRestart;
200544
+ exports.closeLanHttp = require_lan_http_bind.closeLanHttp;
199389
200545
  exports.clusterEventTopic = require_manifest_python_deps.clusterEventTopic;
199390
200546
  exports.clusterSecretMatches = clusterSecretMatches;
199391
- exports.collectCertIdentity = collectCertIdentity;
200547
+ exports.collectCertIdentity = require_lan_http_bind.collectCertIdentity;
199392
200548
  exports.collectModelFiles = require_file_data_plane.collectModelFiles;
199393
200549
  exports.contentTypeFor = require_file_data_plane.contentTypeFor;
199394
200550
  exports.copyDirRecursive = copyDirRecursive;
@@ -199400,6 +200556,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199400
200556
  exports.createBroker = createBroker2;
199401
200557
  exports.createBrokerDeviceManagerApi = require_manifest_python_deps.createBrokerDeviceManagerApi;
199402
200558
  exports.createCoreCapService = createCoreCapService;
200559
+ exports.createDoorSettingsView = createDoorSettingsView;
199403
200560
  exports.createFileDataPlaneHandler = require_file_data_plane.createFileDataPlaneHandler;
199404
200561
  exports.createHubCapForwardService = require_manifest_python_deps.createHubCapForwardService;
199405
200562
  exports.createHubService = createHubService;
@@ -199454,8 +200611,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199454
200611
  return _camstack_types_node.ensurePython;
199455
200612
  }
199456
200613
  });
199457
- exports.ensureTlsCert = ensureTlsCert;
199458
- exports.evaluateExistingCert = evaluateExistingCert;
200614
+ exports.ensureTlsCert = require_lan_http_bind.ensureTlsCert;
200615
+ exports.evaluateExistingCert = require_lan_http_bind.evaluateExistingCert;
199459
200616
  exports.expandCapMethods = require_dist10.expandCapMethods;
199460
200617
  exports.fetchJson = require_file_data_plane.fetchJson;
199461
200618
  Object.defineProperty(exports, "findInPath", {
@@ -199519,21 +200676,30 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199519
200676
  exports.isInfraCapability = isInfraCapability;
199520
200677
  exports.isModelDownloaded = require_file_data_plane.isModelDownloaded;
199521
200678
  exports.isSourceNewer = isSourceNewer;
199522
- exports.loadTlsCert = loadTlsCert;
200679
+ exports.isolatedBuiltinPhase = isolatedBuiltinPhase;
200680
+ exports.loadTlsCert = require_lan_http_bind.loadTlsCert;
199523
200681
  exports.localEndpointPath = require_manifest_python_deps.localEndpointPath;
199524
200682
  exports.localProviderLink = require_manifest_python_deps.localProviderLink;
199525
200683
  exports.mountNativeCapService = require_manifest_python_deps.mountNativeCapService;
199526
200684
  exports.parseCapAction = require_manifest_python_deps.parseCapAction;
199527
200685
  exports.parseRangeHeader = require_file_data_plane.parseRangeHeader;
199528
200686
  exports.parseTokenizedUrl = require_file_data_plane.parseTokenizedUrl;
200687
+ exports.partitionIsolatedBuiltinIds = partitionIsolatedBuiltinIds;
199529
200688
  exports.proxyToUpstream = proxyToUpstream;
199530
200689
  exports.quarantineAddonResidue = quarantineAddonResidue;
200690
+ exports.readExtraSans = require_lan_http_bind.readExtraSans;
200691
+ exports.readLanHttpState = require_lan_http_bind.readLanHttpState;
199531
200692
  exports.readPendingRestart = readPendingRestart;
200693
+ exports.readTlsAccessStatus = require_lan_http_bind.readTlsAccessStatus;
200694
+ exports.readTlsMode = require_lan_http_bind.readTlsMode;
199532
200695
  exports.readinessKey = require_dist10.readinessKey;
199533
200696
  exports.registerEventBusService = require_manifest_python_deps.registerEventBusService;
200697
+ exports.registerLanHttpHandler = require_lan_http_bind.registerLanHttpHandler;
200698
+ exports.reissueTlsLeaf = require_lan_http_bind.reissueTlsLeaf;
199534
200699
  exports.resolveFilePath = require_file_data_plane.resolveFilePath;
199535
200700
  exports.resolveHwAccel = require_manifest_python_deps.resolveHwAccel;
199536
200701
  exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation;
200702
+ exports.runHubAddonBoot = runHubAddonBoot;
199537
200703
  exports.runNpm = require_manifest_python_deps.runNpm;
199538
200704
  exports.scheduleSelfRestart = scheduleSelfRestart;
199539
200705
  exports.scopeKey = require_dist10.scopeKey;
@@ -199551,7 +200717,11 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
199551
200717
  exports.subscribePassthrough = require_manifest_python_deps.subscribePassthrough;
199552
200718
  exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
199553
200719
  exports.validateProviderRegistrations = require_manifest_python_deps.validateProviderRegistrations;
200720
+ exports.validateUploadedTls = require_lan_http_bind.validateUploadedTls;
200721
+ exports.waitUntilReady = waitUntilReady;
200722
+ exports.writeExtraSans = require_lan_http_bind.writeExtraSans;
199554
200723
  exports.writePendingRestart = writePendingRestart;
200724
+ exports.writeTlsMode = require_lan_http_bind.writeTlsMode;
199555
200725
  }
199556
200726
  });
199557
200727
 
@@ -238240,7 +239410,7 @@ var require_dist9 = __commonJS({
238240
239410
  "use strict";
238241
239411
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
238242
239412
  var require_event_category = require_event_category_EY0GNjV9();
238243
- var require_sleep = require_sleep_C2XhJhkd();
239413
+ var require_sleep = require_sleep_CizGYrCD();
238244
239414
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
238245
239415
  var require_enums2 = require_enums();
238246
239416
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -239766,6 +240936,16 @@ var require_dist9 = __commonJS({
239766
240936
  description: zod.z.string().optional(),
239767
240937
  icon: zod.z.string().optional()
239768
240938
  });
240939
+ var CLASS_MAP_MACRO_TARGETS = [
240940
+ "person",
240941
+ "vehicle",
240942
+ "animal",
240943
+ "package"
240944
+ ];
240945
+ var ClassMapDefinitionSchema = zod.z.object({
240946
+ mapping: zod.z.record(zod.z.string(), zod.z.enum(CLASS_MAP_MACRO_TARGETS)),
240947
+ preserveOriginal: zod.z.boolean()
240948
+ });
239769
240949
  var FORMAT_KEYS = [
239770
240950
  "onnx",
239771
240951
  "coreml",
@@ -239939,6 +241119,20 @@ var require_dist9 = __commonJS({
239939
241119
  */
239940
241120
  resolution: zod.z.number().int().positive().optional()
239941
241121
  });
241122
+ var MODEL_PROVIDER_IDS = [
241123
+ "camstack",
241124
+ "frigate",
241125
+ "scrypted",
241126
+ "custom"
241127
+ ];
241128
+ var ModelProviderIdSchema = zod.z.enum(MODEL_PROVIDER_IDS);
241129
+ function inferModelProvider(entry) {
241130
+ if (entry.provider !== void 0) return entry.provider;
241131
+ const haystack = `${entry.id} ${entry.description ?? ""}`;
241132
+ if (/scrypted/i.test(haystack)) return "scrypted";
241133
+ if (/frigate/i.test(haystack)) return "frigate";
241134
+ return "custom";
241135
+ }
239942
241136
  var ModelCatalogEntrySchema = zod.z.object({
239943
241137
  id: zod.z.string(),
239944
241138
  name: zod.z.string(),
@@ -240034,7 +241228,19 @@ var require_dist9 = __commonJS({
240034
241228
  * `id` stays the source of truth for resolution/download/persistence; grouping
240035
241229
  * is a presentation overlay resolved back to an `id`.
240036
241230
  */
240037
- group: ModelVariantGroupSchema.optional()
241231
+ group: ModelVariantGroupSchema.optional(),
241232
+ /**
241233
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
241234
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
241235
+ * persisted before this field existed (`inferModelProvider` fills those).
241236
+ */
241237
+ provider: ModelProviderIdSchema.optional(),
241238
+ /**
241239
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
241240
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
241241
+ * labels already ARE the CamStack macros (Scrypted identity map).
241242
+ */
241243
+ classMap: ClassMapDefinitionSchema.optional()
240038
241244
  });
240039
241245
  var ConvertTargetSchema = zod.z.discriminatedUnion("format", [zod.z.object({
240040
241246
  format: zod.z.literal("openvino"),
@@ -240063,7 +241269,8 @@ var require_dist9 = __commonJS({
240063
241269
  "ocr",
240064
241270
  "segmentation"
240065
241271
  ]),
240066
- faceAlignment: zod.z.boolean().optional()
241272
+ faceAlignment: zod.z.boolean().optional(),
241273
+ classMap: ClassMapDefinitionSchema.optional()
240067
241274
  });
240068
241275
  var ConvertArtifactSchema = zod.z.object({
240069
241276
  format: zod.z.enum(MODEL_FORMATS),
@@ -247891,14 +249098,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
247891
249098
  });
247892
249099
  var NC_AUDIO_DBFS_FLOOR = -96;
247893
249100
  var NcAudioConditionSchema = zod.z.object({
247894
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
249101
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
247895
249102
  labels: zod.z.array(zod.z.string().min(1)).min(1).optional(),
247896
249103
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
247897
249104
  dbThreshold: zod.z.number().min(-96).max(0).optional(),
247898
249105
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
247899
249106
  hitPercent: zod.z.number().int().min(1).max(100).default(60),
247900
249107
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
247901
- samplingSeconds: zod.z.number().int().min(1).max(300).default(10)
249108
+ samplingSeconds: zod.z.number().int().min(1).max(300).default(10),
249109
+ /**
249110
+ * LABEL MODE: how many labelled frames must land inside
249111
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
249112
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
249113
+ */
249114
+ confirmHits: zod.z.number().int().min(1).max(20).optional(),
249115
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
249116
+ confirmWindowSec: zod.z.number().int().min(1).max(60).optional()
247902
249117
  });
247903
249118
  var NcCrossingSchema = zod.z.enum([
247904
249119
  "enter",
@@ -250158,6 +251373,46 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250158
251373
  /** Cursor for the next page, or null when this page is the last. */
250159
251374
  nextCursor: zod.z.string().nullable()
250160
251375
  });
251376
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
251377
+ var LIST_GROUPS_MAX_LIMIT = 100;
251378
+ var AnalyticsGroupRecordSchema = zod.z.object({
251379
+ id: zod.z.string(),
251380
+ deviceId: zod.z.number().int(),
251381
+ openedAt: zod.z.number().int(),
251382
+ closedAt: zod.z.number().int(),
251383
+ timestamp: zod.z.number().int(),
251384
+ memberCount: zod.z.number().int(),
251385
+ memberTrackIds: zod.z.array(zod.z.string()).readonly(),
251386
+ className: zod.z.string(),
251387
+ classes: zod.z.array(zod.z.string()).readonly(),
251388
+ /** Relative event-media path, or null when the group has no picture yet. */
251389
+ mediaUrl: zod.z.string().nullable(),
251390
+ singleton: zod.z.boolean()
251391
+ });
251392
+ var AnalyticsGroupMemberSchema = zod.z.object({
251393
+ trackId: zod.z.string(),
251394
+ deviceId: zod.z.number().int(),
251395
+ className: zod.z.string(),
251396
+ firstSeen: zod.z.number().int(),
251397
+ lastSeen: zod.z.number().int(),
251398
+ mediaUrl: zod.z.string().nullable()
251399
+ });
251400
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
251401
+ var ListGroupsQueryInput = zod.z.object({
251402
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
251403
+ deviceIds: zod.z.array(zod.z.number()),
251404
+ /** Window lower bound on `closedAt` (inclusive). */
251405
+ since: zod.z.number().optional(),
251406
+ /** Window upper bound on `openedAt` (inclusive). */
251407
+ until: zod.z.number().optional(),
251408
+ limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
251409
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
251410
+ cursor: zod.z.string().optional()
251411
+ });
251412
+ var ListGroupsPageSchema = zod.z.object({
251413
+ groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
251414
+ nextCursor: zod.z.string().nullable()
251415
+ });
250161
251416
  var KeyEventQueryInput = zod.z.object({
250162
251417
  deviceId: zod.z.number(),
250163
251418
  /** Window lower bound (track firstSeen ≥ since). */
@@ -250233,7 +251488,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250233
251488
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
250234
251489
  plates: zod.z.number().int(),
250235
251490
  /** Per-track CLIP search vectors removed (best-effort). */
250236
- embeddings: zod.z.number().int()
251491
+ embeddings: zod.z.number().int(),
251492
+ /** Group membership + group rows removed with their last member (best-effort). */
251493
+ groups: zod.z.number().int()
250237
251494
  });
250238
251495
  var DiskReconcileCountsSchema = zod.z.object({
250239
251496
  mediaDropped: zod.z.number().int(),
@@ -250375,6 +251632,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250375
251632
  * are not included (same contract as `listTracks`).
250376
251633
  */
250377
251634
  listRecentTracks: require_sleep.method(RecentTracksQueryInput, RecentTracksPageSchema),
251635
+ /**
251636
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
251637
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
251638
+ * one session; `getGroup` is the detail with members.
251639
+ */
251640
+ listGroups: require_sleep.method(ListGroupsQueryInput, ListGroupsPageSchema),
251641
+ getGroup: require_sleep.method(zod.z.object({
251642
+ deviceId: zod.z.number(),
251643
+ groupId: zod.z.string().min(1)
251644
+ }), AnalyticsGroupDetailSchema.nullable()),
250378
251645
  clearTracks: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
250379
251646
  kind: "mutation",
250380
251647
  auth: "admin"
@@ -250963,6 +252230,33 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250963
252230
  h: zod.z.number()
250964
252231
  })
250965
252232
  });
252233
+ zod.z.object({
252234
+ crop: zod.z.object({
252235
+ left: zod.z.number(),
252236
+ top: zod.z.number(),
252237
+ width: zod.z.number().positive(),
252238
+ height: zod.z.number().positive()
252239
+ }).optional(),
252240
+ content: zod.z.object({
252241
+ width: zod.z.number().int().positive(),
252242
+ height: zod.z.number().int().positive()
252243
+ }),
252244
+ fit: zod.z.enum(["stretch", "contain"]),
252245
+ format: zod.z.enum([
252246
+ "rgb",
252247
+ "gray",
252248
+ "jpeg"
252249
+ ])
252250
+ });
252251
+ var FrameRefSchema = zod.z.object({
252252
+ registryId: zod.z.string().min(1),
252253
+ id: zod.z.string().min(1),
252254
+ width: zod.z.number().int().positive(),
252255
+ height: zod.z.number().int().positive(),
252256
+ format: zod.z.enum(["rgb", "gray"]),
252257
+ timestamp: zod.z.number(),
252258
+ capturedAt: zod.z.number().optional()
252259
+ });
250966
252260
  var ModelFormatSchema$1 = zod.z.enum([
250967
252261
  "onnx",
250968
252262
  "coreml",
@@ -251029,7 +252323,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251029
252323
  sizeMB: zod.z.number()
251030
252324
  })),
251031
252325
  group: ModelVariantGroupSchema.optional(),
251032
- legacy: zod.z.boolean().optional()
252326
+ legacy: zod.z.boolean().optional(),
252327
+ provider: ModelProviderIdSchema.optional()
251033
252328
  });
251034
252329
  var ConfigFieldBridge = zod.z.custom();
251035
252330
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -251262,7 +252557,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251262
252557
  * legacy call shape used by existing benchmark code; once all
251263
252558
  * callers pass it explicitly we make it required.
251264
252559
  *
251265
- * Exactly one of `frame`, `frameHandle`, `imageBase64`,
252560
+ * Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
251266
252561
  * `referenceImage` must be provided:
251267
252562
  * - `frame`: runtime dispatch path (runner → decoded broker frame).
251268
252563
  * Carries the raw buffer, dimensions, and format; the executor
@@ -251284,6 +252579,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251284
252579
  steps: zod.z.array(PipelineStepInputSchema).min(1),
251285
252580
  frame: FrameInputSchema.optional(),
251286
252581
  /**
252582
+ * Process-local lazy frame. Valid only when caller and provider resolve
252583
+ * in the same execution-group process; split/cross-node callers use
252584
+ * `frame`/`image` inline compatibility instead.
252585
+ */
252586
+ frameRef: FrameRefSchema.optional(),
252587
+ /**
251287
252588
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
251288
252589
  * the decoded pixels live in. One more member of the one-of
251289
252590
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -251586,7 +252887,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251586
252887
  * Which source served this crop, so a quality-sensitive consumer (the native
251587
252888
  * `keyFrame`) can reject a degraded fallback:
251588
252889
  * - `native` — cut from the decode worker's retained NATIVE surface (the
251589
- * quality path).
252890
+ * quality path). A subject-tile serve is also native-resolution and stays
252891
+ * `native` here: the public enum cannot name `tile` without a breaking cap
252892
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
252893
+ * internal crop result (`nativeHits` vs `tileHits`).
251590
252894
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
251591
252895
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
251592
252896
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -252089,12 +253393,41 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
252089
253393
  cpuCores: zod.z.number().optional()
252090
253394
  })
252091
253395
  });
253396
+ var FrameLazyCountersSchema = zod.z.object({
253397
+ framesDecoded: zod.z.number(),
253398
+ framesAdmitted: zod.z.number(),
253399
+ framesDroppedPixelFree: zod.z.number(),
253400
+ viewsMaterialized: zod.z.number(),
253401
+ viewsSkipped: zod.z.number(),
253402
+ workerToRunnerBytes: zod.z.number(),
253403
+ runnerToPoolRawBytes: zod.z.number(),
253404
+ runnerToPoolJpegBytes: zod.z.number(),
253405
+ onDemandFullFrameRequests: zod.z.number(),
253406
+ onDemandCropRequests: zod.z.number(),
253407
+ nativeHits: zod.z.number(),
253408
+ nativeMisses: zod.z.number(),
253409
+ tileHits: zod.z.number(),
253410
+ tileMisses: zod.z.number(),
253411
+ fallbackHits: zod.z.number(),
253412
+ fallbackMisses: zod.z.number(),
253413
+ retainedWritesAvoided: zod.z.number(),
253414
+ residentRefs: zod.z.number(),
253415
+ residentBytes: zod.z.number(),
253416
+ releases: zod.z.number(),
253417
+ evictions: zod.z.number(),
253418
+ staleMisses: zod.z.number()
253419
+ });
253420
+ var FrameLazyMetricsSchema = zod.z.object({
253421
+ node: FrameLazyCountersSchema,
253422
+ cameras: zod.z.array(FrameLazyCountersSchema.extend({ deviceId: zod.z.number() }))
253423
+ });
252092
253424
  var RunnerLocalMetricsSchema = zod.z.object({
252093
253425
  nodeId: zod.z.string(),
252094
253426
  activeCameras: zod.z.number(),
252095
253427
  throttledCameras: zod.z.number(),
252096
253428
  avgInferenceTimeMs: zod.z.number(),
252097
- queueDepth: zod.z.number()
253429
+ queueDepth: zod.z.number(),
253430
+ frameLazy: FrameLazyMetricsSchema.optional()
252098
253431
  });
252099
253432
  var pipelineRunnerCapability = {
252100
253433
  name: "pipeline-runner",
@@ -253900,6 +255233,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253900
255233
  endDownload: require_sleep.method(EndDownloadInputSchema, zod.z.void(), { kind: "mutation" })
253901
255234
  }
253902
255235
  };
255236
+ var ProfileSettingsSchemaBridge = zod.z.unknown().nullable();
255237
+ var ProfileSettingsBagSchema = zod.z.record(zod.z.string(), zod.z.unknown());
253903
255238
  var TerminalSessionInfoSchema = zod.z.object({
253904
255239
  /** Opaque session id minted by the provider on `openSession`. */
253905
255240
  sessionId: zod.z.string(),
@@ -253915,7 +255250,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253915
255250
  var TerminalProfileInfoSchema = zod.z.object({
253916
255251
  profileId: zod.z.string(),
253917
255252
  label: zod.z.string(),
253918
- description: zod.z.string().optional()
255253
+ description: zod.z.string().optional(),
255254
+ /** Spawn defaults the instance form copies on create. */
255255
+ executable: zod.z.string().optional(),
255256
+ args: zod.z.array(zod.z.string()).readonly().optional(),
255257
+ cwd: zod.z.string().optional(),
255258
+ environment: zod.z.array(zod.z.string()).readonly().optional(),
255259
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
255260
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
253919
255261
  });
253920
255262
  var TerminalInstanceInfoSchema = zod.z.object({
253921
255263
  instanceId: zod.z.string(),
@@ -253924,7 +255266,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253924
255266
  profileId: zod.z.string(),
253925
255267
  profileLabel: zod.z.string(),
253926
255268
  name: zod.z.string(),
253927
- enabled: zod.z.boolean()
255269
+ enabled: zod.z.boolean(),
255270
+ executable: zod.z.string(),
255271
+ args: zod.z.array(zod.z.string()).readonly(),
255272
+ cwd: zod.z.string(),
255273
+ environment: zod.z.array(zod.z.string()).readonly(),
255274
+ profileSettings: ProfileSettingsBagSchema
253928
255275
  });
253929
255276
  var TerminalLegacyCameraSchema = zod.z.object({
253930
255277
  stableId: zod.z.string(),
@@ -253963,7 +255310,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253963
255310
  createInstance: require_sleep.method(zod.z.object({
253964
255311
  targetNodeId: zod.z.string().min(1),
253965
255312
  profileId: zod.z.string().min(1),
253966
- name: zod.z.string().trim().min(1).max(160).optional()
255313
+ name: zod.z.string().trim().min(1).max(160).optional(),
255314
+ executable: zod.z.string().max(1024).optional(),
255315
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
255316
+ cwd: zod.z.string().max(1024).optional(),
255317
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
255318
+ profileSettings: ProfileSettingsBagSchema.optional()
255319
+ }), TerminalInstanceInfoSchema, {
255320
+ kind: "mutation",
255321
+ auth: "admin"
255322
+ }),
255323
+ updateInstance: require_sleep.method(zod.z.object({
255324
+ instanceId: zod.z.string().min(1),
255325
+ name: zod.z.string().trim().min(1).max(160).optional(),
255326
+ executable: zod.z.string().max(1024).optional(),
255327
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
255328
+ cwd: zod.z.string().max(1024).optional(),
255329
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional(),
255330
+ profileSettings: ProfileSettingsBagSchema.optional()
253967
255331
  }), TerminalInstanceInfoSchema, {
253968
255332
  kind: "mutation",
253969
255333
  auth: "admin"
@@ -253998,7 +255362,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253998
255362
  openSession: require_sleep.method(zod.z.object({
253999
255363
  profileId: zod.z.string(),
254000
255364
  cols: zod.z.number().int().positive(),
254001
- rows: zod.z.number().int().positive()
255365
+ rows: zod.z.number().int().positive(),
255366
+ executable: zod.z.string().max(1024).optional(),
255367
+ args: zod.z.array(zod.z.string().max(2048)).max(64).optional(),
255368
+ cwd: zod.z.string().max(1024).optional(),
255369
+ environment: zod.z.array(zod.z.string().max(4096)).max(64).optional()
254002
255370
  }), TerminalSessionInfoSchema, {
254003
255371
  kind: "mutation",
254004
255372
  auth: "admin"
@@ -257724,6 +259092,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257724
259092
  /** What the ranking currently resolves to (null when nothing is reachable). */
257725
259093
  resolved: zod.z.string().nullable()
257726
259094
  });
259095
+ var ViewerEndpointsSchema = zod.z.object({
259096
+ /** The operator's explicit race set, or empty for AUTO. */
259097
+ baseUrls: zod.z.array(zod.z.string()).readonly(),
259098
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
259099
+ resolved: zod.z.array(zod.z.string()).readonly()
259100
+ });
257727
259101
  var AllowedAddressesSchema = zod.z.object({
257728
259102
  /**
257729
259103
  * Allowlist of interface addresses operators have explicitly opted
@@ -257733,6 +259107,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257733
259107
  */
257734
259108
  addresses: zod.z.array(zod.z.string()).readonly()
257735
259109
  });
259110
+ var TlsStatusSchema = zod.z.object({
259111
+ mode: zod.z.enum([
259112
+ "generated",
259113
+ "uploaded",
259114
+ "disabled"
259115
+ ]),
259116
+ leafFingerprintSha256: zod.z.string().nullable(),
259117
+ caFingerprintSha256: zod.z.string().nullable(),
259118
+ validTo: zod.z.string().nullable(),
259119
+ sans: zod.z.array(zod.z.string()),
259120
+ caCertPem: zod.z.string().nullable(),
259121
+ reissueError: zod.z.string().nullable(),
259122
+ restartRequired: zod.z.boolean()
259123
+ });
257736
259124
  var localNetworkCapability = {
257737
259125
  name: "local-network",
257738
259126
  scope: "system",
@@ -257752,13 +259140,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257752
259140
  */
257753
259141
  getPreferred: require_sleep.method(zod.z.void(), PreferredSchema),
257754
259142
  /**
257755
- * Ordered candidate base URLs the SDK should try on connect.
257756
- * Includes LAN IPs (one per non-internal interface), the public
257757
- * tunnel hostname (when active), and loopback as a last-resort
257758
- * fallback. Filterable by `includeLoopback` / `ipv4Only`.
257759
- * Honours `getAllowedAddresses()` when set addresses outside
257760
- * the allowlist are dropped (the public tunnel + loopback are
257761
- * always included as escape hatches).
259143
+ * Ordered candidate base URLs (the palette the Network tab shows).
259144
+ * Includes LAN IPv4, stable LAN IPv6, the public tunnel, and mesh when
259145
+ * joined. Loopback is off by default. The SDK races the subset from
259146
+ * `getViewerEndpoints`, not this full list — IPv6 stays here because
259147
+ * WebRTC ICE gathers dual-stack regardless of the HTTP race. Honours
259148
+ * `getAllowedAddresses()` when set addresses outside the allowlist
259149
+ * are dropped (the public tunnel is still included as an escape hatch).
257762
259150
  *
257763
259151
  * **The port is the hub's, not the caller's** (D62 — a function's fact
257764
259152
  * belongs to whoever already owns it). This method used to take a `port`
@@ -257789,10 +259177,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257789
259177
  */
257790
259178
  port: zod.z.number().int().min(1).max(65535).optional(),
257791
259179
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
257792
- * candidate. Default `true`. */
259180
+ * candidate. Default `false` — loopback is not a client route. */
257793
259181
  includeLoopback: zod.z.boolean().optional(),
257794
- /** Skip IPv6 entries. Some legacy clients can't parse them.
257795
- * Default `false`. */
259182
+ /** Skip IPv6 entries. Default `false` the palette includes stable
259183
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
259184
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
257796
259185
  ipv4Only: zod.z.boolean().optional(),
257797
259186
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
257798
259187
  * Pass `'https'` when the caller is itself loaded over HTTPS
@@ -257821,6 +259210,19 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257821
259210
  */
257822
259211
  setNotificationEndpoint: require_sleep.method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
257823
259212
  /**
259213
+ * The endpoints the SDK / viewer races for API access. Empty `baseUrls`
259214
+ * means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
259215
+ * never mesh, never loopback. `resolved` is that set (or the operator's
259216
+ * explicit subset) as it stands right now.
259217
+ */
259218
+ getViewerEndpoints: require_sleep.method(zod.z.void(), ViewerEndpointsSchema),
259219
+ /**
259220
+ * Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
259221
+ * verbatim (not indices) so a temporarily-down tunnel is not silently
259222
+ * dropped from the operator's choice.
259223
+ */
259224
+ setViewerEndpoints: require_sleep.method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
259225
+ /**
257824
259226
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
257825
259227
  * by the admin UI's address selector to seed its checkbox state.
257826
259228
  */
@@ -257838,7 +259240,34 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
257838
259240
  * when the operator wants to wipe their manual edits and start
257839
259241
  * over from the auto-detected best matches.
257840
259242
  */
257841
- resetAllowlistToBestMatch: require_sleep.method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" })
259243
+ resetAllowlistToBestMatch: require_sleep.method(zod.z.void(), AllowedAddressesSchema, { kind: "mutation" }),
259244
+ /**
259245
+ * Live TLS material for the Network → Local access certificate card.
259246
+ * LAN HTTP / hostname are addon settings (`globalSettingsSchema`), not
259247
+ * a second store — this query is status, not configuration.
259248
+ */
259249
+ getTlsStatus: require_sleep.method(zod.z.void(), TlsStatusSchema),
259250
+ /** Issue a new leaf under the existing local CA. Disabled in uploaded mode. */
259251
+ regenerateCertificate: require_sleep.method(zod.z.object({ reason: zod.z.string().optional() }), TlsStatusSchema, {
259252
+ kind: "mutation",
259253
+ auth: "admin"
259254
+ }),
259255
+ /** Replace the served material with operator-supplied PEMs. */
259256
+ uploadCertificate: require_sleep.method(zod.z.object({
259257
+ certPem: zod.z.string().min(1),
259258
+ keyPem: zod.z.string().min(1),
259259
+ caPem: zod.z.string().optional()
259260
+ }), TlsStatusSchema, {
259261
+ kind: "mutation",
259262
+ auth: "admin"
259263
+ }),
259264
+ /** The local CA PEM, or empty when there is none to download. */
259265
+ downloadCa: require_sleep.method(zod.z.void(), zod.z.object({ pem: zod.z.string() })),
259266
+ /** Drop uploaded material and return to the generated local CA. */
259267
+ revertToGeneratedCertificate: require_sleep.method(zod.z.void(), TlsStatusSchema, {
259268
+ kind: "mutation",
259269
+ auth: "admin"
259270
+ })
257842
259271
  },
257843
259272
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
257844
259273
  mount: { kind: "hub-only" }
@@ -259373,7 +260802,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
259373
260802
  plateBbox: BoundingBoxSchema.optional(),
259374
260803
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
259375
260804
  keyFrameMediaKey: zod.z.string().optional(),
259376
- base64: zod.z.string().optional()
260805
+ base64: zod.z.string().optional(),
260806
+ /**
260807
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
260808
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
260809
+ */
260810
+ cropUrl: zod.z.string().optional()
259377
260811
  });
259378
260812
  var MediaFileLiteSchema = zod.z.object({
259379
260813
  key: zod.z.string(),
@@ -268127,6 +269561,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268127
269561
  addonId: null,
268128
269562
  access: "create"
268129
269563
  },
269564
+ "localNetwork.downloadCa": {
269565
+ capName: "local-network",
269566
+ capScope: "system",
269567
+ addonId: null,
269568
+ access: "view"
269569
+ },
268130
269570
  "localNetwork.getAllowedAddresses": {
268131
269571
  capName: "local-network",
268132
269572
  capScope: "system",
@@ -268151,18 +269591,42 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268151
269591
  addonId: null,
268152
269592
  access: "view"
268153
269593
  },
269594
+ "localNetwork.getTlsStatus": {
269595
+ capName: "local-network",
269596
+ capScope: "system",
269597
+ addonId: null,
269598
+ access: "view"
269599
+ },
269600
+ "localNetwork.getViewerEndpoints": {
269601
+ capName: "local-network",
269602
+ capScope: "system",
269603
+ addonId: null,
269604
+ access: "view"
269605
+ },
268154
269606
  "localNetwork.list": {
268155
269607
  capName: "local-network",
268156
269608
  capScope: "system",
268157
269609
  addonId: null,
268158
269610
  access: "view"
268159
269611
  },
269612
+ "localNetwork.regenerateCertificate": {
269613
+ capName: "local-network",
269614
+ capScope: "system",
269615
+ addonId: null,
269616
+ access: "create"
269617
+ },
268160
269618
  "localNetwork.resetAllowlistToBestMatch": {
268161
269619
  capName: "local-network",
268162
269620
  capScope: "system",
268163
269621
  addonId: null,
268164
269622
  access: "delete"
268165
269623
  },
269624
+ "localNetwork.revertToGeneratedCertificate": {
269625
+ capName: "local-network",
269626
+ capScope: "system",
269627
+ addonId: null,
269628
+ access: "create"
269629
+ },
268166
269630
  "localNetwork.setAllowedAddresses": {
268167
269631
  capName: "local-network",
268168
269632
  capScope: "system",
@@ -268175,6 +269639,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268175
269639
  addonId: null,
268176
269640
  access: "create"
268177
269641
  },
269642
+ "localNetwork.setViewerEndpoints": {
269643
+ capName: "local-network",
269644
+ capScope: "system",
269645
+ addonId: null,
269646
+ access: "create"
269647
+ },
269648
+ "localNetwork.uploadCertificate": {
269649
+ capName: "local-network",
269650
+ capScope: "system",
269651
+ addonId: null,
269652
+ access: "create"
269653
+ },
268178
269654
  "lockControl.lock": {
268179
269655
  capName: "lock-control",
268180
269656
  capScope: "device",
@@ -268973,6 +270449,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268973
270449
  addonId: null,
268974
270450
  access: "view"
268975
270451
  },
270452
+ "pipelineAnalytics.getGroup": {
270453
+ capName: "pipeline-analytics",
270454
+ capScope: "device",
270455
+ addonId: null,
270456
+ access: "view"
270457
+ },
268976
270458
  "pipelineAnalytics.getKeyEvents": {
268977
270459
  capName: "pipeline-analytics",
268978
270460
  capScope: "device",
@@ -269057,6 +270539,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
269057
270539
  addonId: null,
269058
270540
  access: "view"
269059
270541
  },
270542
+ "pipelineAnalytics.listGroups": {
270543
+ capName: "pipeline-analytics",
270544
+ capScope: "device",
270545
+ addonId: null,
270546
+ access: "view"
270547
+ },
269060
270548
  "pipelineAnalytics.listOpsLog": {
269061
270549
  capName: "pipeline-analytics",
269062
270550
  capScope: "device",
@@ -271055,6 +272543,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
271055
272543
  addonId: null,
271056
272544
  access: "create"
271057
272545
  },
272546
+ "terminalSession.updateInstance": {
272547
+ capName: "terminal-session",
272548
+ capScope: "system",
272549
+ addonId: null,
272550
+ access: "create"
272551
+ },
271058
272552
  "terminalSession.writeInput": {
271059
272553
  capName: "terminal-session",
271060
272554
  capScope: "system",
@@ -272722,6 +274216,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
272722
274216
  form: "single",
272723
274217
  optional: false
272724
274218
  }],
274219
+ "pipelineAnalytics.getGroup": [{
274220
+ name: "deviceId",
274221
+ form: "single",
274222
+ optional: false
274223
+ }],
272725
274224
  "pipelineAnalytics.getKeyEvents": [{
272726
274225
  name: "deviceId",
272727
274226
  form: "single",
@@ -272777,6 +274276,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
272777
274276
  form: "array",
272778
274277
  optional: false
272779
274278
  }],
274279
+ "pipelineAnalytics.listGroups": [{
274280
+ name: "deviceIds",
274281
+ form: "array",
274282
+ optional: false
274283
+ }],
272780
274284
  "pipelineAnalytics.listOpsLog": [{
272781
274285
  name: "deviceId",
272782
274286
  form: "single",
@@ -274313,9 +275817,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274313
275817
  getConnectionEndpoints: (input) => dispatch("localNetwork", "getConnectionEndpoints", "query", input),
274314
275818
  getNotificationEndpoint: (input) => dispatch("localNetwork", "getNotificationEndpoint", "query", input),
274315
275819
  setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
275820
+ getViewerEndpoints: (input) => dispatch("localNetwork", "getViewerEndpoints", "query", input),
275821
+ setViewerEndpoints: (input) => dispatch("localNetwork", "setViewerEndpoints", "mutation", input),
274316
275822
  getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
274317
275823
  setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
274318
- resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input)
275824
+ resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input),
275825
+ getTlsStatus: (input) => dispatch("localNetwork", "getTlsStatus", "query", input),
275826
+ regenerateCertificate: (input) => dispatch("localNetwork", "regenerateCertificate", "mutation", input),
275827
+ uploadCertificate: (input) => dispatch("localNetwork", "uploadCertificate", "mutation", input),
275828
+ downloadCa: (input) => dispatch("localNetwork", "downloadCa", "query", input),
275829
+ revertToGeneratedCertificate: (input) => dispatch("localNetwork", "revertToGeneratedCertificate", "mutation", input)
274319
275830
  },
274320
275831
  meshNetwork: {
274321
275832
  getStatus: (input) => dispatch("meshNetwork", "getStatus", "query", input),
@@ -274597,6 +276108,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274597
276108
  listProfiles: (input) => dispatch("terminalSession", "listProfiles", "query", input),
274598
276109
  listInstances: (input) => dispatch("terminalSession", "listInstances", "query", input),
274599
276110
  createInstance: (input) => dispatch("terminalSession", "createInstance", "mutation", input),
276111
+ updateInstance: (input) => dispatch("terminalSession", "updateInstance", "mutation", input),
274600
276112
  deleteInstance: (input) => dispatch("terminalSession", "deleteInstance", "mutation", input),
274601
276113
  setInstanceEnabled: (input) => dispatch("terminalSession", "setInstanceEnabled", "mutation", input),
274602
276114
  listLegacyCameras: (input) => dispatch("terminalSession", "listLegacyCameras", "query", input),
@@ -274655,6 +276167,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274655
276167
  var NC_AUDIO_HIT_PERCENT_MAX = 100;
274656
276168
  var NC_AUDIO_SAMPLING_MIN_SEC = 1;
274657
276169
  var NC_AUDIO_SAMPLING_MAX_SEC = 300;
276170
+ var NC_AUDIO_CONFIRM_HITS_DEFAULT = 2;
276171
+ var NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT = 5;
276172
+ var NC_AUDIO_CONFIRM_HITS_MIN = 1;
276173
+ var NC_AUDIO_CONFIRM_HITS_MAX = 20;
276174
+ var NC_AUDIO_CONFIRM_WINDOW_MIN_SEC = 1;
276175
+ var NC_AUDIO_CONFIRM_WINDOW_MAX_SEC = 60;
274658
276176
  var NC_AUDIO_DEFAULTS = {
274659
276177
  hitPercent: 60,
274660
276178
  samplingSeconds: 10
@@ -274691,7 +276209,15 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274691
276209
  ...labels !== void 0 ? { labels: [...labels] } : {},
274692
276210
  ...dbThreshold !== void 0 ? { dbThreshold: clampInt(dbThreshold, NC_AUDIO_DB_MIN, 0) } : {},
274693
276211
  hitPercent: clampInt(patch.hitPercent ?? base.hitPercent, 1, 100),
274694
- samplingSeconds: clampInt(patch.samplingSeconds ?? base.samplingSeconds, 1, 300)
276212
+ samplingSeconds: clampInt(patch.samplingSeconds ?? base.samplingSeconds, 1, 300),
276213
+ ...(() => {
276214
+ const hits = has(patch, "confirmHits") ? patch.confirmHits : base.confirmHits;
276215
+ const windowSec = has(patch, "confirmWindowSec") ? patch.confirmWindowSec : base.confirmWindowSec;
276216
+ return {
276217
+ ...hits !== void 0 ? { confirmHits: clampInt(hits, 1, 20) } : {},
276218
+ ...windowSec !== void 0 ? { confirmWindowSec: clampInt(windowSec, 1, 60) } : {}
276219
+ };
276220
+ })()
274695
276221
  };
274696
276222
  }
274697
276223
  function audioLabelChoices(taxonomy, selected) {
@@ -275511,6 +277037,58 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275511
277037
  const chosen = models[stepId];
275512
277038
  return chosen !== void 0 && chosen !== "" ? chosen : step2.defaultModelId;
275513
277039
  }
277040
+ var DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = 24;
277041
+ var CLUSTER_STEP_SETTING_FIELDS = [{
277042
+ stepId: "face-embedding",
277043
+ key: "minLandmarkFaceSize",
277044
+ label: "Min face size for recognition (detection px)",
277045
+ 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.",
277046
+ type: "slider",
277047
+ min: 0,
277048
+ max: 64,
277049
+ step: 2,
277050
+ default: 24
277051
+ }];
277052
+ function clusterStepSettingKey(stepId, fieldKey) {
277053
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
277054
+ }
277055
+ function clusterStepSettingFieldsFor(stepId) {
277056
+ return CLUSTER_STEP_SETTING_FIELDS.filter((field) => field.stepId === stepId);
277057
+ }
277058
+ var ClusterSettingNumberSchema = zod.z.number().finite();
277059
+ function readClusterStepSettings(config) {
277060
+ const out = {};
277061
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
277062
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
277063
+ const value = parsed.success ? parsed.data : field.default;
277064
+ const existing = out[field.stepId] ?? {};
277065
+ out[field.stepId] = {
277066
+ ...existing,
277067
+ [field.key]: value
277068
+ };
277069
+ }
277070
+ return out;
277071
+ }
277072
+ var DEFAULT_CLUSTER_STEP_SETTINGS = readClusterStepSettings({});
277073
+ function pickClusterStepSettings(view) {
277074
+ if (view === null) return DEFAULT_CLUSTER_STEP_SETTINGS;
277075
+ const flat = {};
277076
+ const wanted = new Set(CLUSTER_STEP_SETTING_FIELDS.map((field) => clusterStepSettingKey(field.stepId, field.key)));
277077
+ for (const section of view.sections) for (const entry of section.fields) {
277078
+ if (!isHydratedField$2(entry) || typeof entry.key !== "string") continue;
277079
+ if (wanted.has(entry.key)) flat[entry.key] = entry.value;
277080
+ }
277081
+ return readClusterStepSettings(flat);
277082
+ }
277083
+ function overlayClusterStepSettings(stepId, deviceSettings, cluster) {
277084
+ const overlay = cluster[stepId];
277085
+ if (overlay === void 0 || Object.keys(overlay).length === 0) return deviceSettings === void 0 ? void 0 : { ...deviceSettings };
277086
+ if (deviceSettings === void 0) return { ...overlay };
277087
+ return {
277088
+ ...deviceSettings,
277089
+ ...overlay
277090
+ };
277091
+ }
275514
277092
  var DETAIL_CROP_SECTION_ID = "detail-crop";
275515
277093
  var DETAIL_CROP_PADDING_KEY = "detailCropPaddingRatio";
275516
277094
  var DETAIL_CROP_SQUARE_KEY = "detailCropSquare";
@@ -277223,6 +278801,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277223
278801
  exports.AlertSourceSchema = AlertSourceSchema;
277224
278802
  exports.AlertStatusSchema = AlertStatusSchema;
277225
278803
  exports.AmbientLightSensorStatusSchema = AmbientLightSensorStatusSchema;
278804
+ exports.AnalyticsGroupDetailSchema = AnalyticsGroupDetailSchema;
278805
+ exports.AnalyticsGroupMemberSchema = AnalyticsGroupMemberSchema;
278806
+ exports.AnalyticsGroupRecordSchema = AnalyticsGroupRecordSchema;
277226
278807
  exports.ApiKeyRecordSchema = ApiKeyRecordSchema;
277227
278808
  exports.ApiKeySummarySchema = ApiKeySummarySchema;
277228
278809
  exports.ArchiveEntrySchema = ArchiveEntrySchema;
@@ -277299,8 +278880,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277299
278880
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
277300
278881
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
277301
278882
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
278883
+ exports.CLASS_MAP_MACRO_TARGETS = CLASS_MAP_MACRO_TARGETS;
277302
278884
  exports.CLUSTER_MODEL_SCOPED_STEPS = CLUSTER_MODEL_SCOPED_STEPS;
277303
278885
  exports.CLUSTER_MODEL_SECTION_ID = CLUSTER_MODEL_SECTION_ID;
278886
+ exports.CLUSTER_STEP_SETTING_FIELDS = CLUSTER_STEP_SETTING_FIELDS;
277304
278887
  exports.COCO_80_LABELS = COCO_80_LABELS;
277305
278888
  exports.COCO_TO_MACRO = COCO_TO_MACRO;
277306
278889
  exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
@@ -277344,6 +278927,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277344
278927
  exports.CapabilityBindingsSchema = CapabilityBindingsSchema;
277345
278928
  exports.CarbonMonoxideStatusSchema = CarbonMonoxideStatusSchema;
277346
278929
  exports.ChargingStatus = require_sleep.ChargingStatus;
278930
+ exports.ClassMapDefinitionSchema = ClassMapDefinitionSchema;
277347
278931
  exports.ClientNetworkStatsSchema = ClientNetworkStatsSchema;
277348
278932
  exports.ClimateControlStatusSchema = ClimateControlStatusSchema;
277349
278933
  exports.ClipPlaybackSchema = ClipPlaybackSchema;
@@ -277389,11 +278973,13 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277389
278973
  exports.DEFAULT_ADDON_PLACEMENT = DEFAULT_ADDON_PLACEMENT;
277390
278974
  exports.DEFAULT_AUDIO_ANALYZER_CONFIG = DEFAULT_AUDIO_ANALYZER_CONFIG;
277391
278975
  exports.DEFAULT_CLUSTER_STEP_MODELS = DEFAULT_CLUSTER_STEP_MODELS;
278976
+ exports.DEFAULT_CLUSTER_STEP_SETTINGS = DEFAULT_CLUSTER_STEP_SETTINGS;
277392
278977
  exports.DEFAULT_DECODER_HWACCEL_CONFIG = DEFAULT_DECODER_HWACCEL_CONFIG;
277393
278978
  exports.DEFAULT_DETAIL_CROP_CONVENTION = DEFAULT_DETAIL_CROP_CONVENTION;
277394
278979
  exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
277395
278980
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
277396
278981
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
278982
+ exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
277397
278983
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
277398
278984
  exports.DEFAULT_POOL_MEMORY_POLICY = DEFAULT_POOL_MEMORY_POLICY;
277399
278985
  exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
@@ -277517,6 +279103,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277517
279103
  exports.FrameHandleFormatSchema = require_sleep.FrameHandleFormatSchema;
277518
279104
  exports.FrameHandleSchema = require_sleep.FrameHandleSchema;
277519
279105
  exports.FrameInputSchema = FrameInputSchema;
279106
+ exports.FrameLazyCountersSchema = FrameLazyCountersSchema;
279107
+ exports.FrameLazyMetricsSchema = FrameLazyMetricsSchema;
277520
279108
  exports.GasStatusSchema = GasStatusSchema;
277521
279109
  exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
277522
279110
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
@@ -277559,6 +279147,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277559
279147
  exports.LawnMowerControlStatusSchema = LawnMowerControlStatusSchema;
277560
279148
  exports.LinkedDeviceSchema = LinkedDeviceSchema;
277561
279149
  exports.LinkedDevicesModeSchema = LinkedDevicesModeSchema;
279150
+ exports.ListGroupsPageSchema = ListGroupsPageSchema;
279151
+ exports.ListGroupsQueryInput = ListGroupsQueryInput;
277562
279152
  exports.LlmDefaultSchema = LlmDefaultSchema;
277563
279153
  exports.LlmDefaultSelectorSchema = LlmDefaultSelectorSchema;
277564
279154
  exports.LlmDownloadProgressSchema = LlmDownloadProgressSchema;
@@ -277602,6 +279192,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277602
279192
  exports.METHOD_ACCESS_MAP = METHOD_ACCESS_MAP;
277603
279193
  exports.METHOD_DEVICE_SELECTORS = METHOD_DEVICE_SELECTORS;
277604
279194
  exports.MODEL_FORMATS = MODEL_FORMATS;
279195
+ exports.MODEL_PROVIDER_IDS = MODEL_PROVIDER_IDS;
277605
279196
  exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
277606
279197
  exports.ManagedModelCatalogEntrySchema = ManagedModelCatalogEntrySchema;
277607
279198
  exports.ManagedModelExtraFileSchema = ManagedModelExtraFileSchema;
@@ -277632,6 +279223,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277632
279223
  exports.ModelExtraFileSchema = ModelExtraFileSchema;
277633
279224
  exports.ModelFormatEntrySchema = ModelFormatEntrySchema;
277634
279225
  exports.ModelFormatsSchema = ModelFormatsSchema;
279226
+ exports.ModelProviderIdSchema = ModelProviderIdSchema;
277635
279227
  exports.ModelSubstitutionSchema = ModelSubstitutionSchema;
277636
279228
  exports.ModelVariantGroupSchema = ModelVariantGroupSchema;
277637
279229
  exports.MotionAnalysisResultSchema = MotionAnalysisResultSchema;
@@ -277661,6 +279253,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
277661
279253
  exports.NATIVE_LEASE_TILE_BUDGET_FIELD = NATIVE_LEASE_TILE_BUDGET_FIELD;
277662
279254
  exports.NATIVE_LEASE_TILE_BUDGET_KEY = NATIVE_LEASE_TILE_BUDGET_KEY;
277663
279255
  exports.NC_ALARM_SYSTEM_EVENT_KINDS = NC_ALARM_SYSTEM_EVENT_KINDS;
279256
+ exports.NC_AUDIO_CONFIRM_HITS_DEFAULT = NC_AUDIO_CONFIRM_HITS_DEFAULT;
279257
+ exports.NC_AUDIO_CONFIRM_HITS_MAX = NC_AUDIO_CONFIRM_HITS_MAX;
279258
+ exports.NC_AUDIO_CONFIRM_HITS_MIN = NC_AUDIO_CONFIRM_HITS_MIN;
279259
+ exports.NC_AUDIO_CONFIRM_WINDOW_MAX_SEC = NC_AUDIO_CONFIRM_WINDOW_MAX_SEC;
279260
+ exports.NC_AUDIO_CONFIRM_WINDOW_MIN_SEC = NC_AUDIO_CONFIRM_WINDOW_MIN_SEC;
279261
+ exports.NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT = NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT;
277664
279262
  exports.NC_AUDIO_DBFS_FLOOR = NC_AUDIO_DBFS_FLOOR;
277665
279263
  exports.NC_AUDIO_DB_MAX = NC_AUDIO_DB_MAX;
277666
279264
  exports.NC_AUDIO_DB_MIN = NC_AUDIO_DB_MIN;
@@ -278171,6 +279769,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278171
279769
  exports.classifyStreams = classifyStreams;
278172
279770
  exports.climateControlCapability = climateControlCapability;
278173
279771
  exports.clusterModelSettingKey = clusterModelSettingKey;
279772
+ exports.clusterStepSettingFieldsFor = clusterStepSettingFieldsFor;
279773
+ exports.clusterStepSettingKey = clusterStepSettingKey;
278174
279774
  exports.collectHydratedFieldEntries = require_sleep.collectHydratedFieldEntries;
278175
279775
  exports.collectHydratedFieldValues = require_sleep.collectHydratedFieldValues;
278176
279776
  exports.colorCapability = colorCapability;
@@ -278197,6 +279797,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278197
279797
  exports.createDeviceProxy = require_sleep.createDeviceProxy;
278198
279798
  exports.createDurableState = require_sleep.createDurableState;
278199
279799
  exports.createEvent = require_sleep.createEvent;
279800
+ exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
278200
279801
  exports.createExpressionScope = createExpressionScope;
278201
279802
  exports.createHwAccelCache = createHwAccelCache;
278202
279803
  exports.createLazyTrpcSource = require_sleep.createLazyTrpcSource;
@@ -278279,6 +279880,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278279
279880
  exports.hydrateSchema = require_sleep.hydrateSchema;
278280
279881
  exports.imageCapability = imageCapability;
278281
279882
  exports.imageSettingsCapability = imageSettingsCapability;
279883
+ exports.inferModelProvider = inferModelProvider;
278282
279884
  exports.initialPoolMemoryState = initialPoolMemoryState;
278283
279885
  exports.integrationsCapability = integrationsCapability;
278284
279886
  exports.intercomCapability = intercomCapability;
@@ -278361,6 +279963,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278361
279963
  exports.objectInputDeclaresAddonId = objectInputDeclaresAddonId;
278362
279964
  exports.osdCapability = osdCapability;
278363
279965
  exports.osdManagerCapability = osdManagerCapability;
279966
+ exports.overlayClusterStepSettings = overlayClusterStepSettings;
278364
279967
  exports.parseCameraStreamConfig = parseCameraStreamConfig;
278365
279968
  exports.parseExpression = parseExpression;
278366
279969
  exports.parseJsonArray = require_sleep.parseJsonArray;
@@ -278374,6 +279977,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278374
279977
  exports.petFeederCapability = petFeederCapability;
278375
279978
  exports.pickAccessoryControl = pickAccessoryControl;
278376
279979
  exports.pickClusterStepModels = pickClusterStepModels;
279980
+ exports.pickClusterStepSettings = pickClusterStepSettings;
278377
279981
  exports.pickDetailCropConvention = pickDetailCropConvention;
278378
279982
  exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
278379
279983
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
@@ -278398,6 +280002,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278398
280002
  exports.ptzCapability = ptzCapability;
278399
280003
  exports.pythonScriptForBackend = pythonScriptForBackend;
278400
280004
  exports.readClusterStepModels = readClusterStepModels;
280005
+ exports.readClusterStepSettings = readClusterStepSettings;
278401
280006
  exports.readDetailCropConvention = readDetailCropConvention;
278402
280007
  exports.readDeviceStateFrom = readDeviceStateFrom;
278403
280008
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
@@ -394926,18 +396531,26 @@ var require_session_cookie = __commonJS({
394926
396531
  exports.isEmbedRedirectTarget = isEmbedRedirectTarget;
394927
396532
  exports.isSessionGradeJwtPayload = isSessionGradeJwtPayload;
394928
396533
  exports.SESSION_COOKIE = "camstack_session";
394929
- function buildSessionCookie(token2, ttlSec) {
396534
+ function buildSessionCookie(token2, ttlSec, opts = {}) {
394930
396535
  return {
394931
396536
  name: exports.SESSION_COOKIE,
394932
396537
  value: token2,
394933
- options: { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: ttlSec }
396538
+ options: {
396539
+ httpOnly: true,
396540
+ sameSite: "lax",
396541
+ // Secure cookies are invisible on the LAN HTTP sibling (plain http://).
396542
+ // Default stays true so HTTPS callers do not regress.
396543
+ secure: opts.secure ?? true,
396544
+ path: "/",
396545
+ maxAge: ttlSec
396546
+ }
394934
396547
  };
394935
396548
  }
394936
- function clearSessionCookie() {
396549
+ function clearSessionCookie(opts = {}) {
394937
396550
  return {
394938
396551
  name: exports.SESSION_COOKIE,
394939
396552
  value: "",
394940
- options: { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: 0 }
396553
+ options: { httpOnly: true, sameSite: "lax", secure: opts.secure ?? true, path: "/", maxAge: 0 }
394941
396554
  };
394942
396555
  }
394943
396556
  function readSessionCookieFromHeader(header) {
@@ -395102,6 +396715,25 @@ var require_health_routes = __commonJS({
395102
396715
  }
395103
396716
  });
395104
396717
 
396718
+ // ../../server/backend/dist/api/health/adaptive-probe.routes.js
396719
+ var require_adaptive_probe_routes = __commonJS({
396720
+ "../../server/backend/dist/api/health/adaptive-probe.routes.js"(exports) {
396721
+ "use strict";
396722
+ Object.defineProperty(exports, "__esModule", { value: true });
396723
+ exports.ADAPTIVE_PROBE_BYTES = void 0;
396724
+ exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
396725
+ exports.ADAPTIVE_PROBE_BYTES = 128 * 1024;
396726
+ var BODY = Buffer.alloc(exports.ADAPTIVE_PROBE_BYTES, 97);
396727
+ function registerAdaptiveProbeRoute(fastify) {
396728
+ fastify.get("/adaptive-probe", async (_req, reply) => {
396729
+ reply.header("cache-control", "no-store");
396730
+ reply.header("content-type", "application/octet-stream");
396731
+ return reply.send(BODY);
396732
+ });
396733
+ }
396734
+ }
396735
+ });
396736
+
395105
396737
  // ../../server/backend/dist/api/model-distributor.js
395106
396738
  var require_model_distributor = __commonJS({
395107
396739
  "../../server/backend/dist/api/model-distributor.js"(exports) {
@@ -402068,19 +403700,8 @@ var require_trpc_router = __commonJS({
402068
403700
  const relayOnly = FORCE_RELAY_REMOTE ? (0, client_ip_js_1.deriveRelayOnly)(clientClass) : false;
402069
403701
  return { ...input, relayOnly };
402070
403702
  }
402071
- var REMOTE_INITIAL_ADAPTIVE_TIER = "low";
402072
- function enrichHintsWithClientClass(input, clientClass) {
402073
- if (clientClass !== "remote")
402074
- return input;
402075
- const isAdaptive = input.target === void 0 || input.target.kind === "adaptive";
402076
- if (!isAdaptive)
402077
- return input;
402078
- if (input.hints?.prefersTier !== void 0)
402079
- return input;
402080
- return {
402081
- ...input,
402082
- hints: { ...input.hints, prefersTier: REMOTE_INITIAL_ADAPTIVE_TIER }
402083
- };
403703
+ function enrichHintsWithClientClass(input, _clientClass) {
403704
+ return input;
402084
403705
  }
402085
403706
  function wrapWebrtcSessionProviderWithRelay(provider, ctx) {
402086
403707
  const userAgent = (0, client_ip_js_1.extractUserAgent)(ctx.req);
@@ -402418,7 +404039,8 @@ var require_boot_config = __commonJS({
402418
404039
  const pair = loadTlsCert(config.tls.certPath, config.tls.keyPath);
402419
404040
  tlsOptions = { key: pair.key, cert: pair.cert };
402420
404041
  } else {
402421
- const tlsResult = await ensureTlsCert(dataPath);
404042
+ const extraSans = [...core.readExtraSans?.(dataPath) ?? []];
404043
+ const tlsResult = await ensureTlsCert(dataPath, extraSans.length > 0 ? { extraSans } : void 0);
402422
404044
  tlsCert = tlsResult;
402423
404045
  logTlsCert(tlsResult);
402424
404046
  const pair = loadTlsCert(tlsResult.certPath, tlsResult.keyPath);
@@ -403509,90 +405131,127 @@ var require_addon_registry_service = __commonJS({
403509
405131
  return entry?.packageName === "@camstack/system" && entry.declaration !== void 0 && (0, types_1.isIsolatedBuiltin)(entry.declaration);
403510
405132
  });
403511
405133
  const isolatedBuiltins = new Set(isolatedBuiltinIds);
403512
- await spawnRunnerPlan(this.buildAddonGroupPlan(allIds.filter((id) => !isolatedBuiltins.has(id))));
405134
+ const { infra: isolatedInfraIds, consumers: isolatedConsumerIds } = (0, system_1.partitionIsolatedBuiltinIds)(isolatedBuiltinIds, (id) => {
405135
+ const entry = this.addonEntries.get(id);
405136
+ return entry?.declaredCapabilities ?? [];
405137
+ });
403513
405138
  const isCoreBuiltin = (id) => this.addonEntries.get(id)?.packageName === "@camstack/system" && !isolatedBuiltins.has(id);
403514
- for (const infra of system_1.INFRA_CAPABILITIES) {
403515
- const addonId = this.findAddonForCapability(infra.name, allIds);
403516
- if (addonId) {
403517
- const entry = this.addonEntries.get(addonId);
403518
- if (!entry || entry.initialized || !isCoreBuiltin(addonId))
403519
- continue;
405139
+ await (0, system_1.runHubAddonBoot)({
405140
+ spawnIsolatedInfra: async () => {
405141
+ if (isolatedInfraIds.length === 0)
405142
+ return;
405143
+ this.logger.info("Spawning isolated infrastructure builtins", {
405144
+ meta: { addonIds: isolatedInfraIds }
405145
+ });
405146
+ await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedInfraIds));
405147
+ },
405148
+ waitForDataStoreProvider: async () => {
405149
+ if (isolatedInfraIds.length === 0)
405150
+ return;
403520
405151
  try {
403521
- await this.initializeAddon(addonId);
403522
- this.wireCapabilities(addonId);
403523
- } catch (error) {
403524
- const msg = (0, types_1.errMsg)(error);
403525
- this.emitAddonLifecycleEvent("addon.error", addonId, {
403526
- error: msg,
403527
- phase: "init"
405152
+ await (0, system_1.waitUntilReady)(() => this.capabilityRegistry.getCollection("data-store-provider").length > 0, {
405153
+ timeoutMs: 3e4,
405154
+ intervalMs: 50,
405155
+ what: "isolated data-store-provider engine"
403528
405156
  });
403529
- if (infra.required) {
403530
- throw new Error(`Required infrastructure addon "${addonId}" failed: ${msg}`, {
403531
- cause: error
403532
- });
403533
- }
403534
- this.logger.warn("Optional infra addon failed -- continuing", {
403535
- tags: { addonId },
403536
- meta: { error: msg }
405157
+ } catch (err) {
405158
+ this.logger.error("Isolated data-store-provider engine did not register in time", {
405159
+ meta: { error: (0, types_1.errMsg)(err), addonIds: isolatedInfraIds }
403537
405160
  });
403538
405161
  }
403539
- } else if (infra.required) {
403540
- throw new Error(`No addon provides required infrastructure capability "${infra.name}"`);
403541
- }
403542
- }
403543
- const bootOrder = this.capabilityRegistry.getBootOrder();
403544
- const infraNames = new Set(system_1.INFRA_CAPABILITIES.map((c) => c.name));
403545
- for (const capName of bootOrder) {
403546
- if (infraNames.has(capName))
403547
- continue;
403548
- for (const id of allIds) {
403549
- const entry = this.addonEntries.get(id);
403550
- if (!entry || entry.initialized || !isCoreBuiltin(id))
403551
- continue;
403552
- const provides = this.getAddonCapabilities(entry.addon);
403553
- if (!provides.some((c) => c.name === capName))
403554
- continue;
403555
- try {
403556
- await this.initializeAddon(id);
403557
- this.wireCapabilities(id);
403558
- } catch (error) {
403559
- const msg = (0, types_1.errMsg)(error);
403560
- this.emitAddonLifecycleEvent("addon.error", id, {
403561
- error: msg,
403562
- phase: "init"
403563
- });
403564
- this.logger.error("Core builtin failed to initialize -- skipping", {
403565
- tags: { addonId: id },
403566
- meta: { error: msg }
403567
- });
405162
+ },
405163
+ bootInProcessInfra: async () => {
405164
+ for (const infra of system_1.INFRA_CAPABILITIES) {
405165
+ const addonId = this.findAddonForCapability(infra.name, allIds);
405166
+ if (addonId) {
405167
+ const entry = this.addonEntries.get(addonId);
405168
+ if (!entry || entry.initialized || !isCoreBuiltin(addonId))
405169
+ continue;
405170
+ try {
405171
+ await this.initializeAddon(addonId);
405172
+ this.wireCapabilities(addonId);
405173
+ } catch (error) {
405174
+ const msg = (0, types_1.errMsg)(error);
405175
+ this.emitAddonLifecycleEvent("addon.error", addonId, {
405176
+ error: msg,
405177
+ phase: "init"
405178
+ });
405179
+ if (infra.required) {
405180
+ throw new Error(`Required infrastructure addon "${addonId}" failed: ${msg}`, {
405181
+ cause: error
405182
+ });
405183
+ }
405184
+ this.logger.warn("Optional infra addon failed -- continuing", {
405185
+ tags: { addonId },
405186
+ meta: { error: msg }
405187
+ });
405188
+ }
405189
+ } else if (infra.required) {
405190
+ throw new Error(`No addon provides required infrastructure capability "${infra.name}"`);
405191
+ }
403568
405192
  }
403569
- }
403570
- }
403571
- for (const id of allIds) {
403572
- const entry = this.addonEntries.get(id);
403573
- if (entry && !entry.initialized && isCoreBuiltin(id)) {
403574
- try {
403575
- await this.initializeAddon(id);
403576
- this.wireCapabilities(id);
403577
- } catch (error) {
403578
- const msg = (0, types_1.errMsg)(error);
403579
- this.emitAddonLifecycleEvent("addon.error", id, {
403580
- error: msg,
403581
- phase: "init"
403582
- });
403583
- this.logger.error("Core builtin failed to initialize -- skipping", {
403584
- tags: { addonId: id },
403585
- meta: { error: msg }
403586
- });
405193
+ },
405194
+ spawnForkedAddons: async () => {
405195
+ await spawnRunnerPlan(this.buildAddonGroupPlan(allIds.filter((id) => !isolatedBuiltins.has(id))));
405196
+ },
405197
+ bootInProcessConsumers: async () => {
405198
+ const bootOrder = this.capabilityRegistry.getBootOrder();
405199
+ const infraNames = new Set(system_1.INFRA_CAPABILITIES.map((c) => c.name));
405200
+ for (const capName of bootOrder) {
405201
+ if (infraNames.has(capName))
405202
+ continue;
405203
+ for (const id of allIds) {
405204
+ const entry = this.addonEntries.get(id);
405205
+ if (!entry || entry.initialized || !isCoreBuiltin(id))
405206
+ continue;
405207
+ const provides = this.getAddonCapabilities(entry.addon);
405208
+ if (!provides.some((c) => c.name === capName))
405209
+ continue;
405210
+ try {
405211
+ await this.initializeAddon(id);
405212
+ this.wireCapabilities(id);
405213
+ } catch (error) {
405214
+ const msg = (0, types_1.errMsg)(error);
405215
+ this.emitAddonLifecycleEvent("addon.error", id, {
405216
+ error: msg,
405217
+ phase: "init"
405218
+ });
405219
+ this.logger.error("Core builtin failed to initialize -- skipping", {
405220
+ tags: { addonId: id },
405221
+ meta: { error: msg }
405222
+ });
405223
+ }
405224
+ }
405225
+ }
405226
+ for (const id of allIds) {
405227
+ const entry = this.addonEntries.get(id);
405228
+ if (entry && !entry.initialized && isCoreBuiltin(id)) {
405229
+ try {
405230
+ await this.initializeAddon(id);
405231
+ this.wireCapabilities(id);
405232
+ } catch (error) {
405233
+ const msg = (0, types_1.errMsg)(error);
405234
+ this.emitAddonLifecycleEvent("addon.error", id, {
405235
+ error: msg,
405236
+ phase: "init"
405237
+ });
405238
+ this.logger.error("Core builtin failed to initialize -- skipping", {
405239
+ tags: { addonId: id },
405240
+ meta: { error: msg }
405241
+ });
405242
+ }
405243
+ }
403587
405244
  }
405245
+ },
405246
+ spawnIsolatedConsumers: async () => {
405247
+ if (isolatedConsumerIds.length === 0)
405248
+ return;
405249
+ this.logger.info("Spawning isolated system builtins", {
405250
+ meta: { addonIds: isolatedConsumerIds }
405251
+ });
405252
+ await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedConsumerIds));
403588
405253
  }
403589
- }
403590
- if (isolatedBuiltinIds.length > 0) {
403591
- this.logger.info("Spawning isolated system builtins", {
403592
- meta: { addonIds: isolatedBuiltinIds }
403593
- });
403594
- await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedBuiltinIds));
403595
- }
405254
+ });
403596
405255
  const initializedIds = [...this.addonEntries.entries()].filter(([, e]) => e.initialized).map(([id]) => id);
403597
405256
  this.logger.info("Addons initialized", {
403598
405257
  meta: { initializedCount: initializedIds.length, totalCount: this.addonEntries.size }
@@ -404855,12 +406514,13 @@ var require_addon_registry_service = __commonJS({
404855
406514
  if (syncStore) {
404856
406515
  this.configService.setSettingsStore(syncStore);
404857
406516
  } else {
404858
- this.logger.error("settings-store provider does not implement the sync ConfigManager surface and no data-store-provider engine does either \u2014 every addon store reads empty, devices will NOT be restored", { meta: { addonId, phase: "v2" } });
406517
+ this.logger.info("settings-store engine is isolated \u2014 ConfigManager uses the async door, not a sync ISettingsStore", { meta: { addonId, phase: "v2" } });
404859
406518
  }
404860
406519
  this.storageService.setSettingsBackend(provider);
404861
406520
  const store = this.capabilityRegistry.getProviderByAddon("settings-store", addonId);
404862
406521
  if (!store)
404863
406522
  return;
406523
+ this.configService.setSettingsDoor(store);
404864
406524
  this.integrationRegistry = new system_1.IntegrationRegistry(store);
404865
406525
  void this.integrationRegistry.initialize().then(() => {
404866
406526
  this.logger.info("IntegrationRegistry initialized", { meta: { phase: "v2" } });
@@ -407334,15 +408994,15 @@ var require_moleculer_service = __commonJS({
407334
408994
  "../../server/backend/dist/core/moleculer/moleculer.service.js"(exports) {
407335
408995
  "use strict";
407336
408996
  Object.defineProperty(exports, "__esModule", { value: true });
407337
- exports.MoleculerService = void 0;
408997
+ exports.ChildManifestGate = exports.CHILD_MANIFEST_SKIP_SAMPLE = exports.MoleculerService = void 0;
407338
408998
  exports.childOwnerToken = childOwnerToken;
407339
408999
  exports.buildChildUdsManifest = buildChildUdsManifest;
407340
409000
  var node_crypto_1 = __require("crypto");
407341
409001
  var system_1 = require_dist3();
407342
409002
  var types_1 = require_dist9();
407343
- var agent_readiness_pull_js_1 = require_agent_readiness_pull();
407344
409003
  var cap_router_runtime_js_1 = require_cap_router_runtime();
407345
409004
  var core_cap_bridge_js_1 = require_core_cap_bridge();
409005
+ var agent_readiness_pull_js_1 = require_agent_readiness_pull();
407346
409006
  var cap_call_fn_js_1 = require_cap_call_fn();
407347
409007
  var cap_route_authority_js_1 = require_cap_route_authority();
407348
409008
  var MoleculerService = class _MoleculerService {
@@ -407377,6 +409037,12 @@ var require_moleculer_service = __commonJS({
407377
409037
  * See `docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md`.
407378
409038
  */
407379
409039
  nodeOwners = /* @__PURE__ */ new Map();
409040
+ /**
409041
+ * Skips the manifest rebuild for a child re-register that carries nothing new
409042
+ * — 246 of them in 30 minutes with zero respawns, measured live 2026-08-25.
409043
+ * See {@link ChildManifestGate}.
409044
+ */
409045
+ childManifestGate = new ChildManifestGate();
407380
409046
  /**
407381
409047
  * Fixed-period agent-readiness snapshot sweep (D8 reconcile) — repairs
407382
409048
  * agent-origin readiness deltas lost while the agent stayed connected.
@@ -407698,6 +409364,19 @@ var require_moleculer_service = __commonJS({
407698
409364
  const hubNodeId = this.brokerSafe.nodeID;
407699
409365
  const childNodeId = `${hubNodeId}/${child.childId}`;
407700
409366
  const params = buildChildUdsManifest(childNodeId, child.childId, child.caps);
409367
+ if (!this.childManifestGate.shouldApply(child.childId, child.incarnation, params)) {
409368
+ if (this.childManifestGate.sampleDue()) {
409369
+ logger.debug("UDS child re-registered with an unchanged manifest \u2014 skipped", {
409370
+ meta: {
409371
+ nodeId: childNodeId,
409372
+ incarnation: child.incarnation,
409373
+ skipped: this.childManifestGate.skippedSince(),
409374
+ sampleEvery: exports.CHILD_MANIFEST_SKIP_SAMPLE
409375
+ }
409376
+ });
409377
+ }
409378
+ return;
409379
+ }
407701
409380
  this.onRegisterNode(params, childOwnerToken(childNodeId, child.incarnation));
407702
409381
  logger.info("UDS child registered \u2014 manifest applied", {
407703
409382
  meta: { nodeId: childNodeId, incarnation: child.incarnation }
@@ -407706,6 +409385,7 @@ var require_moleculer_service = __commonJS({
407706
409385
  registry.onChildGone((childId, incarnation) => {
407707
409386
  const hubNodeId = this.brokerSafe.nodeID;
407708
409387
  const childNodeId = `${hubNodeId}/${childId}`;
409388
+ this.childManifestGate.forget(childId);
407709
409389
  logger.info("UDS child gone \u2014 removing from registry", {
407710
409390
  meta: { childId, incarnation }
407711
409391
  });
@@ -407940,12 +409620,13 @@ var require_moleculer_service = __commonJS({
407940
409620
  if (!registry)
407941
409621
  return;
407942
409622
  const registryKeyFor = (addonId) => isLocalChild ? addonId : `${addonId}@${nodeId}`;
409623
+ const skipInfraFromRemote = (capName) => (0, system_1.isInfraCapability)(capName) && !isLocalChild;
407943
409624
  const appliedKeys = (manifest) => {
407944
409625
  const keys = /* @__PURE__ */ new Map();
407945
409626
  for (const addon of manifest) {
407946
409627
  const registryKey = registryKeyFor(addon.addonId);
407947
409628
  for (const capName of addon.capabilities) {
407948
- if ((0, system_1.isInfraCapability)(capName))
409629
+ if (skipInfraFromRemote(capName))
407949
409630
  continue;
407950
409631
  const capDef = registry.getDefinition(capName);
407951
409632
  if (!capDef)
@@ -408236,6 +409917,48 @@ var require_moleculer_service = __commonJS({
408236
409917
  function childOwnerToken(childNodeId, incarnation) {
408237
409918
  return `${childNodeId}#${incarnation}`;
408238
409919
  }
409920
+ exports.CHILD_MANIFEST_SKIP_SAMPLE = 25;
409921
+ function childManifestFingerprint(params) {
409922
+ const addons = params.addons.map((addon) => `${addon.addonId}:${[...addon.capabilities].sort().join(",")}`).sort();
409923
+ return `${params.nodeId}|${addons.join("|")}`;
409924
+ }
409925
+ var ChildManifestGate = class {
409926
+ applied = /* @__PURE__ */ new Map();
409927
+ skipped = 0;
409928
+ sinceSample = 0;
409929
+ /** True when this registration carries something the registry does not have. */
409930
+ shouldApply(childId, incarnation, params) {
409931
+ const fingerprint = childManifestFingerprint(params);
409932
+ const previous = this.applied.get(childId);
409933
+ if (previous !== void 0 && previous.incarnation === incarnation) {
409934
+ if (previous.fingerprint === fingerprint) {
409935
+ this.skipped += 1;
409936
+ this.sinceSample += 1;
409937
+ return false;
409938
+ }
409939
+ }
409940
+ this.applied.set(childId, { incarnation, fingerprint });
409941
+ return true;
409942
+ }
409943
+ /** Drop a child's record — its next register is a first register again. */
409944
+ forget(childId) {
409945
+ this.applied.delete(childId);
409946
+ }
409947
+ /** How many have been skipped since the last call. Reading RESETS it. */
409948
+ skippedSince() {
409949
+ const n = this.skipped;
409950
+ this.skipped = 0;
409951
+ return n;
409952
+ }
409953
+ /** True once every {@link CHILD_MANIFEST_SKIP_SAMPLE} skips. */
409954
+ sampleDue() {
409955
+ if (this.sinceSample < exports.CHILD_MANIFEST_SKIP_SAMPLE)
409956
+ return false;
409957
+ this.sinceSample = 0;
409958
+ return true;
409959
+ }
409960
+ };
409961
+ exports.ChildManifestGate = ChildManifestGate;
408239
409962
  function buildChildUdsManifest(nodeId, childId, caps) {
408240
409963
  const capsByAddon = /* @__PURE__ */ new Map();
408241
409964
  for (const cap of caps) {
@@ -409742,7 +411465,13 @@ var require_manual_boot = __commonJS({
409742
411465
  });
409743
411466
  },
409744
411467
  async listen(port, host) {
409745
- await fastify.listen({ port, host });
411468
+ await fastify.listen({
411469
+ port,
411470
+ host,
411471
+ // Dual-stack when binding `::`. Positional listen() drops this and
411472
+ // on macOS/BSD `IPV6_V6ONLY` defaults to 1 — IPv4 clients die.
411473
+ ipv6Only: host === "::" ? false : void 0
411474
+ });
409746
411475
  },
409747
411476
  close
409748
411477
  };
@@ -409807,6 +411536,7 @@ var require_main4 = __commonJS({
409807
411536
  var addon_upload_1 = require_addon_upload();
409808
411537
  var auth_whoami_1 = require_auth_whoami();
409809
411538
  var health_routes_1 = require_health_routes();
411539
+ var adaptive_probe_routes_1 = require_adaptive_probe_routes();
409810
411540
  var model_distributor_js_1 = require_model_distributor();
409811
411541
  var oauth2_routes_js_1 = require_oauth2_routes();
409812
411542
  var server_upload_1 = require_server_upload();
@@ -410044,6 +411774,7 @@ var require_main4 = __commonJS({
410044
411774
  verifyToken: (token2) => app.get(auth_service_1.AuthService).verifyToken(token2)
410045
411775
  });
410046
411776
  console.log(`[bootstrap] Health routes registered (hub v${hubVersion})`);
411777
+ (0, adaptive_probe_routes_1.registerAdaptiveProbeRoute)(fastify);
410047
411778
  } catch (err) {
410048
411779
  console.warn("[bootstrap] Failed to register health routes:", err);
410049
411780
  }
@@ -410281,12 +412012,12 @@ var require_main4 = __commonJS({
410281
412012
  } catch {
410282
412013
  return reply.status(401).send({ error: "invalid token" });
410283
412014
  }
410284
- const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec);
412015
+ const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec, { secure: request.protocol === "https" });
410285
412016
  reply.setCookie(c.name, c.value, c.options);
410286
412017
  return reply.send({ ok: true });
410287
412018
  });
410288
- fastify.delete("/api/auth/session", async (_request, reply) => {
410289
- const c = (0, session_cookie_js_1.clearSessionCookie)();
412019
+ fastify.delete("/api/auth/session", async (request, reply) => {
412020
+ const c = (0, session_cookie_js_1.clearSessionCookie)({ secure: request.protocol === "https" });
410290
412021
  reply.setCookie(c.name, c.value, c.options);
410291
412022
  return reply.send({ ok: true });
410292
412023
  });
@@ -410306,7 +412037,7 @@ var require_main4 = __commonJS({
410306
412037
  } catch {
410307
412038
  return reply.status(401).send({ error: "invalid token" });
410308
412039
  }
410309
- const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec);
412040
+ const c = (0, session_cookie_js_1.buildSessionCookie)(token2, ttlSec, { secure: request.protocol === "https" });
410310
412041
  reply.setCookie(c.name, c.value, c.options);
410311
412042
  return reply.redirect(next);
410312
412043
  });
@@ -410571,7 +412302,7 @@ var require_main4 = __commonJS({
410571
412302
  const url = request.url;
410572
412303
  if ((0, spa_static_1.isRetiredPublicPath)(url))
410573
412304
  return reply.callNotFound();
410574
- if (url.startsWith("/trpc") || url.startsWith("/api/") || url.startsWith("/agent") || url.startsWith("/health") || url.startsWith("/viewer")) {
412305
+ if (url.startsWith("/trpc") || url.startsWith("/api/") || url.startsWith("/agent") || url.startsWith("/health") || url.startsWith("/adaptive-probe") || url.startsWith("/viewer")) {
410575
412306
  return reply.callNotFound();
410576
412307
  }
410577
412308
  const { staticDir, indexPath } = adminUiState;
@@ -410661,7 +412392,16 @@ var require_main4 = __commonJS({
410661
412392
  }
410662
412393
  };
410663
412394
  try {
410664
- await app.listen(port, host);
412395
+ const listenHost = (0, system_1.allFamiliesListenHost)(host).host;
412396
+ try {
412397
+ await app.listen(port, listenHost);
412398
+ } catch (listenErr) {
412399
+ if (listenHost === "::" && host !== "::") {
412400
+ await app.listen(port, "0.0.0.0");
412401
+ } else {
412402
+ throw listenErr;
412403
+ }
412404
+ }
410665
412405
  } catch (listenErr) {
410666
412406
  if (listenErr !== null && typeof listenErr === "object" && "code" in listenErr && listenErr.code === "EADDRINUSE") {
410667
412407
  console.error(`[bootstrap] FATAL: Port ${port} is already in use. Stop the other process or change server.port in config.yaml.`);
@@ -410672,6 +412412,26 @@ var require_main4 = __commonJS({
410672
412412
  const logger = app.get(logging_service_1.LoggingService).createLogger("System");
410673
412413
  const protocol = tlsOptions ? "https" : "http";
410674
412414
  logger.info("CamStack server listening", { meta: { protocol, host, port, trpcRegistered } });
412415
+ (0, system_1.registerLanHttpHandler)({
412416
+ onRequest: (req, res) => {
412417
+ fastify.server.emit("request", req, res);
412418
+ },
412419
+ onUpgrade: (req, socket, head) => {
412420
+ fastify.server.emit("upgrade", req, socket, head);
412421
+ }
412422
+ });
412423
+ try {
412424
+ const lanHttp = await (0, system_1.bindPendingLanHttp)();
412425
+ if (lanHttp.listening) {
412426
+ logger.info("LAN HTTP listening", { meta: { port: lanHttp.port } });
412427
+ } else if (lanHttp.error) {
412428
+ logger.warn("LAN HTTP not bound", { meta: { error: lanHttp.error, port: lanHttp.port } });
412429
+ }
412430
+ } catch (err) {
412431
+ logger.warn("LAN HTTP bind failed", {
412432
+ meta: { error: err instanceof Error ? err.message : String(err) }
412433
+ });
412434
+ }
410675
412435
  void Promise.all([resolveAdminUi(), resolveViewerUi()]);
410676
412436
  const postBoot = app.get(post_boot_service_1.PostBootService);
410677
412437
  await postBoot.run({ port, host, dataPath, trpcRegistered, tlsCert });