camstack 1.2.39 → 1.2.41

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-C2_1HCpW.js
23635
- var require_dist_C2_1HCpW = __commonJS({
23636
- "../system/dist/dist-C2_1HCpW.js"(exports) {
23634
+ // ../system/dist/dist-CIDgcxPk.js
23635
+ var require_dist_CIDgcxPk = __commonJS({
23636
+ "../system/dist/dist-CIDgcxPk.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_C2_1HCpW = __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_C2_1HCpW = __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_C2_1HCpW = __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
  }
@@ -26318,6 +26328,12 @@ var require_dist_C2_1HCpW = __commonJS({
26318
26328
  */
26319
26329
  resolution: zod.z.number().int().positive().optional()
26320
26330
  });
26331
+ var ModelProviderIdSchema = zod.z.enum([
26332
+ "camstack",
26333
+ "frigate",
26334
+ "scrypted",
26335
+ "custom"
26336
+ ]);
26321
26337
  var ModelCatalogEntrySchema = zod.z.object({
26322
26338
  id: zod.z.string(),
26323
26339
  name: zod.z.string(),
@@ -26415,6 +26431,12 @@ var require_dist_C2_1HCpW = __commonJS({
26415
26431
  */
26416
26432
  group: ModelVariantGroupSchema.optional(),
26417
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
+ /**
26418
26440
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
26419
26441
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
26420
26442
  * labels already ARE the CamStack macros (Scrypted identity map).
@@ -30290,6 +30312,21 @@ var require_dist_C2_1HCpW = __commonJS({
30290
30312
  features: zod.z.array(zod.z.string()),
30291
30313
  producesTrackedEvents: zod.z.boolean().optional()
30292
30314
  });
30315
+ var LinkedDevicesForDeviceSchema = zod.z.object({
30316
+ deviceId: zod.z.number(),
30317
+ mode: LinkedDevicesModeSchema,
30318
+ devices: zod.z.array(LinkedDeviceSchema)
30319
+ });
30320
+ var DeviceBindingsForDeviceSchema = zod.z.object({
30321
+ deviceId: zod.z.number(),
30322
+ entries: zod.z.array(zod.z.object({
30323
+ capName: zod.z.string(),
30324
+ kind: zod.z.enum(["native", "wrapped"]),
30325
+ providerAddonId: zod.z.string(),
30326
+ providerNodeId: zod.z.string(),
30327
+ nativeAddonId: zod.z.string()
30328
+ }))
30329
+ });
30293
30330
  var SavedDeviceRowSchema = zod.z.object({
30294
30331
  /** Numeric id reserved at allocateDeviceId time. */
30295
30332
  id: zod.z.number(),
@@ -30647,7 +30684,21 @@ var require_dist_C2_1HCpW = __commonJS({
30647
30684
  projection: zod.z.enum(["full", "slim"]).optional(),
30648
30685
  /** Return only camera devices. Filtering server-side instead of
30649
30686
  * shipping 293 rows to find 12. */
30650
- isCamera: zod.z.boolean().optional()
30687
+ isCamera: zod.z.boolean().optional(),
30688
+ /**
30689
+ * Return only these device ids. For the caller that already KNOWS the
30690
+ * handful it wants and needs a field the id-bearing answer does not
30691
+ * carry — the viewer's linked-devices panel joins `type` and `online`
30692
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
30693
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
30694
+ * refetches on the reconcile interval, on a phone.
30695
+ *
30696
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
30697
+ * keys rather than rejecting them (verified against the live hub
30698
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
30699
+ * it answers today and the caller filters as it already does.
30700
+ */
30701
+ deviceIds: zod.z.array(zod.z.number()).optional()
30651
30702
  }), zod.z.array(DeviceInfoSchema)),
30652
30703
  /** Get a single device by numeric deviceId. */
30653
30704
  getDevice: method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
@@ -30666,6 +30717,23 @@ var require_dist_C2_1HCpW = __commonJS({
30666
30717
  mode: LinkedDevicesModeSchema,
30667
30718
  devices: zod.z.array(LinkedDeviceSchema)
30668
30719
  })),
30720
+ /**
30721
+ * `getLinkedDevices` for MANY cameras, in one call.
30722
+ *
30723
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
30724
+ * needs the whole fleet as candidates (children ∪ same-location), so the
30725
+ * single-device path runs a full `listAll` per call. Asked per camera that
30726
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
30727
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
30728
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
30729
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
30730
+ * camera.
30731
+ *
30732
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
30733
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
30734
+ * are missing, or that any are.
30735
+ */
30736
+ getLinkedDevicesBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(LinkedDevicesForDeviceSchema)),
30669
30737
  /** Get stream sources for a camera device. */
30670
30738
  getStreamSources: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(StreamSourceEntrySchema$1)),
30671
30739
  /** Get config entries (key + value + description) for a device. */
@@ -30723,16 +30791,22 @@ var require_dist_C2_1HCpW = __commonJS({
30723
30791
  * currently-active provider (native or wrapper) + the underlying native
30724
30792
  * addon id, so consumers can decide routing without re-running discovery.
30725
30793
  */
30726
- getBindings: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
30727
- deviceId: zod.z.number(),
30728
- entries: zod.z.array(zod.z.object({
30729
- capName: zod.z.string(),
30730
- kind: zod.z.enum(["native", "wrapped"]),
30731
- providerAddonId: zod.z.string(),
30732
- providerNodeId: zod.z.string(),
30733
- nativeAddonId: zod.z.string()
30734
- }))
30735
- })),
30794
+ getBindings: method(zod.z.object({ deviceId: zod.z.number() }), DeviceBindingsForDeviceSchema),
30795
+ /**
30796
+ * `getBindings` for a NAMED set of devices, in one call.
30797
+ *
30798
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
30799
+ * was nothing, so a caller that needs seventy-five either pays
30800
+ * seventy-five round-trips or drags the whole fleet across. Measured on
30801
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
30802
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
30803
+ * "these seventy-five".
30804
+ *
30805
+ * Same resolver, same routing rules, same per-device shape as
30806
+ * `getBindings`; ids are deduped and a device with no bindings answers
30807
+ * `entries: []` rather than dropping out.
30808
+ */
30809
+ getBindingsBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(DeviceBindingsForDeviceSchema)),
30736
30810
  /**
30737
30811
  * Return the binding map for every device known to the hub. Used by
30738
30812
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -30741,16 +30815,7 @@ var require_dist_C2_1HCpW = __commonJS({
30741
30815
  * device add/remove) — clients invalidate via the
30742
30816
  * `capability.binding-changed` event.
30743
30817
  */
30744
- getAllBindings: method(zod.z.object({}), zod.z.array(zod.z.object({
30745
- deviceId: zod.z.number(),
30746
- entries: zod.z.array(zod.z.object({
30747
- capName: zod.z.string(),
30748
- kind: zod.z.enum(["native", "wrapped"]),
30749
- providerAddonId: zod.z.string(),
30750
- providerNodeId: zod.z.string(),
30751
- nativeAddonId: zod.z.string()
30752
- }))
30753
- }))),
30818
+ getAllBindings: method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
30754
30819
  /**
30755
30820
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
30756
30821
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -33183,14 +33248,22 @@ var require_dist_C2_1HCpW = __commonJS({
33183
33248
  sustainSeconds: zod.z.number().int().min(0).max(3600).default(15)
33184
33249
  });
33185
33250
  var NcAudioConditionSchema = zod.z.object({
33186
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
33251
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
33187
33252
  labels: zod.z.array(zod.z.string().min(1)).min(1).optional(),
33188
33253
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
33189
33254
  dbThreshold: zod.z.number().min(-96).max(0).optional(),
33190
33255
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
33191
33256
  hitPercent: zod.z.number().int().min(1).max(100).default(60),
33192
33257
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
33193
- samplingSeconds: zod.z.number().int().min(1).max(300).default(10)
33258
+ samplingSeconds: zod.z.number().int().min(1).max(300).default(10),
33259
+ /**
33260
+ * LABEL MODE: how many labelled frames must land inside
33261
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
33262
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
33263
+ */
33264
+ confirmHits: zod.z.number().int().min(1).max(20).optional(),
33265
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
33266
+ confirmWindowSec: zod.z.number().int().min(1).max(60).optional()
33194
33267
  });
33195
33268
  var NcCrossingSchema = zod.z.enum([
33196
33269
  "enter",
@@ -35008,6 +35081,46 @@ var require_dist_C2_1HCpW = __commonJS({
35008
35081
  /** Cursor for the next page, or null when this page is the last. */
35009
35082
  nextCursor: zod.z.string().nullable()
35010
35083
  });
35084
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
35085
+ var LIST_GROUPS_MAX_LIMIT = 100;
35086
+ var AnalyticsGroupRecordSchema = zod.z.object({
35087
+ id: zod.z.string(),
35088
+ deviceId: zod.z.number().int(),
35089
+ openedAt: zod.z.number().int(),
35090
+ closedAt: zod.z.number().int(),
35091
+ timestamp: zod.z.number().int(),
35092
+ memberCount: zod.z.number().int(),
35093
+ memberTrackIds: zod.z.array(zod.z.string()).readonly(),
35094
+ className: zod.z.string(),
35095
+ classes: zod.z.array(zod.z.string()).readonly(),
35096
+ /** Relative event-media path, or null when the group has no picture yet. */
35097
+ mediaUrl: zod.z.string().nullable(),
35098
+ singleton: zod.z.boolean()
35099
+ });
35100
+ var AnalyticsGroupMemberSchema = zod.z.object({
35101
+ trackId: zod.z.string(),
35102
+ deviceId: zod.z.number().int(),
35103
+ className: zod.z.string(),
35104
+ firstSeen: zod.z.number().int(),
35105
+ lastSeen: zod.z.number().int(),
35106
+ mediaUrl: zod.z.string().nullable()
35107
+ });
35108
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
35109
+ var ListGroupsQueryInput = zod.z.object({
35110
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
35111
+ deviceIds: zod.z.array(zod.z.number()),
35112
+ /** Window lower bound on `closedAt` (inclusive). */
35113
+ since: zod.z.number().optional(),
35114
+ /** Window upper bound on `openedAt` (inclusive). */
35115
+ until: zod.z.number().optional(),
35116
+ limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
35117
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
35118
+ cursor: zod.z.string().optional()
35119
+ });
35120
+ var ListGroupsPageSchema = zod.z.object({
35121
+ groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
35122
+ nextCursor: zod.z.string().nullable()
35123
+ });
35011
35124
  var KeyEventQueryInput = zod.z.object({
35012
35125
  deviceId: zod.z.number(),
35013
35126
  /** Window lower bound (track firstSeen ≥ since). */
@@ -35083,7 +35196,9 @@ var require_dist_C2_1HCpW = __commonJS({
35083
35196
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
35084
35197
  plates: zod.z.number().int(),
35085
35198
  /** Per-track CLIP search vectors removed (best-effort). */
35086
- embeddings: zod.z.number().int()
35199
+ embeddings: zod.z.number().int(),
35200
+ /** Group membership + group rows removed with their last member (best-effort). */
35201
+ groups: zod.z.number().int()
35087
35202
  });
35088
35203
  var DiskReconcileCountsSchema = zod.z.object({
35089
35204
  mediaDropped: zod.z.number().int(),
@@ -35225,6 +35340,16 @@ var require_dist_C2_1HCpW = __commonJS({
35225
35340
  * are not included (same contract as `listTracks`).
35226
35341
  */
35227
35342
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
35343
+ /**
35344
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
35345
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
35346
+ * one session; `getGroup` is the detail with members.
35347
+ */
35348
+ listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
35349
+ getGroup: method(zod.z.object({
35350
+ deviceId: zod.z.number(),
35351
+ groupId: zod.z.string().min(1)
35352
+ }), AnalyticsGroupDetailSchema.nullable()),
35228
35353
  clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
35229
35354
  kind: "mutation",
35230
35355
  auth: "admin"
@@ -35906,7 +36031,8 @@ var require_dist_C2_1HCpW = __commonJS({
35906
36031
  sizeMB: zod.z.number()
35907
36032
  })),
35908
36033
  group: ModelVariantGroupSchema.optional(),
35909
- legacy: zod.z.boolean().optional()
36034
+ legacy: zod.z.boolean().optional(),
36035
+ provider: ModelProviderIdSchema.optional()
35910
36036
  });
35911
36037
  var ConfigFieldBridge = zod.z.custom();
35912
36038
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -44215,7 +44341,12 @@ var require_dist_C2_1HCpW = __commonJS({
44215
44341
  plateBbox: BoundingBoxSchema.optional(),
44216
44342
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
44217
44343
  keyFrameMediaKey: zod.z.string().optional(),
44218
- base64: zod.z.string().optional()
44344
+ base64: zod.z.string().optional(),
44345
+ /**
44346
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
44347
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
44348
+ */
44349
+ cropUrl: zod.z.string().optional()
44219
44350
  });
44220
44351
  var MediaFileLiteSchema = zod.z.object({
44221
44352
  key: zod.z.string(),
@@ -49104,6 +49235,12 @@ var require_dist_C2_1HCpW = __commonJS({
49104
49235
  addonId: null,
49105
49236
  access: "view"
49106
49237
  },
49238
+ "deviceManager.getBindingsBatch": {
49239
+ capName: "device-manager",
49240
+ capScope: "system",
49241
+ addonId: null,
49242
+ access: "view"
49243
+ },
49107
49244
  "deviceManager.getChildren": {
49108
49245
  capName: "device-manager",
49109
49246
  capScope: "system",
@@ -49164,6 +49301,12 @@ var require_dist_C2_1HCpW = __commonJS({
49164
49301
  addonId: null,
49165
49302
  access: "view"
49166
49303
  },
49304
+ "deviceManager.getLinkedDevicesBatch": {
49305
+ capName: "device-manager",
49306
+ capScope: "system",
49307
+ addonId: null,
49308
+ access: "view"
49309
+ },
49167
49310
  "deviceManager.getRoleDisplayDefaults": {
49168
49311
  capName: "device-manager",
49169
49312
  capScope: "system",
@@ -50934,6 +51077,12 @@ var require_dist_C2_1HCpW = __commonJS({
50934
51077
  addonId: null,
50935
51078
  access: "view"
50936
51079
  },
51080
+ "pipelineAnalytics.getGroup": {
51081
+ capName: "pipeline-analytics",
51082
+ capScope: "device",
51083
+ addonId: null,
51084
+ access: "view"
51085
+ },
50937
51086
  "pipelineAnalytics.getKeyEvents": {
50938
51087
  capName: "pipeline-analytics",
50939
51088
  capScope: "device",
@@ -51018,6 +51167,12 @@ var require_dist_C2_1HCpW = __commonJS({
51018
51167
  addonId: null,
51019
51168
  access: "view"
51020
51169
  },
51170
+ "pipelineAnalytics.listGroups": {
51171
+ capName: "pipeline-analytics",
51172
+ capScope: "device",
51173
+ addonId: null,
51174
+ access: "view"
51175
+ },
51021
51176
  "pipelineAnalytics.listOpsLog": {
51022
51177
  capName: "pipeline-analytics",
51023
51178
  capScope: "device",
@@ -53799,6 +53954,11 @@ var require_dist_C2_1HCpW = __commonJS({
53799
53954
  form: "single",
53800
53955
  optional: false
53801
53956
  }],
53957
+ "deviceManager.getBindingsBatch": [{
53958
+ name: "deviceIds",
53959
+ form: "array",
53960
+ optional: false
53961
+ }],
53802
53962
  "deviceManager.getChildren": [{
53803
53963
  name: "parentDeviceId",
53804
53964
  form: "single",
@@ -53844,6 +54004,11 @@ var require_dist_C2_1HCpW = __commonJS({
53844
54004
  form: "single",
53845
54005
  optional: false
53846
54006
  }],
54007
+ "deviceManager.getLinkedDevicesBatch": [{
54008
+ name: "deviceIds",
54009
+ form: "array",
54010
+ optional: false
54011
+ }],
53847
54012
  "deviceManager.getSettingsSchema": [{
53848
54013
  name: "deviceId",
53849
54014
  form: "single",
@@ -53864,6 +54029,11 @@ var require_dist_C2_1HCpW = __commonJS({
53864
54029
  form: "single",
53865
54030
  optional: false
53866
54031
  }],
54032
+ "deviceManager.listAll": [{
54033
+ name: "deviceIds",
54034
+ form: "array",
54035
+ optional: true
54036
+ }],
53867
54037
  "deviceManager.loadConfig": [{
53868
54038
  name: "deviceId",
53869
54039
  form: "single",
@@ -54437,6 +54607,11 @@ var require_dist_C2_1HCpW = __commonJS({
54437
54607
  form: "single",
54438
54608
  optional: false
54439
54609
  }],
54610
+ "pipelineAnalytics.getGroup": [{
54611
+ name: "deviceId",
54612
+ form: "single",
54613
+ optional: false
54614
+ }],
54440
54615
  "pipelineAnalytics.getKeyEvents": [{
54441
54616
  name: "deviceId",
54442
54617
  form: "single",
@@ -54492,6 +54667,11 @@ var require_dist_C2_1HCpW = __commonJS({
54492
54667
  form: "array",
54493
54668
  optional: false
54494
54669
  }],
54670
+ "pipelineAnalytics.listGroups": [{
54671
+ name: "deviceIds",
54672
+ form: "array",
54673
+ optional: false
54674
+ }],
54495
54675
  "pipelineAnalytics.listOpsLog": [{
54496
54676
  name: "deviceId",
54497
54677
  form: "single",
@@ -56510,7 +56690,7 @@ var require_alerts_addon = __commonJS({
56510
56690
  [Symbol.toStringTag]: { value: "Module" }
56511
56691
  });
56512
56692
  require_chunk_Cek0wNdY();
56513
- var require_dist10 = require_dist_C2_1HCpW();
56693
+ var require_dist10 = require_dist_CIDgcxPk();
56514
56694
  function selectExpired(alerts, cutoffMs) {
56515
56695
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
56516
56696
  }
@@ -57329,7 +57509,7 @@ var require_console_logging = __commonJS({
57329
57509
  [Symbol.toStringTag]: { value: "Module" }
57330
57510
  });
57331
57511
  require_chunk_Cek0wNdY();
57332
- var require_dist10 = require_dist_C2_1HCpW();
57512
+ var require_dist10 = require_dist_CIDgcxPk();
57333
57513
  var require_formatter = require_formatter_DqAKDlvN();
57334
57514
  var LEVEL_RANK = {
57335
57515
  debug: 0,
@@ -57423,7 +57603,7 @@ var require_core_blocks_addon = __commonJS({
57423
57603
  "use strict";
57424
57604
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
57425
57605
  var require_chunk = require_chunk_Cek0wNdY();
57426
- var require_dist10 = require_dist_C2_1HCpW();
57606
+ var require_dist10 = require_dist_CIDgcxPk();
57427
57607
  var node_crypto = __require("crypto");
57428
57608
  var node_fs_promises = __require("fs/promises");
57429
57609
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -58320,11 +58500,11 @@ var require_core_blocks = __commonJS({
58320
58500
  }
58321
58501
  });
58322
58502
 
58323
- // ../system/dist/retired-settings-keys-DHRXLMPn.js
58324
- var require_retired_settings_keys_DHRXLMPn = __commonJS({
58325
- "../system/dist/retired-settings-keys-DHRXLMPn.js"(exports) {
58503
+ // ../system/dist/retired-settings-keys-D7c0n9jO.js
58504
+ var require_retired_settings_keys_D7c0n9jO = __commonJS({
58505
+ "../system/dist/retired-settings-keys-D7c0n9jO.js"(exports) {
58326
58506
  "use strict";
58327
- var require_dist10 = require_dist_C2_1HCpW();
58507
+ var require_dist10 = require_dist_CIDgcxPk();
58328
58508
  function settingsStoreIsAuthoritativeHere(env) {
58329
58509
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
58330
58510
  return raw === "" || raw === "hub";
@@ -60367,8 +60547,8 @@ var require_device_manager_addon = __commonJS({
60367
60547
  [Symbol.toStringTag]: { value: "Module" }
60368
60548
  });
60369
60549
  require_chunk_Cek0wNdY();
60370
- var require_dist10 = require_dist_C2_1HCpW();
60371
- var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
60550
+ var require_dist10 = require_dist_CIDgcxPk();
60551
+ var require_retired_settings_keys = require_retired_settings_keys_D7c0n9jO();
60372
60552
  var node_crypto = __require("crypto");
60373
60553
  var _camstack_types_node = require_node();
60374
60554
  var JOB_HISTORY = 20;
@@ -60945,6 +61125,11 @@ var require_device_manager_addon = __commonJS({
60945
61125
  entries
60946
61126
  };
60947
61127
  }
61128
+ async function getBindingsBatch(deps, input) {
61129
+ const out = [];
61130
+ for (const deviceId of new Set(input.deviceIds)) out.push(await getBindings(deps, { deviceId }));
61131
+ return out;
61132
+ }
60948
61133
  async function getAllBindings(deps) {
60949
61134
  const ids = /* @__PURE__ */ new Set();
60950
61135
  for (const row of await deps.rows.listAll()) ids.add(row.meta.id);
@@ -61390,6 +61575,7 @@ var require_device_manager_addon = __commonJS({
61390
61575
  const { addonId } = input;
61391
61576
  const slim = input.projection === "slim";
61392
61577
  const camerasOnly = input.isCamera === true;
61578
+ const idFilter = input.deviceIds === void 0 ? null : new Set(input.deviceIds);
61393
61579
  const results = [];
61394
61580
  const seen = /* @__PURE__ */ new Set();
61395
61581
  const fleet = addonId ? await pctx.metaStore.rows.listByAddon(addonId) : await pctx.metaStore.rows.listAll();
@@ -61405,6 +61591,7 @@ var require_device_manager_addon = __commonJS({
61405
61591
  const row = rowById.get(device.id);
61406
61592
  const info = toDeviceInfo(aid, device, row?.metadata ?? null, row?.meta ?? null);
61407
61593
  seen.add(key);
61594
+ if (idFilter !== null && !idFilter.has(device.id)) continue;
61408
61595
  if (camerasOnly && !info.isCamera) continue;
61409
61596
  results.push(slim ? {
61410
61597
  ...info,
@@ -61418,6 +61605,7 @@ var require_device_manager_addon = __commonJS({
61418
61605
  const aid = m.addonId;
61419
61606
  const stableId = m.stableId;
61420
61607
  if (seen.has(String(m.id))) continue;
61608
+ if (idFilter !== null && !idFilter.has(m.id)) continue;
61421
61609
  const persistedType = m.type;
61422
61610
  if (camerasOnly && persistedType !== require_dist10.DeviceType.Camera) continue;
61423
61611
  const persistedConfig = slim ? {} : await pctx.settings.readDeviceStore(m.id);
@@ -61916,11 +62104,8 @@ var require_device_manager_addon = __commonJS({
61916
62104
  }
61917
62105
  return linkedIds.filter((id) => picked.has(id));
61918
62106
  }
61919
- async function getLinkedDevices(pctx, input) {
61920
- const { deviceId } = input;
61921
- const [all, blob] = await Promise.all([listAll(pctx, {}), pctx.settings.readDeviceStore(deviceId)]);
62107
+ function resolveFor(deviceId, all, byId, blob) {
61922
62108
  const config = parseLinkedDevicesConfig(blob);
61923
- const byId = new Map(all.map((d) => [d.id, d]));
61924
62109
  const ids = resolveLinkedDeviceIds({
61925
62110
  selfId: deviceId,
61926
62111
  selfLocation: byId.get(deviceId)?.location ?? null,
@@ -61945,6 +62130,27 @@ var require_device_manager_addon = __commonJS({
61945
62130
  devices
61946
62131
  };
61947
62132
  }
62133
+ async function getLinkedDevices(pctx, input) {
62134
+ const { deviceId } = input;
62135
+ const [all, blob] = await Promise.all([listAll(pctx, {}), pctx.settings.readDeviceStore(deviceId)]);
62136
+ return resolveFor(deviceId, all, new Map(all.map((d) => [d.id, d])), blob);
62137
+ }
62138
+ async function getLinkedDevicesBatch(pctx, input) {
62139
+ const deviceIds = [...new Set(input.deviceIds)];
62140
+ if (deviceIds.length === 0) return [];
62141
+ const [all, blobs] = await Promise.all([listAll(pctx, {}), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
62142
+ pctx.host.ctx.logger.warn("getLinkedDevicesBatch: settings read failed \u2014 children only", {
62143
+ tags: { deviceId: id },
62144
+ meta: { error: err instanceof Error ? err.message : String(err) }
62145
+ });
62146
+ return {};
62147
+ })))]);
62148
+ const byId = new Map(all.map((d) => [d.id, d]));
62149
+ return deviceIds.map((deviceId, index) => ({
62150
+ deviceId,
62151
+ ...resolveFor(deviceId, all, byId, blobs[index] ?? {})
62152
+ }));
62153
+ }
61948
62154
  async function buildLinkedDevicesContribution(pctx, deviceId) {
61949
62155
  const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
61950
62156
  if (!persisted || persisted.meta.type !== require_dist10.DeviceType.Camera) return null;
@@ -64386,6 +64592,9 @@ var require_device_manager_addon = __commonJS({
64386
64592
  async getBindings(input) {
64387
64593
  return getBindings(this.bindingsDeps, input);
64388
64594
  }
64595
+ async getBindingsBatch(input) {
64596
+ return getBindingsBatch(this.bindingsDeps, input);
64597
+ }
64389
64598
  async getAllBindings() {
64390
64599
  return getAllBindings(this.bindingsDeps);
64391
64600
  }
@@ -64497,6 +64706,7 @@ var require_device_manager_addon = __commonJS({
64497
64706
  getDevice: (input) => getDevice(pctx, input),
64498
64707
  getChildren: (input) => getChildren(pctx, input),
64499
64708
  getLinkedDevices: (input) => getLinkedDevices(pctx, input),
64709
+ getLinkedDevicesBatch: (input) => getLinkedDevicesBatch(pctx, input),
64500
64710
  getDeviceSettingsContribution: (input) => buildLinkedDevicesContribution(pctx, input.deviceId),
64501
64711
  getDeviceLiveContribution: async () => null,
64502
64712
  applyDeviceSettingsPatch: (input) => applyLinkedDevicesPatch(pctx, input.deviceId, input.patch),
@@ -64575,6 +64785,7 @@ var require_device_manager_addon = __commonJS({
64575
64785
  entries: result.entries
64576
64786
  };
64577
64787
  },
64788
+ getBindingsBatch: (input) => this.getBindingsBatch({ deviceIds: input.deviceIds }),
64578
64789
  getAllBindings: async () => {
64579
64790
  return this.getAllBindings();
64580
64791
  },
@@ -64695,7 +64906,7 @@ var require_hub_forwarder = __commonJS({
64695
64906
  [Symbol.toStringTag]: { value: "Module" }
64696
64907
  });
64697
64908
  require_chunk_Cek0wNdY();
64698
- var require_dist10 = require_dist_C2_1HCpW();
64909
+ var require_dist10 = require_dist_CIDgcxPk();
64699
64910
  var require_formatter = require_formatter_DqAKDlvN();
64700
64911
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
64701
64912
  var HubForwarderDestination = class {
@@ -64832,7 +65043,7 @@ var require_liveness_monitor_addon = __commonJS({
64832
65043
  "use strict";
64833
65044
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
64834
65045
  require_chunk_Cek0wNdY();
64835
- var require_dist10 = require_dist_C2_1HCpW();
65046
+ var require_dist10 = require_dist_CIDgcxPk();
64836
65047
  var NO_DEVICES = "liveness:no-devices";
64837
65048
  var ALL_OFFLINE = "liveness:all-devices-offline";
64838
65049
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -65022,7 +65233,7 @@ var require_local_auth_addon = __commonJS({
65022
65233
  [Symbol.toStringTag]: { value: "Module" }
65023
65234
  });
65024
65235
  var require_chunk = require_chunk_Cek0wNdY();
65025
- var require_dist10 = require_dist_C2_1HCpW();
65236
+ var require_dist10 = require_dist_CIDgcxPk();
65026
65237
  var node_crypto = __require("crypto");
65027
65238
  node_crypto = require_chunk.__toESM(node_crypto);
65028
65239
  var crypto$1 = __require("crypto");
@@ -72706,7 +72917,7 @@ var require_loki_logging = __commonJS({
72706
72917
  [Symbol.toStringTag]: { value: "Module" }
72707
72918
  });
72708
72919
  require_chunk_Cek0wNdY();
72709
- var require_dist10 = require_dist_C2_1HCpW();
72920
+ var require_dist10 = require_dist_CIDgcxPk();
72710
72921
  function sanitizeLabelName(raw) {
72711
72922
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
72712
72923
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -73271,7 +73482,7 @@ var require_native_metrics_addon = __commonJS({
73271
73482
  [Symbol.toStringTag]: { value: "Module" }
73272
73483
  });
73273
73484
  var require_chunk = require_chunk_Cek0wNdY();
73274
- var require_dist10 = require_dist_C2_1HCpW();
73485
+ var require_dist10 = require_dist_CIDgcxPk();
73275
73486
  var node_child_process = __require("child_process");
73276
73487
  var node_util = __require("util");
73277
73488
  var node_os = __require("os");
@@ -74213,7 +74424,7 @@ var require_filesystem_storage_addon = __commonJS({
74213
74424
  [Symbol.toStringTag]: { value: "Module" }
74214
74425
  });
74215
74426
  var require_chunk = require_chunk_Cek0wNdY();
74216
- var require_dist10 = require_dist_C2_1HCpW();
74427
+ var require_dist10 = require_dist_CIDgcxPk();
74217
74428
  var node_crypto = __require("crypto");
74218
74429
  var node_fs_promises = __require("fs/promises");
74219
74430
  var node_path = __require("path");
@@ -75329,8 +75540,8 @@ var require_sqlite_settings_addon = __commonJS({
75329
75540
  [Symbol.toStringTag]: { value: "Module" }
75330
75541
  });
75331
75542
  var require_chunk = require_chunk_Cek0wNdY();
75332
- var require_dist10 = require_dist_C2_1HCpW();
75333
- var require_retired_settings_keys = require_retired_settings_keys_DHRXLMPn();
75543
+ var require_dist10 = require_dist_CIDgcxPk();
75544
+ var require_retired_settings_keys = require_retired_settings_keys_D7c0n9jO();
75334
75545
  var node_crypto = __require("crypto");
75335
75546
  var node_fs = __require("fs");
75336
75547
  var node_module = __require("module");
@@ -76674,6 +76885,17 @@ var require_sqlite_settings_addon = __commonJS({
76674
76885
  constructor() {
76675
76886
  super({});
76676
76887
  }
76888
+ /**
76889
+ * The engine behind `settings-store` cannot read that door during
76890
+ * `initialize()`. `BaseAddon` always `await`s `resolveConfig()` first;
76891
+ * on an isolated sqlite that round-trip is a UDS call to the parent,
76892
+ * and the parent is waiting for THIS child's post-init handshake before
76893
+ * it builds the door (D233). Live 1.2.152: 30 s hang, timeout, every
76894
+ * in-process builtin skipped, then this addon finished one second later.
76895
+ * Constructor defaults (`{}`) are the whole config this addon has.
76896
+ */
76897
+ async resolveConfig() {
76898
+ }
76677
76899
  async onInitialize() {
76678
76900
  const addonId = require_dist10.bareAddonId(this.ctx.id);
76679
76901
  const path = await import("path");
@@ -76789,6 +77011,7 @@ var require_sqlite_settings_addon = __commonJS({
76789
77011
  exports.WAL_IDLE_QUIET_MS = WAL_IDLE_QUIET_MS;
76790
77012
  exports.WAL_MAINTENANCE_INTERVAL_MS = WAL_MAINTENANCE_INTERVAL_MS;
76791
77013
  exports.WalMaintenance = WalMaintenance;
77014
+ exports.prefixRange = prefixRange;
76792
77015
  }
76793
77016
  });
76794
77017
 
@@ -76874,7 +77097,7 @@ var require_storage_orchestrator_addon = __commonJS({
76874
77097
  [Symbol.toStringTag]: { value: "Module" }
76875
77098
  });
76876
77099
  var require_chunk = require_chunk_Cek0wNdY();
76877
- var require_dist10 = require_dist_C2_1HCpW();
77100
+ var require_dist10 = require_dist_CIDgcxPk();
76878
77101
  var node_crypto = __require("crypto");
76879
77102
  var node_fs_promises = __require("fs/promises");
76880
77103
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -78753,7 +78976,7 @@ var require_system_config_addon = __commonJS({
78753
78976
  [Symbol.toStringTag]: { value: "Module" }
78754
78977
  });
78755
78978
  require_chunk_Cek0wNdY();
78756
- var require_dist10 = require_dist_C2_1HCpW();
78979
+ var require_dist10 = require_dist_CIDgcxPk();
78757
78980
  var SECTION_TITLES = {
78758
78981
  server: "Server",
78759
78982
  auth: "Authentication"
@@ -96814,7 +97037,7 @@ var require_winston_logging = __commonJS({
96814
97037
  [Symbol.toStringTag]: { value: "Module" }
96815
97038
  });
96816
97039
  var require_chunk = require_chunk_Cek0wNdY();
96817
- var require_dist10 = require_dist_C2_1HCpW();
97040
+ var require_dist10 = require_dist_CIDgcxPk();
96818
97041
  var require_formatter = require_formatter_DqAKDlvN();
96819
97042
  var node_path = __require("path");
96820
97043
  node_path = require_chunk.__toESM(node_path);
@@ -98011,9 +98234,9 @@ var require_event_category_EY0GNjV9 = __commonJS({
98011
98234
  }
98012
98235
  });
98013
98236
 
98014
- // ../types/dist/sleep-C2XhJhkd.js
98015
- var require_sleep_C2XhJhkd = __commonJS({
98016
- "../types/dist/sleep-C2XhJhkd.js"(exports) {
98237
+ // ../types/dist/sleep-CUuoW-kk.js
98238
+ var require_sleep_CUuoW_kk = __commonJS({
98239
+ "../types/dist/sleep-CUuoW-kk.js"(exports) {
98017
98240
  "use strict";
98018
98241
  var require_event_category = require_event_category_EY0GNjV9();
98019
98242
  var zod = require_zod();
@@ -98384,6 +98607,13 @@ var require_sleep_C2XhJhkd = __commonJS({
98384
98607
  _readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
98385
98608
  /** Capability names this addon registered at init — used to emit matching `down` events on shutdown. */
98386
98609
  _registeredCapNames = [];
98610
+ /**
98611
+ * True only after `readAddonStore` actually answered. Constructor
98612
+ * defaults look like stored config when the store is down — a forked
98613
+ * addon that auto-starts from those defaults (cloudflare-tunnel quick
98614
+ * mode, 2026-08-25) is not "the operator chose this".
98615
+ */
98616
+ settingsStoreReady = false;
98387
98617
  /** Default config values. Provided via constructor. */
98388
98618
  defaults;
98389
98619
  constructor(defaults) {
@@ -98789,7 +99019,9 @@ var require_sleep_C2XhJhkd = __commonJS({
98789
99019
  ];
98790
99020
  let lastErr;
98791
99021
  for (let attempt = 0; attempt <= delaysMs.length; attempt++) try {
98792
- return await settings.readAddonStore() ?? {};
99022
+ const stored = await settings.readAddonStore() ?? {};
99023
+ this.settingsStoreReady = true;
99024
+ return stored;
98793
99025
  } catch (err) {
98794
99026
  lastErr = err;
98795
99027
  const msg = err instanceof Error ? err.message : String(err);
@@ -98797,6 +99029,7 @@ var require_sleep_C2XhJhkd = __commonJS({
98797
99029
  if (attempt === delaysMs.length) break;
98798
99030
  await new Promise((r) => setTimeout(r, delaysMs[attempt]));
98799
99031
  }
99032
+ this.settingsStoreReady = false;
98800
99033
  this._ctx?.logger?.warn?.("readAddonStore: settings-store unavailable after retries \u2014 using defaults", { meta: { error: lastErr instanceof Error ? lastErr.message : String(lastErr) } });
98801
99034
  return {};
98802
99035
  }
@@ -100055,6 +100288,73 @@ var require_sleep_C2XhJhkd = __commonJS({
100055
100288
  }
100056
100289
  };
100057
100290
  }
100291
+ function createEventBusSliceSource(deps) {
100292
+ const { eventBus, api } = deps;
100293
+ const cache2 = /* @__PURE__ */ new Map();
100294
+ const listeners = /* @__PURE__ */ new Map();
100295
+ let offBus = null;
100296
+ const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
100297
+ const fanOut = (deviceId, capName, slice) => {
100298
+ const k = keyOf(deviceId, capName);
100299
+ cache2.set(k, slice);
100300
+ const set = listeners.get(k);
100301
+ if (!set) return;
100302
+ for (const cb of set) try {
100303
+ cb(slice);
100304
+ } catch {
100305
+ }
100306
+ };
100307
+ const ensureBridge = () => {
100308
+ if (offBus) return;
100309
+ offBus = eventBus.subscribe({ category: DEVICE_STATE_EVENT_CATEGORY }, (event2) => {
100310
+ const data = event2.data;
100311
+ if (typeof data !== "object" || data === null) return;
100312
+ const deviceId = Reflect.get(data, "deviceId");
100313
+ const capName = Reflect.get(data, "capName");
100314
+ if (typeof deviceId !== "number" || typeof capName !== "string") return;
100315
+ fanOut(deviceId, capName, Reflect.get(data, "slice"));
100316
+ });
100317
+ };
100318
+ const closeBridgeIfIdle = () => {
100319
+ if (offBus === null) return;
100320
+ if (listeners.size > 0) return;
100321
+ offBus();
100322
+ offBus = null;
100323
+ };
100324
+ return {
100325
+ read(deviceId, capName) {
100326
+ return cache2.get(keyOf(deviceId, capName));
100327
+ },
100328
+ async refresh(deviceId, capName) {
100329
+ fanOut(deviceId, capName, await api.deviceState.getCapSlice.query({
100330
+ deviceId,
100331
+ capName
100332
+ }) ?? void 0);
100333
+ },
100334
+ watch(deviceId, capName, cb) {
100335
+ const k = keyOf(deviceId, capName);
100336
+ let set = listeners.get(k);
100337
+ if (!set) {
100338
+ set = /* @__PURE__ */ new Set();
100339
+ listeners.set(k, set);
100340
+ }
100341
+ set.add(cb);
100342
+ ensureBridge();
100343
+ return () => {
100344
+ set.delete(cb);
100345
+ if (set.size === 0) listeners.delete(k);
100346
+ closeBridgeIfIdle();
100347
+ };
100348
+ },
100349
+ async write(deviceId, capName, slice) {
100350
+ await api.deviceState.setCapSlice.mutate({
100351
+ deviceId,
100352
+ capName,
100353
+ slice
100354
+ });
100355
+ }
100356
+ };
100357
+ }
100058
100358
  function createMirrorSource(mirror, listeners, api) {
100059
100359
  const keyOf = (deviceId, capName) => `${deviceId}:${capName}`;
100060
100360
  return {
@@ -100474,6 +100774,8 @@ var require_sleep_C2XhJhkd = __commonJS({
100474
100774
  getTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrack", "query", input),
100475
100775
  listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
100476
100776
  listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
100777
+ listGroups: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listGroups", "query", input),
100778
+ getGroup: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getGroup", "query", input),
100477
100779
  clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
100478
100780
  getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
100479
100781
  getObjectEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getObjectEvents", "query", input),
@@ -100698,7 +101000,6 @@ var require_sleep_C2XhJhkd = __commonJS({
100698
101000
  setStreamProfileMap: (input) => dispatchSystem("deviceManager", "setStreamProfileMap", "mutation", input),
100699
101001
  probeStreams: (input) => dispatchSystem("deviceManager", "probeStreams", "mutation", input),
100700
101002
  getBindings: (input) => dispatchSystem("deviceManager", "getBindings", "query", input),
100701
- getAllBindings: (input) => dispatchSystem("deviceManager", "getAllBindings", "query", input),
100702
101003
  setWrapperActive: (input) => dispatchSystem("deviceManager", "setWrapperActive", "mutation", input),
100703
101004
  getDeviceSettingsAggregate: (input) => dispatchSystem("deviceManager", "getDeviceSettingsAggregate", "query", input),
100704
101005
  getDeviceLiveInfoAggregate: (input) => dispatchSystem("deviceManager", "getDeviceLiveInfoAggregate", "query", input),
@@ -101252,6 +101553,12 @@ var require_sleep_C2XhJhkd = __commonJS({
101252
101553
  return createEvent;
101253
101554
  }
101254
101555
  });
101556
+ Object.defineProperty(exports, "createEventBusSliceSource", {
101557
+ enumerable: true,
101558
+ get: function() {
101559
+ return createEventBusSliceSource;
101560
+ }
101561
+ });
101255
101562
  Object.defineProperty(exports, "createLazyTrpcSource", {
101256
101563
  enumerable: true,
101257
101564
  get: function() {
@@ -101453,7 +101760,7 @@ var require_addon = __commonJS({
101453
101760
  "use strict";
101454
101761
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
101455
101762
  var require_event_category = require_event_category_EY0GNjV9();
101456
- var require_sleep = require_sleep_C2XhJhkd();
101763
+ var require_sleep = require_sleep_CUuoW_kk();
101457
101764
  var require_err_msg = require_err_msg_COpsHMw2();
101458
101765
  var CAP_INPUT_DEFAULTS = Object.freeze({
101459
101766
  "addons": { "getLogs": { "limit": 100 } },
@@ -101566,6 +101873,7 @@ var require_addon = __commonJS({
101566
101873
  "getMotionEvents": { "limit": 1e3 },
101567
101874
  "getObjectEvents": { "limit": 1e3 },
101568
101875
  "getSensorEvents": { "limit": 1e3 },
101876
+ "listGroups": { "limit": 40 },
101569
101877
  "listRecentTracks": { "limit": 200 },
101570
101878
  "searchObjectEvents": {
101571
101879
  "limit": 50,
@@ -101773,6 +102081,7 @@ var require_addon = __commonJS({
101773
102081
  exports.asJsonObject = require_sleep.asJsonObject;
101774
102082
  exports.asString = require_sleep.asString;
101775
102083
  exports.createDeviceProxy = require_sleep.createDeviceProxy;
102084
+ exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
101776
102085
  exports.deviceOpsCapability = require_sleep.deviceOpsCapability;
101777
102086
  exports.emitReadiness = require_sleep.emitReadiness;
101778
102087
  exports.errMsg = require_err_msg.errMsg;
@@ -108327,9 +108636,9 @@ var require_dist2 = __commonJS({
108327
108636
  }
108328
108637
  });
108329
108638
 
108330
- // ../system/dist/manifest-python-deps-CwBbX4Ut.js
108331
- var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108332
- "../system/dist/manifest-python-deps-CwBbX4Ut.js"(exports) {
108639
+ // ../system/dist/manifest-python-deps-DB_4H3tR.js
108640
+ var require_manifest_python_deps_DB_4H3tR = __commonJS({
108641
+ "../system/dist/manifest-python-deps-DB_4H3tR.js"(exports) {
108333
108642
  "use strict";
108334
108643
  var require_chunk = require_chunk_Cek0wNdY();
108335
108644
  var node_crypto = __require("crypto");
@@ -108345,6 +108654,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108345
108654
  var node_fs = __require("fs");
108346
108655
  node_fs = require_chunk.__toESM(node_fs);
108347
108656
  var node_http = __require("http");
108657
+ var node_perf_hooks = __require("perf_hooks");
108348
108658
  var node_v8 = __require("v8");
108349
108659
  node_v8 = require_chunk.__toESM(node_v8);
108350
108660
  var node_vm = __require("vm");
@@ -108362,6 +108672,41 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108362
108672
  }
108363
108673
  var HEAP_RECLAIM_TRIGGER_MB = 1024;
108364
108674
  var HEAP_RECLAIM_MIN_INTERVAL_MS = 12e4;
108675
+ var ZERO_LOOP_DELAY = {
108676
+ p50Ms: 0,
108677
+ p99Ms: 0,
108678
+ maxMs: 0
108679
+ };
108680
+ function createLoopDelayMeter(resolutionMs = 20) {
108681
+ try {
108682
+ const histogram = (0, node_perf_hooks.monitorEventLoopDelay)({ resolution: resolutionMs });
108683
+ histogram.enable();
108684
+ return {
108685
+ read: () => {
108686
+ try {
108687
+ if (histogram.count === 0) return ZERO_LOOP_DELAY;
108688
+ const sample = {
108689
+ p50Ms: Math.round(histogram.percentile(50) / 1e6),
108690
+ p99Ms: Math.round(histogram.percentile(99) / 1e6),
108691
+ maxMs: Math.round(histogram.max / 1e6)
108692
+ };
108693
+ histogram.reset();
108694
+ return sample;
108695
+ } catch {
108696
+ return ZERO_LOOP_DELAY;
108697
+ }
108698
+ },
108699
+ stop: () => {
108700
+ histogram.disable();
108701
+ }
108702
+ };
108703
+ } catch {
108704
+ return;
108705
+ }
108706
+ }
108707
+ function heapCeilingOrigin(execArgv = process.execArgv) {
108708
+ return execArgv.some((arg) => /^--max[-_]old[-_]space[-_]size(=|$)/.test(arg)) ? "explicit" : "v8-default";
108709
+ }
108365
108710
  var MB = (bytes) => Math.round(bytes / 1048576);
108366
108711
  function buildHeapSample(mem, heapLimitBytes, warnRatio = HEAP_WATCH_WARN_RATIO) {
108367
108712
  const usedRatio = heapLimitBytes > 0 ? mem.heapUsed / heapLimitBytes : 0;
@@ -108403,10 +108748,12 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108403
108748
  return;
108404
108749
  }
108405
108750
  }
108406
- function format2(label, s) {
108407
- 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`;
108751
+ function format2(label, s, loop) {
108752
+ 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`;
108753
+ if (loop === void 0) return line;
108754
+ return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms`;
108408
108755
  }
108409
- function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions) {
108756
+ function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv, announceCeilingOrigin = true) {
108410
108757
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
108411
108758
  const now = reclaimOptions?.now ?? (() => Date.now());
108412
108759
  const triggerMb = reclaimOptions?.triggerMb ?? 1024;
@@ -108415,14 +108762,22 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108415
108762
  const escalateRatio = reclaimOptions?.escalateRatio ?? 0.7;
108416
108763
  const deescalateRatio = reclaimOptions?.deescalateRatio ?? 0.6;
108417
108764
  let lastReclaimAt = Number.NEGATIVE_INFINITY;
108765
+ let passesAtFloor = 0;
108766
+ let steadyStateAnnounced = false;
108418
108767
  const read = () => {
108419
108768
  const limit = reclaimOptions?.heapLimitBytes ?? node_v8.getHeapStatistics().heap_size_limit;
108420
108769
  return buildHeapSample(readMemory(), limit);
108421
108770
  };
108422
108771
  const maybeReclaim = (sample) => {
108423
108772
  if (reclaimOptions === void 0) return;
108424
- if (!shouldReclaim(sample, triggerMb)) return;
108425
- if (now() - lastReclaimAt < minIntervalMs) return;
108773
+ if (!shouldReclaim(sample, triggerMb)) {
108774
+ passesAtFloor = 0;
108775
+ steadyStateAnnounced = false;
108776
+ return;
108777
+ }
108778
+ const sinceLast = now() - lastReclaimAt;
108779
+ if (sinceLast < minIntervalMs) return;
108780
+ passesAtFloor = sinceLast <= minIntervalMs * 2 ? passesAtFloor + 1 : 1;
108426
108781
  lastReclaimAt = now();
108427
108782
  const startedAt = now();
108428
108783
  try {
@@ -108433,6 +108788,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108433
108788
  }
108434
108789
  const after = read();
108435
108790
  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`);
108791
+ if (passesAtFloor >= 6 && !steadyStateAnnounced) {
108792
+ steadyStateAnnounced = true;
108793
+ 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.`);
108794
+ }
108436
108795
  };
108437
108796
  let mode = "steady";
108438
108797
  let lastLoggedAt = Number.NEGATIVE_INFINITY;
@@ -108446,7 +108805,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108446
108805
  const due = at - lastLoggedAt >= intervalMs;
108447
108806
  if (mode === "escalated" || due) {
108448
108807
  lastLoggedAt = at;
108449
- const line = format2(label, sample);
108808
+ const line = format2(label, sample, loopDelay?.read());
108450
108809
  if (sample.nearLimit) sink.warn(`${line} \u2014 APPROACHING HEAP LIMIT`);
108451
108810
  else if (mode === "escalated") sink.warn(`${line} \u2014 heap elevated, sampling every ${probeIntervalMs}ms`);
108452
108811
  else sink.info(line);
@@ -108459,24 +108818,26 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
108459
108818
  const timer = setInterval(tick, probeIntervalMs);
108460
108819
  timer.unref?.();
108461
108820
  tick();
108821
+ if (announceCeilingOrigin && 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.`);
108462
108822
  let stopped = false;
108463
108823
  return () => {
108464
108824
  if (stopped) return;
108465
108825
  stopped = true;
108466
108826
  clearInterval(timer);
108827
+ loopDelay?.stop();
108467
108828
  };
108468
108829
  }
108469
108830
  var RUNNER_HEAP_WATCH_INTERVAL_MS = 3e5;
108470
108831
  function startRunnerHeapWatch(options) {
108471
108832
  if (options.heapProfile !== "heavy") return void 0;
108472
108833
  const intervalMs = options.intervalMs ?? 3e5;
108473
- if (options.reclaimSwitch === "off") return startHeapWatch(options.label, options.sink, intervalMs);
108834
+ if (options.reclaimSwitch === "off") return startHeapWatch(options.label, options.sink, intervalMs, void 0, void 0, void 0, false);
108474
108835
  let reclaimOptions = options.reclaimOptions;
108475
108836
  if (reclaimOptions === void 0) {
108476
108837
  const reclaimer = createV8Reclaimer();
108477
108838
  reclaimOptions = reclaimer === void 0 ? void 0 : { reclaim: reclaimer };
108478
108839
  }
108479
- return startHeapWatch(options.label, options.sink, intervalMs, reclaimOptions);
108840
+ return startHeapWatch(options.label, options.sink, intervalMs, reclaimOptions, void 0, void 0, false);
108480
108841
  }
108481
108842
  function trimSlashes(s) {
108482
108843
  return s.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -109555,6 +109916,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
109555
109916
  }
109556
109917
  function createBrokerDeviceManagerApi(opts) {
109557
109918
  const { api, addonId, nodeId, eventBus, registry } = opts;
109919
+ const deviceSliceSource = (0, _camstack_types_addon.createEventBusSliceSource)({
109920
+ eventBus,
109921
+ api
109922
+ });
109558
109923
  let selfApi;
109559
109924
  const deviceRebuildFactories = /* @__PURE__ */ new Map();
109560
109925
  const buildContext = (stableId, id, parentDeviceId = null, initialRuntimeState = {}, persistedConfig = {}, deviceMeta = null) => {
@@ -109599,7 +109964,7 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
109599
109964
  metadata: null
109600
109965
  },
109601
109966
  fetchDevice: async (deviceId) => {
109602
- return (0, _camstack_types_addon.createDeviceProxy)(api, await api.deviceManager.getBindings.query({ deviceId }));
109967
+ return (0, _camstack_types_addon.createDeviceProxy)(api, await api.deviceManager.getBindings.query({ deviceId }), { stateSource: deviceSliceSource });
109603
109968
  },
109604
109969
  get devices() {
109605
109970
  return selfApi;
@@ -114498,6 +114863,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
114498
114863
  const api = (0, _trpc_client.createTRPCClient)({ links });
114499
114864
  const scopedLogger = options?.createLogger?.(addonId) ?? (runtime.mode === "broker" ? createRemoteLogger(runtime.broker, addonId) : createUdsLogger(runtime.client, addonId, nodeId));
114500
114865
  const scopedEventBus = runtime.mode === "broker" ? createBrokerEventBus(runtime.broker, addonId) : createUdsEventBus(runtime.client, addonId);
114866
+ const deviceSliceSource = (0, _camstack_types_addon.createEventBusSliceSource)({
114867
+ eventBus: scopedEventBus,
114868
+ api
114869
+ });
114501
114870
  const workerDisposerChain = new _camstack_types_addon.DisposerChain({ onError: (err, index) => {
114502
114871
  scopedLogger.error(`Disposer #${index} threw during teardown`, { meta: { error: err instanceof Error ? err.message : String(err) } });
114503
114872
  } });
@@ -114733,10 +115102,10 @@ var require_manifest_python_deps_CwBbX4Ut = __commonJS({
114733
115102
  },
114734
115103
  fetchDevice: async (deviceId) => {
114735
115104
  const cached = bindingCache.get(deviceId);
114736
- if (cached) return (0, _camstack_types_addon.createDeviceProxy)(api, cached);
115105
+ if (cached) return (0, _camstack_types_addon.createDeviceProxy)(api, cached, { stateSource: deviceSliceSource });
114737
115106
  const binding = await api.deviceManager.getBindings.query({ deviceId });
114738
115107
  bindingCache.set(deviceId, binding);
114739
- return (0, _camstack_types_addon.createDeviceProxy)(api, binding);
115108
+ return (0, _camstack_types_addon.createDeviceProxy)(api, binding, { stateSource: deviceSliceSource });
114740
115109
  },
114741
115110
  useCapability(capName, scope = { type: "global" }) {
114742
115111
  return getOrCreateHandle(capName, scope, Number.POSITIVE_INFINITY);
@@ -119879,7 +120248,7 @@ var require_dist3 = __commonJS({
119879
120248
  "use strict";
119880
120249
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
119881
120250
  var require_chunk = require_chunk_Cek0wNdY();
119882
- var require_dist10 = require_dist_C2_1HCpW();
120251
+ var require_dist10 = require_dist_CIDgcxPk();
119883
120252
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
119884
120253
  require_alerts();
119885
120254
  var require_formatter = require_formatter_DqAKDlvN();
@@ -119904,7 +120273,7 @@ var require_dist3 = __commonJS({
119904
120273
  require_system_config();
119905
120274
  var require_builtins_winston_logging_index = require_winston_logging();
119906
120275
  var require_file_data_plane = require_file_data_plane_DO8KbxCe();
119907
- var require_manifest_python_deps = require_manifest_python_deps_CwBbX4Ut();
120276
+ var require_manifest_python_deps = require_manifest_python_deps_DB_4H3tR();
119908
120277
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
119909
120278
  var require_lan_http_bind = require_lan_http_bind_DmgpFP6();
119910
120279
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
@@ -122128,7 +122497,7 @@ var require_dist3 = __commonJS({
122128
122497
  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(", ")}`);
122129
122498
  return results;
122130
122499
  }
122131
- function isRecord$1(value) {
122500
+ function isRecord$2(value) {
122132
122501
  return typeof value === "object" && value !== null && !Array.isArray(value);
122133
122502
  }
122134
122503
  var PACKAGE_JSON_LOOKUP_DEPTH = 4;
@@ -122168,9 +122537,9 @@ var require_dist3 = __commonJS({
122168
122537
  return import(`${(0, node_url.pathToFileURL)(entryPath).href}?v=${encodeURIComponent(bust)}`);
122169
122538
  }
122170
122539
  function toAddonPackageManifest(value) {
122171
- if (!isRecord$1(value)) return void 0;
122540
+ if (!isRecord$2(value)) return void 0;
122172
122541
  if (!Array.isArray(value.addons)) return void 0;
122173
- if (!value.addons.every((a) => isRecord$1(a) && typeof a.id === "string")) return void 0;
122542
+ if (!value.addons.every((a) => isRecord$2(a) && typeof a.id === "string")) return void 0;
122174
122543
  return value;
122175
122544
  }
122176
122545
  var noopLogger$1 = {
@@ -122312,7 +122681,7 @@ var require_dist3 = __commonJS({
122312
122681
  }
122313
122682
  if (!node_fs.existsSync(entryPath)) throw new Error(`Entry not found: ${entryPath}`);
122314
122683
  const modUnknown = await importAddonModuleFresh(entryPath);
122315
- const mod = isRecord$1(modUnknown) ? modUnknown : {};
122684
+ const mod = isRecord$2(modUnknown) ? modUnknown : {};
122316
122685
  const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
122317
122686
  if (!AddonClass) throw new Error(`No addon class in ${entryPath}`);
122318
122687
  this.addons.set(declaration.id, {
@@ -122328,7 +122697,7 @@ var require_dist3 = __commonJS({
122328
122697
  /** Load addon from a direct path (for development/testing) */
122329
122698
  async loadFromPath(addonId, modulePath, packageName, declaration, packageVersion = "0.0.0") {
122330
122699
  const modUnknown = await importAddonModuleFresh(modulePath);
122331
- const mod = isRecord$1(modUnknown) ? modUnknown : {};
122700
+ const mod = isRecord$2(modUnknown) ? modUnknown : {};
122332
122701
  const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
122333
122702
  if (!AddonClass) throw new Error(`Module ${modulePath} has no default export`);
122334
122703
  this.addons.set(addonId, {
@@ -125691,6 +126060,143 @@ var require_dist3 = __commonJS({
125691
126060
  function isInfraCapability(name2) {
125692
126061
  return infraNames.has(name2);
125693
126062
  }
126063
+ var INFRA_NAMES = new Set(INFRA_CAPABILITIES.map((c) => c.name));
126064
+ function isolatedBuiltinPhase(capabilities) {
126065
+ return capabilities.some((c) => INFRA_NAMES.has(c.name)) ? "infra" : "consumer";
126066
+ }
126067
+ function partitionIsolatedBuiltinIds(ids, capabilitiesOf) {
126068
+ const infra = [];
126069
+ const consumers = [];
126070
+ for (const id of ids) if (isolatedBuiltinPhase(capabilitiesOf(id)) === "infra") infra.push(id);
126071
+ else consumers.push(id);
126072
+ return {
126073
+ infra,
126074
+ consumers
126075
+ };
126076
+ }
126077
+ async function waitUntilReady(isReady, options) {
126078
+ const deadline = Date.now() + options.timeoutMs;
126079
+ for (; ; ) {
126080
+ if (isReady()) return;
126081
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${options.what}`);
126082
+ await new Promise((resolve) => {
126083
+ setTimeout(resolve, options.intervalMs);
126084
+ });
126085
+ }
126086
+ }
126087
+ async function runHubAddonBoot(steps) {
126088
+ await steps.spawnIsolatedInfra();
126089
+ await steps.waitForDataStoreProvider();
126090
+ await steps.bootInProcessInfra();
126091
+ await steps.spawnForkedAddons();
126092
+ await steps.bootInProcessConsumers();
126093
+ await steps.spawnIsolatedConsumers();
126094
+ }
126095
+ function isRecord$1(value) {
126096
+ return typeof value === "object" && value !== null && !Array.isArray(value);
126097
+ }
126098
+ function asBlob(value) {
126099
+ return isRecord$1(value) ? value : {};
126100
+ }
126101
+ function unwrapValue(parsed) {
126102
+ if (!isRecord$1(parsed) || !("value" in parsed)) return parsed;
126103
+ return parsed.value;
126104
+ }
126105
+ async function loadPrefixed(door, collection, prefix) {
126106
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(prefix);
126107
+ const rows = await door.query({
126108
+ collection,
126109
+ ...range !== null ? { filter: { whereBetween: { id: [range.lo, range.hi] } } } : {}
126110
+ });
126111
+ const result = {};
126112
+ for (const row of rows) {
126113
+ if (range !== null && (row.id < range.lo || row.id >= range.hi)) continue;
126114
+ if (!row.id.startsWith(prefix)) continue;
126115
+ result[row.id.slice(prefix.length)] = unwrapValue(row.data);
126116
+ }
126117
+ return result;
126118
+ }
126119
+ async function replacePrefixed(door, collection, prefix, values, wrap3) {
126120
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(prefix);
126121
+ if (range !== null) await door.deleteWhere({
126122
+ collection,
126123
+ filter: { whereBetween: { id: [range.lo, range.hi] } }
126124
+ });
126125
+ for (const [key, value] of Object.entries(values)) {
126126
+ if (value === void 0) continue;
126127
+ await door.set({
126128
+ collection,
126129
+ key: `${prefix}${key}`,
126130
+ value: wrap3(key, value)
126131
+ });
126132
+ }
126133
+ }
126134
+ function createDoorSettingsView(addonId, door, sections) {
126135
+ const addonPrefix = `${addonId}.`;
126136
+ return {
126137
+ async readAddonStore() {
126138
+ return loadPrefixed(door, "addon-settings", addonPrefix);
126139
+ },
126140
+ async writeAddonStore(patch) {
126141
+ await replacePrefixed(door, "addon-settings", addonPrefix, {
126142
+ ...await loadPrefixed(door, "addon-settings", addonPrefix),
126143
+ ...patch
126144
+ }, (key, value) => ({
126145
+ addonId,
126146
+ key,
126147
+ value
126148
+ }));
126149
+ },
126150
+ async readDeviceStore(deviceId) {
126151
+ return loadPrefixed(door, "addon-device-settings", `${addonId}:${String(deviceId)}.`);
126152
+ },
126153
+ async writeDeviceStore(deviceId, patch) {
126154
+ const scope = `${addonId}:${String(deviceId)}.`;
126155
+ await replacePrefixed(door, "addon-device-settings", scope, {
126156
+ ...await loadPrefixed(door, "addon-device-settings", scope),
126157
+ ...patch
126158
+ }, (key, value) => ({
126159
+ addonId,
126160
+ deviceId: String(deviceId),
126161
+ key,
126162
+ value
126163
+ }));
126164
+ },
126165
+ async clearDeviceStore(deviceId) {
126166
+ const range = require_builtins_sqlite_storage_sqlite_settings_addon.prefixRange(`${addonId}:${String(deviceId)}.`);
126167
+ if (range === null) return;
126168
+ await door.deleteWhere({
126169
+ collection: "addon-device-settings",
126170
+ filter: { whereBetween: { id: [range.lo, range.hi] } }
126171
+ });
126172
+ },
126173
+ async readDeviceRuntimeState(deviceId) {
126174
+ return asBlob(await door.get({
126175
+ collection: "device-runtime-state",
126176
+ key: String(deviceId)
126177
+ }));
126178
+ },
126179
+ async writeDeviceRuntimeState(deviceId, data) {
126180
+ await door.set({
126181
+ collection: "device-runtime-state",
126182
+ key: String(deviceId),
126183
+ value: data
126184
+ });
126185
+ },
126186
+ async clearDeviceRuntimeState(deviceId) {
126187
+ await door.delete({
126188
+ collection: "device-runtime-state",
126189
+ key: String(deviceId)
126190
+ });
126191
+ },
126192
+ async getSection(section) {
126193
+ return sections.getSection(section);
126194
+ },
126195
+ async setSection(section, patch) {
126196
+ await sections.setSection(section, patch);
126197
+ }
126198
+ };
126199
+ }
125694
126200
  var __create = Object.create;
125695
126201
  var __defProp = Object.defineProperty;
125696
126202
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -128170,6 +128676,7 @@ var require_dist3 = __commonJS({
128170
128676
  configPath;
128171
128677
  bootstrapConfig;
128172
128678
  settingsStore = null;
128679
+ settingsDoor = null;
128173
128680
  runtimeState;
128174
128681
  runtimeStatePath;
128175
128682
  constructor(configPath) {
@@ -128190,6 +128697,14 @@ var require_dist3 = __commonJS({
128190
128697
  setSettingsStore(store) {
128191
128698
  this.settingsStore = store;
128192
128699
  }
128700
+ /**
128701
+ * Wire the async `settings-store` door. Used when the engine is isolated
128702
+ * (no sync `ISettingsStore` handle on hub-main). {@link createSettingsView}
128703
+ * prefers the sync store when both are present.
128704
+ */
128705
+ setSettingsDoor(door) {
128706
+ this.settingsDoor = door;
128707
+ }
128193
128708
  get(configPath) {
128194
128709
  return this.resolveConfigValue(configPath);
128195
128710
  }
@@ -128210,8 +128725,21 @@ var require_dist3 = __commonJS({
128210
128725
  * Throws if the settings store is not yet wired.
128211
128726
  */
128212
128727
  set(key, value) {
128213
- if (this.settingsStore === null) throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
128214
- this.settingsStore.setSystem(key, value);
128728
+ if (this.settingsStore !== null) {
128729
+ this.settingsStore.setSystem(key, value);
128730
+ return;
128731
+ }
128732
+ if (this.settingsDoor !== null) {
128733
+ this.settingsDoor.set({
128734
+ collection: "system-settings",
128735
+ key,
128736
+ value
128737
+ }).catch((err) => {
128738
+ console.error("[ConfigManager] isolated settings-store write failed", err);
128739
+ });
128740
+ return;
128741
+ }
128742
+ throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
128215
128743
  }
128216
128744
  /**
128217
128745
  * Bulk-read all keys that belong to a logical section.
@@ -128332,6 +128860,19 @@ var require_dist3 = __commonJS({
128332
128860
  this.settingsStore.clearDeviceRuntimeState(deviceId);
128333
128861
  }
128334
128862
  createSettingsView(addonId) {
128863
+ if (this.settingsStore === null && this.settingsDoor !== null) {
128864
+ const door = this.settingsDoor;
128865
+ return createDoorSettingsView(addonId, door, {
128866
+ getSection: (section) => this.getSection(section),
128867
+ setSection: async (section, patch) => {
128868
+ for (const [key, value] of Object.entries(patch)) await door.set({
128869
+ collection: "system-settings",
128870
+ key: `${section}.${key}`,
128871
+ value
128872
+ });
128873
+ }
128874
+ });
128875
+ }
128335
128876
  const cm = this;
128336
128877
  return {
128337
128878
  async readAddonStore() {
@@ -200115,6 +200656,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
200115
200656
  exports.createBroker = createBroker2;
200116
200657
  exports.createBrokerDeviceManagerApi = require_manifest_python_deps.createBrokerDeviceManagerApi;
200117
200658
  exports.createCoreCapService = createCoreCapService;
200659
+ exports.createDoorSettingsView = createDoorSettingsView;
200118
200660
  exports.createFileDataPlaneHandler = require_file_data_plane.createFileDataPlaneHandler;
200119
200661
  exports.createHubCapForwardService = require_manifest_python_deps.createHubCapForwardService;
200120
200662
  exports.createHubService = createHubService;
@@ -200234,6 +200776,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
200234
200776
  exports.isInfraCapability = isInfraCapability;
200235
200777
  exports.isModelDownloaded = require_file_data_plane.isModelDownloaded;
200236
200778
  exports.isSourceNewer = isSourceNewer;
200779
+ exports.isolatedBuiltinPhase = isolatedBuiltinPhase;
200237
200780
  exports.loadTlsCert = require_lan_http_bind.loadTlsCert;
200238
200781
  exports.localEndpointPath = require_manifest_python_deps.localEndpointPath;
200239
200782
  exports.localProviderLink = require_manifest_python_deps.localProviderLink;
@@ -200241,6 +200784,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
200241
200784
  exports.parseCapAction = require_manifest_python_deps.parseCapAction;
200242
200785
  exports.parseRangeHeader = require_file_data_plane.parseRangeHeader;
200243
200786
  exports.parseTokenizedUrl = require_file_data_plane.parseTokenizedUrl;
200787
+ exports.partitionIsolatedBuiltinIds = partitionIsolatedBuiltinIds;
200244
200788
  exports.proxyToUpstream = proxyToUpstream;
200245
200789
  exports.quarantineAddonResidue = quarantineAddonResidue;
200246
200790
  exports.readExtraSans = require_lan_http_bind.readExtraSans;
@@ -200255,6 +200799,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
200255
200799
  exports.resolveFilePath = require_file_data_plane.resolveFilePath;
200256
200800
  exports.resolveHwAccel = require_manifest_python_deps.resolveHwAccel;
200257
200801
  exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation;
200802
+ exports.runHubAddonBoot = runHubAddonBoot;
200258
200803
  exports.runNpm = require_manifest_python_deps.runNpm;
200259
200804
  exports.scheduleSelfRestart = scheduleSelfRestart;
200260
200805
  exports.scopeKey = require_dist10.scopeKey;
@@ -200273,6 +200818,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
200273
200818
  exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
200274
200819
  exports.validateProviderRegistrations = require_manifest_python_deps.validateProviderRegistrations;
200275
200820
  exports.validateUploadedTls = require_lan_http_bind.validateUploadedTls;
200821
+ exports.waitUntilReady = waitUntilReady;
200276
200822
  exports.writeExtraSans = require_lan_http_bind.writeExtraSans;
200277
200823
  exports.writePendingRestart = writePendingRestart;
200278
200824
  exports.writeTlsMode = require_lan_http_bind.writeTlsMode;
@@ -238964,7 +239510,7 @@ var require_dist9 = __commonJS({
238964
239510
  "use strict";
238965
239511
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
238966
239512
  var require_event_category = require_event_category_EY0GNjV9();
238967
- var require_sleep = require_sleep_C2XhJhkd();
239513
+ var require_sleep = require_sleep_CUuoW_kk();
238968
239514
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
238969
239515
  var require_enums2 = require_enums();
238970
239516
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -240673,6 +241219,20 @@ var require_dist9 = __commonJS({
240673
241219
  */
240674
241220
  resolution: zod.z.number().int().positive().optional()
240675
241221
  });
241222
+ var MODEL_PROVIDER_IDS = [
241223
+ "camstack",
241224
+ "frigate",
241225
+ "scrypted",
241226
+ "custom"
241227
+ ];
241228
+ var ModelProviderIdSchema = zod.z.enum(MODEL_PROVIDER_IDS);
241229
+ function inferModelProvider(entry) {
241230
+ if (entry.provider !== void 0) return entry.provider;
241231
+ const haystack = `${entry.id} ${entry.description ?? ""}`;
241232
+ if (/scrypted/i.test(haystack)) return "scrypted";
241233
+ if (/frigate/i.test(haystack)) return "frigate";
241234
+ return "custom";
241235
+ }
240676
241236
  var ModelCatalogEntrySchema = zod.z.object({
240677
241237
  id: zod.z.string(),
240678
241238
  name: zod.z.string(),
@@ -240770,6 +241330,12 @@ var require_dist9 = __commonJS({
240770
241330
  */
240771
241331
  group: ModelVariantGroupSchema.optional(),
240772
241332
  /**
241333
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
241334
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
241335
+ * persisted before this field existed (`inferModelProvider` fills those).
241336
+ */
241337
+ provider: ModelProviderIdSchema.optional(),
241338
+ /**
240773
241339
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
240774
241340
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
240775
241341
  * labels already ARE the CamStack macros (Scrypted identity map).
@@ -245371,6 +245937,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245371
245937
  features: zod.z.array(zod.z.string()),
245372
245938
  producesTrackedEvents: zod.z.boolean().optional()
245373
245939
  });
245940
+ var LinkedDevicesForDeviceSchema = zod.z.object({
245941
+ deviceId: zod.z.number(),
245942
+ mode: LinkedDevicesModeSchema,
245943
+ devices: zod.z.array(LinkedDeviceSchema)
245944
+ });
245945
+ var DeviceBindingsForDeviceSchema = zod.z.object({
245946
+ deviceId: zod.z.number(),
245947
+ entries: zod.z.array(zod.z.object({
245948
+ capName: zod.z.string(),
245949
+ kind: zod.z.enum(["native", "wrapped"]),
245950
+ providerAddonId: zod.z.string(),
245951
+ providerNodeId: zod.z.string(),
245952
+ nativeAddonId: zod.z.string()
245953
+ }))
245954
+ });
245374
245955
  var SavedDeviceRowSchema = zod.z.object({
245375
245956
  /** Numeric id reserved at allocateDeviceId time. */
245376
245957
  id: zod.z.number(),
@@ -245728,7 +246309,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245728
246309
  projection: zod.z.enum(["full", "slim"]).optional(),
245729
246310
  /** Return only camera devices. Filtering server-side instead of
245730
246311
  * shipping 293 rows to find 12. */
245731
- isCamera: zod.z.boolean().optional()
246312
+ isCamera: zod.z.boolean().optional(),
246313
+ /**
246314
+ * Return only these device ids. For the caller that already KNOWS the
246315
+ * handful it wants and needs a field the id-bearing answer does not
246316
+ * carry — the viewer's linked-devices panel joins `type` and `online`
246317
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
246318
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
246319
+ * refetches on the reconcile interval, on a phone.
246320
+ *
246321
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
246322
+ * keys rather than rejecting them (verified against the live hub
246323
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
246324
+ * it answers today and the caller filters as it already does.
246325
+ */
246326
+ deviceIds: zod.z.array(zod.z.number()).optional()
245732
246327
  }), zod.z.array(DeviceInfoSchema)),
245733
246328
  /** Get a single device by numeric deviceId. */
245734
246329
  getDevice: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
@@ -245747,6 +246342,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245747
246342
  mode: LinkedDevicesModeSchema,
245748
246343
  devices: zod.z.array(LinkedDeviceSchema)
245749
246344
  })),
246345
+ /**
246346
+ * `getLinkedDevices` for MANY cameras, in one call.
246347
+ *
246348
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
246349
+ * needs the whole fleet as candidates (children ∪ same-location), so the
246350
+ * single-device path runs a full `listAll` per call. Asked per camera that
246351
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
246352
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
246353
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
246354
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
246355
+ * camera.
246356
+ *
246357
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
246358
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
246359
+ * are missing, or that any are.
246360
+ */
246361
+ getLinkedDevicesBatch: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(LinkedDevicesForDeviceSchema)),
245750
246362
  /** Get stream sources for a camera device. */
245751
246363
  getStreamSources: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(require_sleep.StreamSourceEntrySchema)),
245752
246364
  /** Get config entries (key + value + description) for a device. */
@@ -245804,16 +246416,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245804
246416
  * currently-active provider (native or wrapper) + the underlying native
245805
246417
  * addon id, so consumers can decide routing without re-running discovery.
245806
246418
  */
245807
- getBindings: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
245808
- deviceId: zod.z.number(),
245809
- entries: zod.z.array(zod.z.object({
245810
- capName: zod.z.string(),
245811
- kind: zod.z.enum(["native", "wrapped"]),
245812
- providerAddonId: zod.z.string(),
245813
- providerNodeId: zod.z.string(),
245814
- nativeAddonId: zod.z.string()
245815
- }))
245816
- })),
246419
+ getBindings: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DeviceBindingsForDeviceSchema),
246420
+ /**
246421
+ * `getBindings` for a NAMED set of devices, in one call.
246422
+ *
246423
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
246424
+ * was nothing, so a caller that needs seventy-five either pays
246425
+ * seventy-five round-trips or drags the whole fleet across. Measured on
246426
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
246427
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
246428
+ * "these seventy-five".
246429
+ *
246430
+ * Same resolver, same routing rules, same per-device shape as
246431
+ * `getBindings`; ids are deduped and a device with no bindings answers
246432
+ * `entries: []` rather than dropping out.
246433
+ */
246434
+ getBindingsBatch: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(DeviceBindingsForDeviceSchema)),
245817
246435
  /**
245818
246436
  * Return the binding map for every device known to the hub. Used by
245819
246437
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -245822,16 +246440,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245822
246440
  * device add/remove) — clients invalidate via the
245823
246441
  * `capability.binding-changed` event.
245824
246442
  */
245825
- getAllBindings: require_sleep.method(zod.z.object({}), zod.z.array(zod.z.object({
245826
- deviceId: zod.z.number(),
245827
- entries: zod.z.array(zod.z.object({
245828
- capName: zod.z.string(),
245829
- kind: zod.z.enum(["native", "wrapped"]),
245830
- providerAddonId: zod.z.string(),
245831
- providerNodeId: zod.z.string(),
245832
- nativeAddonId: zod.z.string()
245833
- }))
245834
- }))),
246443
+ getAllBindings: require_sleep.method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
245835
246444
  /**
245836
246445
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
245837
246446
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -248632,14 +249241,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
248632
249241
  });
248633
249242
  var NC_AUDIO_DBFS_FLOOR = -96;
248634
249243
  var NcAudioConditionSchema = zod.z.object({
248635
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
249244
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
248636
249245
  labels: zod.z.array(zod.z.string().min(1)).min(1).optional(),
248637
249246
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
248638
249247
  dbThreshold: zod.z.number().min(-96).max(0).optional(),
248639
249248
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
248640
249249
  hitPercent: zod.z.number().int().min(1).max(100).default(60),
248641
249250
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
248642
- samplingSeconds: zod.z.number().int().min(1).max(300).default(10)
249251
+ samplingSeconds: zod.z.number().int().min(1).max(300).default(10),
249252
+ /**
249253
+ * LABEL MODE: how many labelled frames must land inside
249254
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
249255
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
249256
+ */
249257
+ confirmHits: zod.z.number().int().min(1).max(20).optional(),
249258
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
249259
+ confirmWindowSec: zod.z.number().int().min(1).max(60).optional()
248643
249260
  });
248644
249261
  var NcCrossingSchema = zod.z.enum([
248645
249262
  "enter",
@@ -250899,6 +251516,46 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250899
251516
  /** Cursor for the next page, or null when this page is the last. */
250900
251517
  nextCursor: zod.z.string().nullable()
250901
251518
  });
251519
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
251520
+ var LIST_GROUPS_MAX_LIMIT = 100;
251521
+ var AnalyticsGroupRecordSchema = zod.z.object({
251522
+ id: zod.z.string(),
251523
+ deviceId: zod.z.number().int(),
251524
+ openedAt: zod.z.number().int(),
251525
+ closedAt: zod.z.number().int(),
251526
+ timestamp: zod.z.number().int(),
251527
+ memberCount: zod.z.number().int(),
251528
+ memberTrackIds: zod.z.array(zod.z.string()).readonly(),
251529
+ className: zod.z.string(),
251530
+ classes: zod.z.array(zod.z.string()).readonly(),
251531
+ /** Relative event-media path, or null when the group has no picture yet. */
251532
+ mediaUrl: zod.z.string().nullable(),
251533
+ singleton: zod.z.boolean()
251534
+ });
251535
+ var AnalyticsGroupMemberSchema = zod.z.object({
251536
+ trackId: zod.z.string(),
251537
+ deviceId: zod.z.number().int(),
251538
+ className: zod.z.string(),
251539
+ firstSeen: zod.z.number().int(),
251540
+ lastSeen: zod.z.number().int(),
251541
+ mediaUrl: zod.z.string().nullable()
251542
+ });
251543
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
251544
+ var ListGroupsQueryInput = zod.z.object({
251545
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
251546
+ deviceIds: zod.z.array(zod.z.number()),
251547
+ /** Window lower bound on `closedAt` (inclusive). */
251548
+ since: zod.z.number().optional(),
251549
+ /** Window upper bound on `openedAt` (inclusive). */
251550
+ until: zod.z.number().optional(),
251551
+ limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
251552
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
251553
+ cursor: zod.z.string().optional()
251554
+ });
251555
+ var ListGroupsPageSchema = zod.z.object({
251556
+ groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
251557
+ nextCursor: zod.z.string().nullable()
251558
+ });
250902
251559
  var KeyEventQueryInput = zod.z.object({
250903
251560
  deviceId: zod.z.number(),
250904
251561
  /** Window lower bound (track firstSeen ≥ since). */
@@ -250974,7 +251631,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250974
251631
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
250975
251632
  plates: zod.z.number().int(),
250976
251633
  /** Per-track CLIP search vectors removed (best-effort). */
250977
- embeddings: zod.z.number().int()
251634
+ embeddings: zod.z.number().int(),
251635
+ /** Group membership + group rows removed with their last member (best-effort). */
251636
+ groups: zod.z.number().int()
250978
251637
  });
250979
251638
  var DiskReconcileCountsSchema = zod.z.object({
250980
251639
  mediaDropped: zod.z.number().int(),
@@ -251116,6 +251775,16 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251116
251775
  * are not included (same contract as `listTracks`).
251117
251776
  */
251118
251777
  listRecentTracks: require_sleep.method(RecentTracksQueryInput, RecentTracksPageSchema),
251778
+ /**
251779
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
251780
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
251781
+ * one session; `getGroup` is the detail with members.
251782
+ */
251783
+ listGroups: require_sleep.method(ListGroupsQueryInput, ListGroupsPageSchema),
251784
+ getGroup: require_sleep.method(zod.z.object({
251785
+ deviceId: zod.z.number(),
251786
+ groupId: zod.z.string().min(1)
251787
+ }), AnalyticsGroupDetailSchema.nullable()),
251119
251788
  clearTracks: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
251120
251789
  kind: "mutation",
251121
251790
  auth: "admin"
@@ -251797,7 +252466,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
251797
252466
  sizeMB: zod.z.number()
251798
252467
  })),
251799
252468
  group: ModelVariantGroupSchema.optional(),
251800
- legacy: zod.z.boolean().optional()
252469
+ legacy: zod.z.boolean().optional(),
252470
+ provider: ModelProviderIdSchema.optional()
251801
252471
  });
251802
252472
  var ConfigFieldBridge = zod.z.custom();
251803
252473
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -260275,7 +260945,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
260275
260945
  plateBbox: BoundingBoxSchema.optional(),
260276
260946
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
260277
260947
  keyFrameMediaKey: zod.z.string().optional(),
260278
- base64: zod.z.string().optional()
260948
+ base64: zod.z.string().optional(),
260949
+ /**
260950
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
260951
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
260952
+ */
260953
+ cropUrl: zod.z.string().optional()
260279
260954
  });
260280
260955
  var MediaFileLiteSchema = zod.z.object({
260281
260956
  key: zod.z.string(),
@@ -268087,6 +268762,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268087
268762
  addonId: null,
268088
268763
  access: "view"
268089
268764
  },
268765
+ "deviceManager.getBindingsBatch": {
268766
+ capName: "device-manager",
268767
+ capScope: "system",
268768
+ addonId: null,
268769
+ access: "view"
268770
+ },
268090
268771
  "deviceManager.getChildren": {
268091
268772
  capName: "device-manager",
268092
268773
  capScope: "system",
@@ -268147,6 +268828,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268147
268828
  addonId: null,
268148
268829
  access: "view"
268149
268830
  },
268831
+ "deviceManager.getLinkedDevicesBatch": {
268832
+ capName: "device-manager",
268833
+ capScope: "system",
268834
+ addonId: null,
268835
+ access: "view"
268836
+ },
268150
268837
  "deviceManager.getRoleDisplayDefaults": {
268151
268838
  capName: "device-manager",
268152
268839
  capScope: "system",
@@ -269917,6 +270604,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
269917
270604
  addonId: null,
269918
270605
  access: "view"
269919
270606
  },
270607
+ "pipelineAnalytics.getGroup": {
270608
+ capName: "pipeline-analytics",
270609
+ capScope: "device",
270610
+ addonId: null,
270611
+ access: "view"
270612
+ },
269920
270613
  "pipelineAnalytics.getKeyEvents": {
269921
270614
  capName: "pipeline-analytics",
269922
270615
  capScope: "device",
@@ -270001,6 +270694,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
270001
270694
  addonId: null,
270002
270695
  access: "view"
270003
270696
  },
270697
+ "pipelineAnalytics.listGroups": {
270698
+ capName: "pipeline-analytics",
270699
+ capScope: "device",
270700
+ addonId: null,
270701
+ access: "view"
270702
+ },
270004
270703
  "pipelineAnalytics.listOpsLog": {
270005
270704
  capName: "pipeline-analytics",
270006
270705
  capScope: "device",
@@ -273034,6 +273733,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273034
273733
  form: "single",
273035
273734
  optional: false
273036
273735
  }],
273736
+ "deviceManager.getBindingsBatch": [{
273737
+ name: "deviceIds",
273738
+ form: "array",
273739
+ optional: false
273740
+ }],
273037
273741
  "deviceManager.getChildren": [{
273038
273742
  name: "parentDeviceId",
273039
273743
  form: "single",
@@ -273079,6 +273783,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273079
273783
  form: "single",
273080
273784
  optional: false
273081
273785
  }],
273786
+ "deviceManager.getLinkedDevicesBatch": [{
273787
+ name: "deviceIds",
273788
+ form: "array",
273789
+ optional: false
273790
+ }],
273082
273791
  "deviceManager.getSettingsSchema": [{
273083
273792
  name: "deviceId",
273084
273793
  form: "single",
@@ -273099,6 +273808,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273099
273808
  form: "single",
273100
273809
  optional: false
273101
273810
  }],
273811
+ "deviceManager.listAll": [{
273812
+ name: "deviceIds",
273813
+ form: "array",
273814
+ optional: true
273815
+ }],
273102
273816
  "deviceManager.loadConfig": [{
273103
273817
  name: "deviceId",
273104
273818
  form: "single",
@@ -273672,6 +274386,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273672
274386
  form: "single",
273673
274387
  optional: false
273674
274388
  }],
274389
+ "pipelineAnalytics.getGroup": [{
274390
+ name: "deviceId",
274391
+ form: "single",
274392
+ optional: false
274393
+ }],
273675
274394
  "pipelineAnalytics.getKeyEvents": [{
273676
274395
  name: "deviceId",
273677
274396
  form: "single",
@@ -273727,6 +274446,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273727
274446
  form: "array",
273728
274447
  optional: false
273729
274448
  }],
274449
+ "pipelineAnalytics.listGroups": [{
274450
+ name: "deviceIds",
274451
+ form: "array",
274452
+ optional: false
274453
+ }],
273730
274454
  "pipelineAnalytics.listOpsLog": [{
273731
274455
  name: "deviceId",
273732
274456
  form: "single",
@@ -274477,6 +275201,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274477
275201
  "deviceManager.disable",
274478
275202
  "deviceManager.enable",
274479
275203
  "deviceManager.getBindings",
275204
+ "deviceManager.getBindingsBatch",
274480
275205
  "deviceManager.getChildren",
274481
275206
  "deviceManager.getConfigSchema",
274482
275207
  "deviceManager.getDevice",
@@ -274486,10 +275211,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
274486
275211
  "deviceManager.getDeviceStatusAggregate",
274487
275212
  "deviceManager.getDeviceStatusAggregateBatch",
274488
275213
  "deviceManager.getLinkedDevices",
275214
+ "deviceManager.getLinkedDevicesBatch",
274489
275215
  "deviceManager.getSettingsSchema",
274490
275216
  "deviceManager.getStreamProfileMap",
274491
275217
  "deviceManager.getStreamSources",
274492
275218
  "deviceManager.getWireableFields",
275219
+ "deviceManager.listAll",
274493
275220
  "deviceManager.loadConfig",
274494
275221
  "deviceManager.loadMeta",
274495
275222
  "deviceManager.loadRuntimeState",
@@ -275167,7 +275894,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275167
275894
  listPersistedByAddon: (input) => dispatch("deviceManager", "listPersistedByAddon", "query", input),
275168
275895
  listAll: (input) => dispatch("deviceManager", "listAll", "query", input),
275169
275896
  getChildren: (input) => dispatch("deviceManager", "getChildren", "query", input),
275897
+ getLinkedDevicesBatch: (input) => dispatch("deviceManager", "getLinkedDevicesBatch", "query", input),
275170
275898
  removeByIntegration: (input) => dispatch("deviceManager", "removeByIntegration", "mutation", input),
275899
+ getBindingsBatch: (input) => dispatch("deviceManager", "getBindingsBatch", "query", input),
275900
+ getAllBindings: (input) => dispatch("deviceManager", "getAllBindings", "query", input),
275171
275901
  listWrappersForCap: (input) => dispatch("deviceManager", "listWrappersForCap", "query", input),
275172
275902
  listBindableCapsForDeviceType: (input) => dispatch("deviceManager", "listBindableCapsForDeviceType", "query", input),
275173
275903
  discoverDevices: (input) => dispatch("deviceManager", "discoverDevices", "mutation", input),
@@ -275613,6 +276343,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275613
276343
  var NC_AUDIO_HIT_PERCENT_MAX = 100;
275614
276344
  var NC_AUDIO_SAMPLING_MIN_SEC = 1;
275615
276345
  var NC_AUDIO_SAMPLING_MAX_SEC = 300;
276346
+ var NC_AUDIO_CONFIRM_HITS_DEFAULT = 2;
276347
+ var NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT = 5;
276348
+ var NC_AUDIO_CONFIRM_HITS_MIN = 1;
276349
+ var NC_AUDIO_CONFIRM_HITS_MAX = 20;
276350
+ var NC_AUDIO_CONFIRM_WINDOW_MIN_SEC = 1;
276351
+ var NC_AUDIO_CONFIRM_WINDOW_MAX_SEC = 60;
275616
276352
  var NC_AUDIO_DEFAULTS = {
275617
276353
  hitPercent: 60,
275618
276354
  samplingSeconds: 10
@@ -275649,7 +276385,15 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275649
276385
  ...labels !== void 0 ? { labels: [...labels] } : {},
275650
276386
  ...dbThreshold !== void 0 ? { dbThreshold: clampInt(dbThreshold, NC_AUDIO_DB_MIN, 0) } : {},
275651
276387
  hitPercent: clampInt(patch.hitPercent ?? base.hitPercent, 1, 100),
275652
- samplingSeconds: clampInt(patch.samplingSeconds ?? base.samplingSeconds, 1, 300)
276388
+ samplingSeconds: clampInt(patch.samplingSeconds ?? base.samplingSeconds, 1, 300),
276389
+ ...(() => {
276390
+ const hits = has(patch, "confirmHits") ? patch.confirmHits : base.confirmHits;
276391
+ const windowSec = has(patch, "confirmWindowSec") ? patch.confirmWindowSec : base.confirmWindowSec;
276392
+ return {
276393
+ ...hits !== void 0 ? { confirmHits: clampInt(hits, 1, 20) } : {},
276394
+ ...windowSec !== void 0 ? { confirmWindowSec: clampInt(windowSec, 1, 60) } : {}
276395
+ };
276396
+ })()
275653
276397
  };
275654
276398
  }
275655
276399
  function audioLabelChoices(taxonomy, selected) {
@@ -278233,6 +278977,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278233
278977
  exports.AlertSourceSchema = AlertSourceSchema;
278234
278978
  exports.AlertStatusSchema = AlertStatusSchema;
278235
278979
  exports.AmbientLightSensorStatusSchema = AmbientLightSensorStatusSchema;
278980
+ exports.AnalyticsGroupDetailSchema = AnalyticsGroupDetailSchema;
278981
+ exports.AnalyticsGroupMemberSchema = AnalyticsGroupMemberSchema;
278982
+ exports.AnalyticsGroupRecordSchema = AnalyticsGroupRecordSchema;
278236
278983
  exports.ApiKeyRecordSchema = ApiKeyRecordSchema;
278237
278984
  exports.ApiKeySummarySchema = ApiKeySummarySchema;
278238
278985
  exports.ArchiveEntrySchema = ArchiveEntrySchema;
@@ -278576,6 +279323,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278576
279323
  exports.LawnMowerControlStatusSchema = LawnMowerControlStatusSchema;
278577
279324
  exports.LinkedDeviceSchema = LinkedDeviceSchema;
278578
279325
  exports.LinkedDevicesModeSchema = LinkedDevicesModeSchema;
279326
+ exports.ListGroupsPageSchema = ListGroupsPageSchema;
279327
+ exports.ListGroupsQueryInput = ListGroupsQueryInput;
278579
279328
  exports.LlmDefaultSchema = LlmDefaultSchema;
278580
279329
  exports.LlmDefaultSelectorSchema = LlmDefaultSelectorSchema;
278581
279330
  exports.LlmDownloadProgressSchema = LlmDownloadProgressSchema;
@@ -278619,6 +279368,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278619
279368
  exports.METHOD_ACCESS_MAP = METHOD_ACCESS_MAP;
278620
279369
  exports.METHOD_DEVICE_SELECTORS = METHOD_DEVICE_SELECTORS;
278621
279370
  exports.MODEL_FORMATS = MODEL_FORMATS;
279371
+ exports.MODEL_PROVIDER_IDS = MODEL_PROVIDER_IDS;
278622
279372
  exports.MOTION_TRIGGER_FEATURE = MOTION_TRIGGER_FEATURE;
278623
279373
  exports.ManagedModelCatalogEntrySchema = ManagedModelCatalogEntrySchema;
278624
279374
  exports.ManagedModelExtraFileSchema = ManagedModelExtraFileSchema;
@@ -278649,6 +279399,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278649
279399
  exports.ModelExtraFileSchema = ModelExtraFileSchema;
278650
279400
  exports.ModelFormatEntrySchema = ModelFormatEntrySchema;
278651
279401
  exports.ModelFormatsSchema = ModelFormatsSchema;
279402
+ exports.ModelProviderIdSchema = ModelProviderIdSchema;
278652
279403
  exports.ModelSubstitutionSchema = ModelSubstitutionSchema;
278653
279404
  exports.ModelVariantGroupSchema = ModelVariantGroupSchema;
278654
279405
  exports.MotionAnalysisResultSchema = MotionAnalysisResultSchema;
@@ -278678,6 +279429,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
278678
279429
  exports.NATIVE_LEASE_TILE_BUDGET_FIELD = NATIVE_LEASE_TILE_BUDGET_FIELD;
278679
279430
  exports.NATIVE_LEASE_TILE_BUDGET_KEY = NATIVE_LEASE_TILE_BUDGET_KEY;
278680
279431
  exports.NC_ALARM_SYSTEM_EVENT_KINDS = NC_ALARM_SYSTEM_EVENT_KINDS;
279432
+ exports.NC_AUDIO_CONFIRM_HITS_DEFAULT = NC_AUDIO_CONFIRM_HITS_DEFAULT;
279433
+ exports.NC_AUDIO_CONFIRM_HITS_MAX = NC_AUDIO_CONFIRM_HITS_MAX;
279434
+ exports.NC_AUDIO_CONFIRM_HITS_MIN = NC_AUDIO_CONFIRM_HITS_MIN;
279435
+ exports.NC_AUDIO_CONFIRM_WINDOW_MAX_SEC = NC_AUDIO_CONFIRM_WINDOW_MAX_SEC;
279436
+ exports.NC_AUDIO_CONFIRM_WINDOW_MIN_SEC = NC_AUDIO_CONFIRM_WINDOW_MIN_SEC;
279437
+ exports.NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT = NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT;
278681
279438
  exports.NC_AUDIO_DBFS_FLOOR = NC_AUDIO_DBFS_FLOOR;
278682
279439
  exports.NC_AUDIO_DB_MAX = NC_AUDIO_DB_MAX;
278683
279440
  exports.NC_AUDIO_DB_MIN = NC_AUDIO_DB_MIN;
@@ -279216,6 +279973,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
279216
279973
  exports.createDeviceProxy = require_sleep.createDeviceProxy;
279217
279974
  exports.createDurableState = require_sleep.createDurableState;
279218
279975
  exports.createEvent = require_sleep.createEvent;
279976
+ exports.createEventBusSliceSource = require_sleep.createEventBusSliceSource;
279219
279977
  exports.createExpressionScope = createExpressionScope;
279220
279978
  exports.createHwAccelCache = createHwAccelCache;
279221
279979
  exports.createLazyTrpcSource = require_sleep.createLazyTrpcSource;
@@ -279298,6 +280056,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
279298
280056
  exports.hydrateSchema = require_sleep.hydrateSchema;
279299
280057
  exports.imageCapability = imageCapability;
279300
280058
  exports.imageSettingsCapability = imageSettingsCapability;
280059
+ exports.inferModelProvider = inferModelProvider;
279301
280060
  exports.initialPoolMemoryState = initialPoolMemoryState;
279302
280061
  exports.integrationsCapability = integrationsCapability;
279303
280062
  exports.intercomCapability = intercomCapability;
@@ -404548,90 +405307,127 @@ var require_addon_registry_service = __commonJS({
404548
405307
  return entry?.packageName === "@camstack/system" && entry.declaration !== void 0 && (0, types_1.isIsolatedBuiltin)(entry.declaration);
404549
405308
  });
404550
405309
  const isolatedBuiltins = new Set(isolatedBuiltinIds);
404551
- await spawnRunnerPlan(this.buildAddonGroupPlan(allIds.filter((id) => !isolatedBuiltins.has(id))));
405310
+ const { infra: isolatedInfraIds, consumers: isolatedConsumerIds } = (0, system_1.partitionIsolatedBuiltinIds)(isolatedBuiltinIds, (id) => {
405311
+ const entry = this.addonEntries.get(id);
405312
+ return entry?.declaredCapabilities ?? [];
405313
+ });
404552
405314
  const isCoreBuiltin = (id) => this.addonEntries.get(id)?.packageName === "@camstack/system" && !isolatedBuiltins.has(id);
404553
- for (const infra of system_1.INFRA_CAPABILITIES) {
404554
- const addonId = this.findAddonForCapability(infra.name, allIds);
404555
- if (addonId) {
404556
- const entry = this.addonEntries.get(addonId);
404557
- if (!entry || entry.initialized || !isCoreBuiltin(addonId))
404558
- continue;
405315
+ await (0, system_1.runHubAddonBoot)({
405316
+ spawnIsolatedInfra: async () => {
405317
+ if (isolatedInfraIds.length === 0)
405318
+ return;
405319
+ this.logger.info("Spawning isolated infrastructure builtins", {
405320
+ meta: { addonIds: isolatedInfraIds }
405321
+ });
405322
+ await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedInfraIds));
405323
+ },
405324
+ waitForDataStoreProvider: async () => {
405325
+ if (isolatedInfraIds.length === 0)
405326
+ return;
404559
405327
  try {
404560
- await this.initializeAddon(addonId);
404561
- this.wireCapabilities(addonId);
404562
- } catch (error) {
404563
- const msg = (0, types_1.errMsg)(error);
404564
- this.emitAddonLifecycleEvent("addon.error", addonId, {
404565
- error: msg,
404566
- phase: "init"
405328
+ await (0, system_1.waitUntilReady)(() => this.capabilityRegistry.getCollection("data-store-provider").length > 0, {
405329
+ timeoutMs: 3e4,
405330
+ intervalMs: 50,
405331
+ what: "isolated data-store-provider engine"
404567
405332
  });
404568
- if (infra.required) {
404569
- throw new Error(`Required infrastructure addon "${addonId}" failed: ${msg}`, {
404570
- cause: error
404571
- });
404572
- }
404573
- this.logger.warn("Optional infra addon failed -- continuing", {
404574
- tags: { addonId },
404575
- meta: { error: msg }
405333
+ } catch (err) {
405334
+ this.logger.error("Isolated data-store-provider engine did not register in time", {
405335
+ meta: { error: (0, types_1.errMsg)(err), addonIds: isolatedInfraIds }
404576
405336
  });
404577
405337
  }
404578
- } else if (infra.required) {
404579
- throw new Error(`No addon provides required infrastructure capability "${infra.name}"`);
404580
- }
404581
- }
404582
- const bootOrder = this.capabilityRegistry.getBootOrder();
404583
- const infraNames = new Set(system_1.INFRA_CAPABILITIES.map((c) => c.name));
404584
- for (const capName of bootOrder) {
404585
- if (infraNames.has(capName))
404586
- continue;
404587
- for (const id of allIds) {
404588
- const entry = this.addonEntries.get(id);
404589
- if (!entry || entry.initialized || !isCoreBuiltin(id))
404590
- continue;
404591
- const provides = this.getAddonCapabilities(entry.addon);
404592
- if (!provides.some((c) => c.name === capName))
404593
- continue;
404594
- try {
404595
- await this.initializeAddon(id);
404596
- this.wireCapabilities(id);
404597
- } catch (error) {
404598
- const msg = (0, types_1.errMsg)(error);
404599
- this.emitAddonLifecycleEvent("addon.error", id, {
404600
- error: msg,
404601
- phase: "init"
404602
- });
404603
- this.logger.error("Core builtin failed to initialize -- skipping", {
404604
- tags: { addonId: id },
404605
- meta: { error: msg }
404606
- });
405338
+ },
405339
+ bootInProcessInfra: async () => {
405340
+ for (const infra of system_1.INFRA_CAPABILITIES) {
405341
+ const addonId = this.findAddonForCapability(infra.name, allIds);
405342
+ if (addonId) {
405343
+ const entry = this.addonEntries.get(addonId);
405344
+ if (!entry || entry.initialized || !isCoreBuiltin(addonId))
405345
+ continue;
405346
+ try {
405347
+ await this.initializeAddon(addonId);
405348
+ this.wireCapabilities(addonId);
405349
+ } catch (error) {
405350
+ const msg = (0, types_1.errMsg)(error);
405351
+ this.emitAddonLifecycleEvent("addon.error", addonId, {
405352
+ error: msg,
405353
+ phase: "init"
405354
+ });
405355
+ if (infra.required) {
405356
+ throw new Error(`Required infrastructure addon "${addonId}" failed: ${msg}`, {
405357
+ cause: error
405358
+ });
405359
+ }
405360
+ this.logger.warn("Optional infra addon failed -- continuing", {
405361
+ tags: { addonId },
405362
+ meta: { error: msg }
405363
+ });
405364
+ }
405365
+ } else if (infra.required) {
405366
+ throw new Error(`No addon provides required infrastructure capability "${infra.name}"`);
405367
+ }
404607
405368
  }
404608
- }
404609
- }
404610
- for (const id of allIds) {
404611
- const entry = this.addonEntries.get(id);
404612
- if (entry && !entry.initialized && isCoreBuiltin(id)) {
404613
- try {
404614
- await this.initializeAddon(id);
404615
- this.wireCapabilities(id);
404616
- } catch (error) {
404617
- const msg = (0, types_1.errMsg)(error);
404618
- this.emitAddonLifecycleEvent("addon.error", id, {
404619
- error: msg,
404620
- phase: "init"
404621
- });
404622
- this.logger.error("Core builtin failed to initialize -- skipping", {
404623
- tags: { addonId: id },
404624
- meta: { error: msg }
404625
- });
405369
+ },
405370
+ spawnForkedAddons: async () => {
405371
+ await spawnRunnerPlan(this.buildAddonGroupPlan(allIds.filter((id) => !isolatedBuiltins.has(id))));
405372
+ },
405373
+ bootInProcessConsumers: async () => {
405374
+ const bootOrder = this.capabilityRegistry.getBootOrder();
405375
+ const infraNames = new Set(system_1.INFRA_CAPABILITIES.map((c) => c.name));
405376
+ for (const capName of bootOrder) {
405377
+ if (infraNames.has(capName))
405378
+ continue;
405379
+ for (const id of allIds) {
405380
+ const entry = this.addonEntries.get(id);
405381
+ if (!entry || entry.initialized || !isCoreBuiltin(id))
405382
+ continue;
405383
+ const provides = this.getAddonCapabilities(entry.addon);
405384
+ if (!provides.some((c) => c.name === capName))
405385
+ continue;
405386
+ try {
405387
+ await this.initializeAddon(id);
405388
+ this.wireCapabilities(id);
405389
+ } catch (error) {
405390
+ const msg = (0, types_1.errMsg)(error);
405391
+ this.emitAddonLifecycleEvent("addon.error", id, {
405392
+ error: msg,
405393
+ phase: "init"
405394
+ });
405395
+ this.logger.error("Core builtin failed to initialize -- skipping", {
405396
+ tags: { addonId: id },
405397
+ meta: { error: msg }
405398
+ });
405399
+ }
405400
+ }
405401
+ }
405402
+ for (const id of allIds) {
405403
+ const entry = this.addonEntries.get(id);
405404
+ if (entry && !entry.initialized && isCoreBuiltin(id)) {
405405
+ try {
405406
+ await this.initializeAddon(id);
405407
+ this.wireCapabilities(id);
405408
+ } catch (error) {
405409
+ const msg = (0, types_1.errMsg)(error);
405410
+ this.emitAddonLifecycleEvent("addon.error", id, {
405411
+ error: msg,
405412
+ phase: "init"
405413
+ });
405414
+ this.logger.error("Core builtin failed to initialize -- skipping", {
405415
+ tags: { addonId: id },
405416
+ meta: { error: msg }
405417
+ });
405418
+ }
405419
+ }
404626
405420
  }
405421
+ },
405422
+ spawnIsolatedConsumers: async () => {
405423
+ if (isolatedConsumerIds.length === 0)
405424
+ return;
405425
+ this.logger.info("Spawning isolated system builtins", {
405426
+ meta: { addonIds: isolatedConsumerIds }
405427
+ });
405428
+ await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedConsumerIds));
404627
405429
  }
404628
- }
404629
- if (isolatedBuiltinIds.length > 0) {
404630
- this.logger.info("Spawning isolated system builtins", {
404631
- meta: { addonIds: isolatedBuiltinIds }
404632
- });
404633
- await spawnRunnerPlan(this.buildAddonGroupPlan(isolatedBuiltinIds));
404634
- }
405430
+ });
404635
405431
  const initializedIds = [...this.addonEntries.entries()].filter(([, e]) => e.initialized).map(([id]) => id);
404636
405432
  this.logger.info("Addons initialized", {
404637
405433
  meta: { initializedCount: initializedIds.length, totalCount: this.addonEntries.size }
@@ -405894,12 +406690,13 @@ var require_addon_registry_service = __commonJS({
405894
406690
  if (syncStore) {
405895
406691
  this.configService.setSettingsStore(syncStore);
405896
406692
  } else {
405897
- 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" } });
406693
+ this.logger.info("settings-store engine is isolated \u2014 ConfigManager uses the async door, not a sync ISettingsStore", { meta: { addonId, phase: "v2" } });
405898
406694
  }
405899
406695
  this.storageService.setSettingsBackend(provider);
405900
406696
  const store = this.capabilityRegistry.getProviderByAddon("settings-store", addonId);
405901
406697
  if (!store)
405902
406698
  return;
406699
+ this.configService.setSettingsDoor(store);
405903
406700
  this.integrationRegistry = new system_1.IntegrationRegistry(store);
405904
406701
  void this.integrationRegistry.initialize().then(() => {
405905
406702
  this.logger.info("IntegrationRegistry initialized", { meta: { phase: "v2" } });
@@ -408373,15 +409170,15 @@ var require_moleculer_service = __commonJS({
408373
409170
  "../../server/backend/dist/core/moleculer/moleculer.service.js"(exports) {
408374
409171
  "use strict";
408375
409172
  Object.defineProperty(exports, "__esModule", { value: true });
408376
- exports.MoleculerService = void 0;
409173
+ exports.ChildManifestGate = exports.CHILD_MANIFEST_SKIP_SAMPLE = exports.MoleculerService = void 0;
408377
409174
  exports.childOwnerToken = childOwnerToken;
408378
409175
  exports.buildChildUdsManifest = buildChildUdsManifest;
408379
409176
  var node_crypto_1 = __require("crypto");
408380
409177
  var system_1 = require_dist3();
408381
409178
  var types_1 = require_dist9();
408382
- var agent_readiness_pull_js_1 = require_agent_readiness_pull();
408383
409179
  var cap_router_runtime_js_1 = require_cap_router_runtime();
408384
409180
  var core_cap_bridge_js_1 = require_core_cap_bridge();
409181
+ var agent_readiness_pull_js_1 = require_agent_readiness_pull();
408385
409182
  var cap_call_fn_js_1 = require_cap_call_fn();
408386
409183
  var cap_route_authority_js_1 = require_cap_route_authority();
408387
409184
  var MoleculerService = class _MoleculerService {
@@ -408416,6 +409213,12 @@ var require_moleculer_service = __commonJS({
408416
409213
  * See `docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md`.
408417
409214
  */
408418
409215
  nodeOwners = /* @__PURE__ */ new Map();
409216
+ /**
409217
+ * Skips the manifest rebuild for a child re-register that carries nothing new
409218
+ * — 246 of them in 30 minutes with zero respawns, measured live 2026-08-25.
409219
+ * See {@link ChildManifestGate}.
409220
+ */
409221
+ childManifestGate = new ChildManifestGate();
408419
409222
  /**
408420
409223
  * Fixed-period agent-readiness snapshot sweep (D8 reconcile) — repairs
408421
409224
  * agent-origin readiness deltas lost while the agent stayed connected.
@@ -408737,6 +409540,19 @@ var require_moleculer_service = __commonJS({
408737
409540
  const hubNodeId = this.brokerSafe.nodeID;
408738
409541
  const childNodeId = `${hubNodeId}/${child.childId}`;
408739
409542
  const params = buildChildUdsManifest(childNodeId, child.childId, child.caps);
409543
+ if (!this.childManifestGate.shouldApply(child.childId, child.incarnation, params)) {
409544
+ if (this.childManifestGate.sampleDue()) {
409545
+ logger.info("UDS child re-registered with an unchanged manifest \u2014 skipped", {
409546
+ meta: {
409547
+ nodeId: childNodeId,
409548
+ incarnation: child.incarnation,
409549
+ skipped: this.childManifestGate.skippedSince(),
409550
+ sampleEvery: exports.CHILD_MANIFEST_SKIP_SAMPLE
409551
+ }
409552
+ });
409553
+ }
409554
+ return;
409555
+ }
408740
409556
  this.onRegisterNode(params, childOwnerToken(childNodeId, child.incarnation));
408741
409557
  logger.info("UDS child registered \u2014 manifest applied", {
408742
409558
  meta: { nodeId: childNodeId, incarnation: child.incarnation }
@@ -408745,6 +409561,7 @@ var require_moleculer_service = __commonJS({
408745
409561
  registry.onChildGone((childId, incarnation) => {
408746
409562
  const hubNodeId = this.brokerSafe.nodeID;
408747
409563
  const childNodeId = `${hubNodeId}/${childId}`;
409564
+ this.childManifestGate.forget(childId);
408748
409565
  logger.info("UDS child gone \u2014 removing from registry", {
408749
409566
  meta: { childId, incarnation }
408750
409567
  });
@@ -408979,12 +409796,13 @@ var require_moleculer_service = __commonJS({
408979
409796
  if (!registry)
408980
409797
  return;
408981
409798
  const registryKeyFor = (addonId) => isLocalChild ? addonId : `${addonId}@${nodeId}`;
409799
+ const skipInfraFromRemote = (capName) => (0, system_1.isInfraCapability)(capName) && !isLocalChild;
408982
409800
  const appliedKeys = (manifest) => {
408983
409801
  const keys = /* @__PURE__ */ new Map();
408984
409802
  for (const addon of manifest) {
408985
409803
  const registryKey = registryKeyFor(addon.addonId);
408986
409804
  for (const capName of addon.capabilities) {
408987
- if ((0, system_1.isInfraCapability)(capName))
409805
+ if (skipInfraFromRemote(capName))
408988
409806
  continue;
408989
409807
  const capDef = registry.getDefinition(capName);
408990
409808
  if (!capDef)
@@ -409275,6 +410093,48 @@ var require_moleculer_service = __commonJS({
409275
410093
  function childOwnerToken(childNodeId, incarnation) {
409276
410094
  return `${childNodeId}#${incarnation}`;
409277
410095
  }
410096
+ exports.CHILD_MANIFEST_SKIP_SAMPLE = 25;
410097
+ function childManifestFingerprint(params) {
410098
+ const addons = params.addons.map((addon) => `${addon.addonId}:${[...addon.capabilities].sort().join(",")}`).sort();
410099
+ return `${params.nodeId}|${addons.join("|")}`;
410100
+ }
410101
+ var ChildManifestGate = class {
410102
+ applied = /* @__PURE__ */ new Map();
410103
+ skipped = 0;
410104
+ sinceSample = 0;
410105
+ /** True when this registration carries something the registry does not have. */
410106
+ shouldApply(childId, incarnation, params) {
410107
+ const fingerprint = childManifestFingerprint(params);
410108
+ const previous = this.applied.get(childId);
410109
+ if (previous !== void 0 && previous.incarnation === incarnation) {
410110
+ if (previous.fingerprint === fingerprint) {
410111
+ this.skipped += 1;
410112
+ this.sinceSample += 1;
410113
+ return false;
410114
+ }
410115
+ }
410116
+ this.applied.set(childId, { incarnation, fingerprint });
410117
+ return true;
410118
+ }
410119
+ /** Drop a child's record — its next register is a first register again. */
410120
+ forget(childId) {
410121
+ this.applied.delete(childId);
410122
+ }
410123
+ /** How many have been skipped since the last call. Reading RESETS it. */
410124
+ skippedSince() {
410125
+ const n = this.skipped;
410126
+ this.skipped = 0;
410127
+ return n;
410128
+ }
410129
+ /** True once every {@link CHILD_MANIFEST_SKIP_SAMPLE} skips. */
410130
+ sampleDue() {
410131
+ if (this.sinceSample < exports.CHILD_MANIFEST_SKIP_SAMPLE)
410132
+ return false;
410133
+ this.sinceSample = 0;
410134
+ return true;
410135
+ }
410136
+ };
410137
+ exports.ChildManifestGate = ChildManifestGate;
409278
410138
  function buildChildUdsManifest(nodeId, childId, caps) {
409279
410139
  const capsByAddon = /* @__PURE__ */ new Map();
409280
410140
  for (const cap of caps) {