@camstack/system 1.2.331 → 1.2.333

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.
Files changed (63) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/autotrack/index.js +1 -1
  10. package/dist/builtins/autotrack/index.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/camera-grid/index.js +1 -1
  14. package/dist/builtins/camera-grid/index.mjs +1 -1
  15. package/dist/builtins/composer/composer.addon.js +2 -2
  16. package/dist/builtins/composer/composer.addon.mjs +2 -2
  17. package/dist/builtins/console-logging/index.js +1 -1
  18. package/dist/builtins/console-logging/index.mjs +1 -1
  19. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  20. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  21. package/dist/builtins/device-manager/device-manager.addon.js +17 -2
  22. package/dist/builtins/device-manager/device-manager.addon.mjs +17 -2
  23. package/dist/builtins/device-manager/stale-wrapper-activations.d.ts +6 -0
  24. package/dist/builtins/hub-forwarder/index.js +1 -1
  25. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  26. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  27. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  28. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  29. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  30. package/dist/builtins/local-network/local-network.addon.js +1 -1
  31. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  32. package/dist/builtins/loki-logging/index.js +1 -1
  33. package/dist/builtins/loki-logging/index.mjs +1 -1
  34. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  35. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  36. package/dist/builtins/platform-probe/index.js +1 -1
  37. package/dist/builtins/platform-probe/index.mjs +1 -1
  38. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  39. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  40. package/dist/builtins/snapshot/index.js +1 -1
  41. package/dist/builtins/snapshot/index.mjs +1 -1
  42. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  43. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  44. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  45. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  46. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  47. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  48. package/dist/builtins/system-config/system-config.addon.js +1 -1
  49. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  50. package/dist/builtins/winston-logging/index.js +1 -1
  51. package/dist/builtins/winston-logging/index.mjs +1 -1
  52. package/dist/{child-cap-dispatch-kLIiU1CG.mjs → child-cap-dispatch-DZBRtBiY.mjs} +39 -0
  53. package/dist/{child-cap-dispatch-93MfsaZL.js → child-cap-dispatch-D_vavR92.js} +39 -0
  54. package/dist/{composition-sources-BXZorHDO.js → composition-sources-BOmLYV5s.js} +1 -1
  55. package/dist/{composition-sources-aEEer5gE.mjs → composition-sources-pkS2rTOz.mjs} +1 -1
  56. package/dist/{dist-DRUzy1SF.js → dist-Dl2VFsPg.js} +112 -16
  57. package/dist/{dist-CoG8lY6H.mjs → dist-DxkeG_0w.mjs} +112 -16
  58. package/dist/index.js +2 -2
  59. package/dist/index.mjs +2 -2
  60. package/dist/kernel/transport/local-child-registry.d.ts +30 -0
  61. package/dist/{retired-settings-keys-BcJDpASY.mjs → retired-settings-keys-BPWzEXW3.mjs} +1 -1
  62. package/dist/{retired-settings-keys-BY9H1I2b.js → retired-settings-keys-D1iqJKR8.js} +1 -1
  63. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
+ const require_dist = require("./dist-Dl2VFsPg.js");
2
3
  const require_proc_stat = require("./proc-stat-DL-WUOhl.js");
3
4
  require("./hub-cap-forward-DmHNjbB0.js");
4
5
  let node_crypto = require("node:crypto");
@@ -8527,6 +8528,11 @@ async function answerClaimedGetStatus(resolve, call) {
8527
8528
  if (answer.kind === "unclaimed") return null;
8528
8529
  return { slice: answer.kind === "claimed" ? answer.slice : null };
8529
8530
  }
8531
+ /** The source every runner lifecycle event this registry emits carries. */
8532
+ var LIFECYCLE_SOURCE = {
8533
+ type: "core",
8534
+ id: "local-child-registry"
8535
+ };
8530
8536
  function readFanoutMode() {
8531
8537
  const raw = process.env.CAMSTACK_UDS_EVENT_FANOUT;
8532
8538
  if (raw === "shadow" || raw === "broadcast") return raw;
@@ -8557,6 +8563,9 @@ var LocalChildRegistry = class {
8557
8563
  server;
8558
8564
  onUnownedCall;
8559
8565
  logger;
8566
+ lifecycleEvents;
8567
+ /** Per childId: the incarnation `WorkerOnline` was last said for. */
8568
+ announcedIncarnation = /* @__PURE__ */ new Map();
8560
8569
  getActiveSingletonAddonId;
8561
8570
  resolveChildIdForAddon;
8562
8571
  /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
@@ -8618,6 +8627,7 @@ var LocalChildRegistry = class {
8618
8627
  this.server = opts.server;
8619
8628
  this.onUnownedCall = opts.onUnownedCall;
8620
8629
  this.logger = opts.logger;
8630
+ this.lifecycleEvents = opts.lifecycleEvents;
8621
8631
  this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
8622
8632
  this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
8623
8633
  this.ownNodeId = opts.ownNodeId;
@@ -9132,6 +9142,33 @@ var LocalChildRegistry = class {
9132
9142
  async close() {
9133
9143
  await this.server.close();
9134
9144
  }
9145
+ /** `WorkerOnline`, once per incarnation: a re-register of the same connection says nothing. */
9146
+ announceOnline(childId, incarnation) {
9147
+ const events = this.lifecycleEvents;
9148
+ if (events === void 0 || this.announcedIncarnation.get(childId) === incarnation) return;
9149
+ this.announcedIncarnation.set(childId, incarnation);
9150
+ const workerId = `${events.parentNodeId()}/${childId}`;
9151
+ this.emitLifecycle(events, require_dist.createEvent(require_dist.EventCategory.WorkerOnline, LIFECYCLE_SOURCE, { workerId }), incarnation);
9152
+ }
9153
+ /** `WorkerOffline` for the LIVE connection's close (a superseded close never reaches here). */
9154
+ announceOffline(childId, incarnation) {
9155
+ const events = this.lifecycleEvents;
9156
+ if (events === void 0) return;
9157
+ this.announcedIncarnation.delete(childId);
9158
+ const workerId = `${events.parentNodeId()}/${childId}`;
9159
+ this.emitLifecycle(events, require_dist.createEvent(require_dist.EventCategory.WorkerOffline, LIFECYCLE_SOURCE, { workerId }), incarnation);
9160
+ }
9161
+ emitLifecycle(events, event, incarnation) {
9162
+ try {
9163
+ events.emit(event);
9164
+ } catch (err) {
9165
+ this.logger?.info("runner lifecycle event could not be emitted", {
9166
+ category: event.category,
9167
+ incarnation,
9168
+ error: err instanceof Error ? err.message : String(err)
9169
+ });
9170
+ }
9171
+ }
9135
9172
  onConnection(channel) {
9136
9173
  let childId = null;
9137
9174
  const incarnation = this.nextIncarnation++;
@@ -9187,6 +9224,7 @@ var LocalChildRegistry = class {
9187
9224
  });
9188
9225
  this.invalidateCapIndex();
9189
9226
  this.logPatternSet(msg.childId, eventPatterns);
9227
+ this.announceOnline(msg.childId, incarnation);
9190
9228
  this.registeredHandler({
9191
9229
  childId: msg.childId,
9192
9230
  caps: msg.caps,
@@ -9286,6 +9324,7 @@ var LocalChildRegistry = class {
9286
9324
  this.actionCensus.forget(childId);
9287
9325
  this.loggedPatternSet.delete(childId);
9288
9326
  this.goneHandler(childId, incarnation);
9327
+ this.announceOffline(childId, incarnation);
9289
9328
  });
9290
9329
  }
9291
9330
  };
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DRUzy1SF.js");
1
+ const require_dist = require("./dist-Dl2VFsPg.js");
2
2
  //#region src/builtins/core-blocks/composition-sources.ts
3
3
  /**
4
4
  * Describe what a composition reads and writes for SAVE-time validation
@@ -1,4 +1,4 @@
1
- import { Hn as errMsg, In as compositionSourceKey } from "./dist-CoG8lY6H.mjs";
1
+ import { Hn as errMsg, In as compositionSourceKey } from "./dist-DxkeG_0w.mjs";
2
2
  //#region src/builtins/core-blocks/composition-sources.ts
3
3
  /**
4
4
  * Describe what a composition reads and writes for SAVE-time validation
@@ -14746,7 +14746,17 @@ function siteZoneKey(label) {
14746
14746
  var ProviderStatusSchema = zod.z.object({
14747
14747
  connected: zod.z.boolean(),
14748
14748
  deviceCount: zod.z.number(),
14749
- error: zod.z.string().optional()
14749
+ error: zod.z.string().optional(),
14750
+ /**
14751
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14752
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14753
+ * which every provider bundles, so only a provider BUILT from D696-amended
14754
+ * code says it. ABSENT means an older provider that may still write it (raw
14755
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14756
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14757
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14758
+ */
14759
+ motionSliceWriter: zod.z.literal("orchestrator").optional()
14750
14760
  });
14751
14761
  zod.z.object({
14752
14762
  externalId: zod.z.string(),
@@ -21396,6 +21406,37 @@ zod.z.object({
21396
21406
  firstAt: zod.z.number(),
21397
21407
  lastAt: zod.z.number()
21398
21408
  });
21409
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
21410
+ var NcAlarmDelaySecSchema = zod.z.number().int().min(0).max(600);
21411
+ var NcAlarmTriggeredSecSchema = zod.z.number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
21412
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
21413
+ /** One mode's OVERRIDES. An absent field inherits the global value (D697). */
21414
+ var NcAlarmModeDelaysSchema = zod.z.object({
21415
+ mode: AlarmArmModeSchema,
21416
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
21417
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
21418
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
21419
+ });
21420
+ var NcAlarmModeDelaysListSchema = zod.z.array(NcAlarmModeDelaysSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
21421
+ /**
21422
+ * One mode's EDIT in a patch: a number sets the override, `null` removes it (the mode inherits
21423
+ * again), an absent field leaves it alone. Per field, so two editors changing two different
21424
+ * delays of one mode never undo each other.
21425
+ */
21426
+ var NcAlarmModeDelaysEditSchema = zod.z.object({
21427
+ mode: AlarmArmModeSchema,
21428
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21429
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21430
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
21431
+ });
21432
+ var NcAlarmModeDelaysEditListSchema = zod.z.array(NcAlarmModeDelaysEditSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
21433
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
21434
+ var NcAlarmNonBlockingEditSchema = zod.z.object({
21435
+ mode: AlarmArmModeSchema,
21436
+ deviceId: zod.z.number().int().positive(),
21437
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
21438
+ nonBlocking: zod.z.boolean()
21439
+ });
21399
21440
  /**
21400
21441
  * One arm mode's non-blocking list: devices that may be open when that mode
21401
21442
  * arms, without the arm being refused.
@@ -21409,10 +21450,10 @@ var NcAlarmNonBlockingSchema = zod.z.object({
21409
21450
  * meaning a reader could agree on (union? the last one?), so they are refused
21410
21451
  * at the boundary rather than interpreted.
21411
21452
  */
21412
- var NcAlarmNonBlockingListSchema = zod.z.array(NcAlarmNonBlockingSchema).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
21453
+ var NcAlarmNonBlockingListSchema = zod.z.array(NcAlarmNonBlockingSchema).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
21413
21454
  /**
21414
- * The three durations the panel's state machine runs on, who hears about its
21415
- * transitions, and which openings each mode tolerates.
21455
+ * The three durations — global, and per mode since D697 — the panel's state
21456
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
21416
21457
  *
21417
21458
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
21418
21459
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -21422,15 +21463,15 @@ var NcAlarmNonBlockingListSchema = zod.z.array(NcAlarmNonBlockingSchema).max(8).
21422
21463
  */
21423
21464
  var NcAlarmSettingsSchema = zod.z.object({
21424
21465
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
21425
- exitDelaySec: zod.z.number().int().min(0).max(600),
21466
+ exitDelaySec: NcAlarmDelaySecSchema,
21426
21467
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
21427
- entryDelaySec: zod.z.number().int().min(0).max(600),
21468
+ entryDelaySec: NcAlarmDelaySecSchema,
21428
21469
  /**
21429
21470
  * How long `triggered` lasts before the panel re-arms itself.
21430
21471
  * **0 = until an operator disarms it** — the behaviour before this field
21431
21472
  * existed, and therefore what an untouched install keeps doing.
21432
21473
  */
21433
- triggeredDurationSec: zod.z.number().int().min(0).max(3600),
21474
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
21434
21475
  /**
21435
21476
  * Deprecated by D630 — every transition is announced. Parsed, never read;
21436
21477
  * remove after one release. Optional so an older admin's patch (which still
@@ -21453,17 +21494,30 @@ var NcAlarmSettingsSchema = zod.z.object({
21453
21494
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
21454
21495
  * parses as "every opening blocks" — the behaviour it was written under.
21455
21496
  */
21456
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
21497
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
21498
+ /**
21499
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
21500
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
21501
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
21502
+ */
21503
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
21457
21504
  });
21458
21505
  /**
21459
21506
  * Every field optional — a tab edits one control at a time.
21460
21507
  *
21461
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
21462
- * remove an inner `.default()`, so a patch that never named the field would
21463
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
21464
- * (the same trap {@link NcRulePatchSchema} documents).
21508
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
21509
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
21510
+ * named the field would parse to `[]` and wipe every mode's list on an
21511
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
21512
+ * `modeDelays` means EDITS, not the stored overrides.
21465
21513
  */
21466
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
21514
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
21515
+ nonBlocking: NcAlarmNonBlockingListSchema,
21516
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
21517
+ modeDelays: NcAlarmModeDelaysEditListSchema,
21518
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
21519
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
21520
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
21467
21521
  /**
21468
21522
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
21469
21523
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -21563,6 +21617,28 @@ var NcAlarmConfigSchema = zod.z.object({
21563
21617
  */
21564
21618
  live: NcAlarmLiveSchema.optional()
21565
21619
  });
21620
+ var NcAlarmSensorReadingSchema = zod.z.enum([
21621
+ "open",
21622
+ "closed",
21623
+ "unknown",
21624
+ "not-opening"
21625
+ ]);
21626
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
21627
+ var NcAlarmSensorStateSchema = zod.z.object({
21628
+ deviceId: zod.z.number().int().positive(),
21629
+ reading: NcAlarmSensorReadingSchema,
21630
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
21631
+ state: zod.z.string().nullable(),
21632
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
21633
+ unknownWhy: zod.z.enum(["read-failed", "unknown-word"]).nullable(),
21634
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
21635
+ online: zod.z.boolean().nullable()
21636
+ });
21637
+ var NcAlarmSensorsInputSchema = zod.z.object({ deviceIds: zod.z.array(zod.z.number().int().positive()).max(500) });
21638
+ var NcAlarmSensorsSchema = zod.z.object({
21639
+ sensors: zod.z.array(NcAlarmSensorStateSchema),
21640
+ readAt: zod.z.number().int().nonnegative()
21641
+ });
21566
21642
  /**
21567
21643
  * ONE rule's demand on ONE camera's clip ring.
21568
21644
  *
@@ -21804,8 +21880,9 @@ var notificationRulesCapability = {
21804
21880
  */
21805
21881
  getAlarmConfig: method(zod.z.object({}), NcAlarmConfigSchema, { auth: "admin" }),
21806
21882
  /**
21807
- * Patch the settings (durations, recipients, per-mode non-blocking lists;
21808
- * `announceArm` is accepted and ignored — D630). Returns the WHOLE config,
21883
+ * Patch the settings (durations — global and per mode —, recipients,
21884
+ * per-mode non-blocking lists or one membership edit; `announceArm` is
21885
+ * accepted and ignored — D630). Returns the WHOLE config,
21809
21886
  * coverage and `live` included, so a
21810
21887
  * client never has to guess what the server settled on — the panel clamps
21811
21888
  * and normalises, and a form that re-rendered from its own input would
@@ -21814,7 +21891,15 @@ var notificationRulesCapability = {
21814
21891
  setAlarmConfig: method(zod.z.object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
21815
21892
  kind: "mutation",
21816
21893
  auth: "admin"
21817
- })
21894
+ }),
21895
+ /**
21896
+ * The CURRENT state of each asked device as the alarm reads it (D697) — open, closed,
21897
+ * unknown (why) or not an opening, plus liveness. Classified by the same table the arm
21898
+ * check uses (`alarm-openings.ts`), so the editor and the arm can never disagree. The
21899
+ * caller names the ids (the household openings it already holds); at most
21900
+ * `NC_ALARM_SENSORS_MAX`.
21901
+ */
21902
+ getAlarmSensors: method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" })
21818
21903
  }
21819
21904
  };
21820
21905
  /**
@@ -51187,6 +51272,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
51187
51272
  addonId: null,
51188
51273
  access: "view"
51189
51274
  },
51275
+ "notificationRules.getAlarmSensors": {
51276
+ capName: "notification-rules",
51277
+ capScope: "system",
51278
+ addonId: null,
51279
+ access: "view"
51280
+ },
51190
51281
  "notificationRules.getClipRetentionAsks": {
51191
51282
  capName: "notification-rules",
51192
51283
  capScope: "system",
@@ -55670,6 +55761,11 @@ Object.freeze({
55670
55761
  form: "single",
55671
55762
  optional: false
55672
55763
  }],
55764
+ "notificationRules.getAlarmSensors": [{
55765
+ name: "deviceIds",
55766
+ form: "array",
55767
+ optional: false
55768
+ }],
55673
55769
  "notificationRules.setDeviceMuted": [{
55674
55770
  name: "deviceId",
55675
55771
  form: "single",
@@ -14746,7 +14746,17 @@ function siteZoneKey(label) {
14746
14746
  var ProviderStatusSchema = z.object({
14747
14747
  connected: z.boolean(),
14748
14748
  deviceCount: z.number(),
14749
- error: z.string().optional()
14749
+ error: z.string().optional(),
14750
+ /**
14751
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14752
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14753
+ * which every provider bundles, so only a provider BUILT from D696-amended
14754
+ * code says it. ABSENT means an older provider that may still write it (raw
14755
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14756
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14757
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14758
+ */
14759
+ motionSliceWriter: z.literal("orchestrator").optional()
14750
14760
  });
14751
14761
  z.object({
14752
14762
  externalId: z.string(),
@@ -21396,6 +21406,37 @@ z.object({
21396
21406
  firstAt: z.number(),
21397
21407
  lastAt: z.number()
21398
21408
  });
21409
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
21410
+ var NcAlarmDelaySecSchema = z.number().int().min(0).max(600);
21411
+ var NcAlarmTriggeredSecSchema = z.number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
21412
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
21413
+ /** One mode's OVERRIDES. An absent field inherits the global value (D697). */
21414
+ var NcAlarmModeDelaysSchema = z.object({
21415
+ mode: AlarmArmModeSchema,
21416
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
21417
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
21418
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
21419
+ });
21420
+ var NcAlarmModeDelaysListSchema = z.array(NcAlarmModeDelaysSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
21421
+ /**
21422
+ * One mode's EDIT in a patch: a number sets the override, `null` removes it (the mode inherits
21423
+ * again), an absent field leaves it alone. Per field, so two editors changing two different
21424
+ * delays of one mode never undo each other.
21425
+ */
21426
+ var NcAlarmModeDelaysEditSchema = z.object({
21427
+ mode: AlarmArmModeSchema,
21428
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21429
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21430
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
21431
+ });
21432
+ var NcAlarmModeDelaysEditListSchema = z.array(NcAlarmModeDelaysEditSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
21433
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
21434
+ var NcAlarmNonBlockingEditSchema = z.object({
21435
+ mode: AlarmArmModeSchema,
21436
+ deviceId: z.number().int().positive(),
21437
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
21438
+ nonBlocking: z.boolean()
21439
+ });
21399
21440
  /**
21400
21441
  * One arm mode's non-blocking list: devices that may be open when that mode
21401
21442
  * arms, without the arm being refused.
@@ -21409,10 +21450,10 @@ var NcAlarmNonBlockingSchema = z.object({
21409
21450
  * meaning a reader could agree on (union? the last one?), so they are refused
21410
21451
  * at the boundary rather than interpreted.
21411
21452
  */
21412
- var NcAlarmNonBlockingListSchema = z.array(NcAlarmNonBlockingSchema).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
21453
+ var NcAlarmNonBlockingListSchema = z.array(NcAlarmNonBlockingSchema).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
21413
21454
  /**
21414
- * The three durations the panel's state machine runs on, who hears about its
21415
- * transitions, and which openings each mode tolerates.
21455
+ * The three durations — global, and per mode since D697 — the panel's state
21456
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
21416
21457
  *
21417
21458
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
21418
21459
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -21422,15 +21463,15 @@ var NcAlarmNonBlockingListSchema = z.array(NcAlarmNonBlockingSchema).max(8).refi
21422
21463
  */
21423
21464
  var NcAlarmSettingsSchema = z.object({
21424
21465
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
21425
- exitDelaySec: z.number().int().min(0).max(600),
21466
+ exitDelaySec: NcAlarmDelaySecSchema,
21426
21467
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
21427
- entryDelaySec: z.number().int().min(0).max(600),
21468
+ entryDelaySec: NcAlarmDelaySecSchema,
21428
21469
  /**
21429
21470
  * How long `triggered` lasts before the panel re-arms itself.
21430
21471
  * **0 = until an operator disarms it** — the behaviour before this field
21431
21472
  * existed, and therefore what an untouched install keeps doing.
21432
21473
  */
21433
- triggeredDurationSec: z.number().int().min(0).max(3600),
21474
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
21434
21475
  /**
21435
21476
  * Deprecated by D630 — every transition is announced. Parsed, never read;
21436
21477
  * remove after one release. Optional so an older admin's patch (which still
@@ -21453,17 +21494,30 @@ var NcAlarmSettingsSchema = z.object({
21453
21494
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
21454
21495
  * parses as "every opening blocks" — the behaviour it was written under.
21455
21496
  */
21456
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
21497
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
21498
+ /**
21499
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
21500
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
21501
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
21502
+ */
21503
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
21457
21504
  });
21458
21505
  /**
21459
21506
  * Every field optional — a tab edits one control at a time.
21460
21507
  *
21461
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
21462
- * remove an inner `.default()`, so a patch that never named the field would
21463
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
21464
- * (the same trap {@link NcRulePatchSchema} documents).
21508
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
21509
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
21510
+ * named the field would parse to `[]` and wipe every mode's list on an
21511
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
21512
+ * `modeDelays` means EDITS, not the stored overrides.
21465
21513
  */
21466
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
21514
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
21515
+ nonBlocking: NcAlarmNonBlockingListSchema,
21516
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
21517
+ modeDelays: NcAlarmModeDelaysEditListSchema,
21518
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
21519
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
21520
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
21467
21521
  /**
21468
21522
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
21469
21523
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -21563,6 +21617,28 @@ var NcAlarmConfigSchema = z.object({
21563
21617
  */
21564
21618
  live: NcAlarmLiveSchema.optional()
21565
21619
  });
21620
+ var NcAlarmSensorReadingSchema = z.enum([
21621
+ "open",
21622
+ "closed",
21623
+ "unknown",
21624
+ "not-opening"
21625
+ ]);
21626
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
21627
+ var NcAlarmSensorStateSchema = z.object({
21628
+ deviceId: z.number().int().positive(),
21629
+ reading: NcAlarmSensorReadingSchema,
21630
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
21631
+ state: z.string().nullable(),
21632
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
21633
+ unknownWhy: z.enum(["read-failed", "unknown-word"]).nullable(),
21634
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
21635
+ online: z.boolean().nullable()
21636
+ });
21637
+ var NcAlarmSensorsInputSchema = z.object({ deviceIds: z.array(z.number().int().positive()).max(500) });
21638
+ var NcAlarmSensorsSchema = z.object({
21639
+ sensors: z.array(NcAlarmSensorStateSchema),
21640
+ readAt: z.number().int().nonnegative()
21641
+ });
21566
21642
  /**
21567
21643
  * ONE rule's demand on ONE camera's clip ring.
21568
21644
  *
@@ -21804,8 +21880,9 @@ var notificationRulesCapability = {
21804
21880
  */
21805
21881
  getAlarmConfig: method(z.object({}), NcAlarmConfigSchema, { auth: "admin" }),
21806
21882
  /**
21807
- * Patch the settings (durations, recipients, per-mode non-blocking lists;
21808
- * `announceArm` is accepted and ignored — D630). Returns the WHOLE config,
21883
+ * Patch the settings (durations — global and per mode —, recipients,
21884
+ * per-mode non-blocking lists or one membership edit; `announceArm` is
21885
+ * accepted and ignored — D630). Returns the WHOLE config,
21809
21886
  * coverage and `live` included, so a
21810
21887
  * client never has to guess what the server settled on — the panel clamps
21811
21888
  * and normalises, and a form that re-rendered from its own input would
@@ -21814,7 +21891,15 @@ var notificationRulesCapability = {
21814
21891
  setAlarmConfig: method(z.object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
21815
21892
  kind: "mutation",
21816
21893
  auth: "admin"
21817
- })
21894
+ }),
21895
+ /**
21896
+ * The CURRENT state of each asked device as the alarm reads it (D697) — open, closed,
21897
+ * unknown (why) or not an opening, plus liveness. Classified by the same table the arm
21898
+ * check uses (`alarm-openings.ts`), so the editor and the arm can never disagree. The
21899
+ * caller names the ids (the household openings it already holds); at most
21900
+ * `NC_ALARM_SENSORS_MAX`.
21901
+ */
21902
+ getAlarmSensors: method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" })
21818
21903
  }
21819
21904
  };
21820
21905
  /**
@@ -51187,6 +51272,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
51187
51272
  addonId: null,
51188
51273
  access: "view"
51189
51274
  },
51275
+ "notificationRules.getAlarmSensors": {
51276
+ capName: "notification-rules",
51277
+ capScope: "system",
51278
+ addonId: null,
51279
+ access: "view"
51280
+ },
51190
51281
  "notificationRules.getClipRetentionAsks": {
51191
51282
  capName: "notification-rules",
51192
51283
  capScope: "system",
@@ -55670,6 +55761,11 @@ Object.freeze({
55670
55761
  form: "single",
55671
55762
  optional: false
55672
55763
  }],
55764
+ "notificationRules.getAlarmSensors": [{
55765
+ name: "deviceIds",
55766
+ form: "array",
55767
+ optional: false
55768
+ }],
55673
55769
  "notificationRules.setDeviceMuted": [{
55674
55770
  name: "deviceId",
55675
55771
  form: "single",
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-DRUzy1SF.js");
3
+ const require_dist = require("./dist-Dl2VFsPg.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_builtins_composer_composer_addon = require("./builtins/composer/composer.addon.js");
@@ -29,7 +29,7 @@ require("./builtins/system-config/index.js");
29
29
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
30
30
  const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-ey4mbofz.js");
31
31
  const require_tls$1 = require("./tls-D_wUeOTD.js");
32
- const require_child_cap_dispatch = require("./child-cap-dispatch-93MfsaZL.js");
32
+ const require_child_cap_dispatch = require("./child-cap-dispatch-D_vavR92.js");
33
33
  const require_resource_monitor = require("./resource-monitor-DzNn_IZK.js");
34
34
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
35
35
  let zod = require("zod");
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { $n as createEvent, At as isArrayOutputSchema, C as LOG_LEVEL_RANK, E as METHOD_ACCESS_MAP, Ft as kebabToCamel, Gn as DEVICE_SETTINGS_CONTRIBUTION_METHODS, H as addonSettingsCapability, Hn as errMsg$1, Ht as logLevelAtMost, Jn as ReadinessTimeoutError, Kn as DEVICE_STATUS_METHOD, Nt as isObjectInput, Pt as isVoidInput, Qn as asString$1, Qt as objectInputDeclaresRequiredDeviceId, Rt as lifecycleJobSchema, Tt as extractNestedAddonId, Ut as looseSchema, Wn as DATAPLANE_SECRET_HEADER$1, Xn as asJsonObject$1, Zn as asNumber, Zt as objectInputDeclaresAddonId, cn as resolveMethodAuth, cr as parseJsonUnknown, dn as scopesAllowDeviceCap, dr as scopeKey, er as emitDownForOwnedCaps, j as RUNTIME_DEFAULTS, jt as isCollectionArrayMethod, lr as readinessKey, mr as EventCategory$1, nn as procedureAuthKey, nr as expandCapMethods, qn as ReadinessRegistry, sr as parseJsonObject, t as ALL_CAPABILITY_DEFINITIONS, un as scopesAllowAddon, ur as resolveCapMount } from "./dist-CoG8lY6H.mjs";
2
+ import { $n as createEvent, At as isArrayOutputSchema, C as LOG_LEVEL_RANK, E as METHOD_ACCESS_MAP, Ft as kebabToCamel, Gn as DEVICE_SETTINGS_CONTRIBUTION_METHODS, H as addonSettingsCapability, Hn as errMsg$1, Ht as logLevelAtMost, Jn as ReadinessTimeoutError, Kn as DEVICE_STATUS_METHOD, Nt as isObjectInput, Pt as isVoidInput, Qn as asString$1, Qt as objectInputDeclaresRequiredDeviceId, Rt as lifecycleJobSchema, Tt as extractNestedAddonId, Ut as looseSchema, Wn as DATAPLANE_SECRET_HEADER$1, Xn as asJsonObject$1, Zn as asNumber, Zt as objectInputDeclaresAddonId, cn as resolveMethodAuth, cr as parseJsonUnknown, dn as scopesAllowDeviceCap, dr as scopeKey, er as emitDownForOwnedCaps, j as RUNTIME_DEFAULTS, jt as isCollectionArrayMethod, lr as readinessKey, mr as EventCategory$1, nn as procedureAuthKey, nr as expandCapMethods, qn as ReadinessRegistry, sr as parseJsonObject, t as ALL_CAPABILITY_DEFINITIONS, un as scopesAllowAddon, ur as resolveCapMount } from "./dist-DxkeG_0w.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { ComposerAddon } from "./builtins/composer/composer.addon.mjs";
@@ -28,7 +28,7 @@ import "./builtins/system-config/index.mjs";
28
28
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
29
29
  import { _ as ensureModel, a as createFileDataPlaneHandler, c as parseRangeHeader, d as ModelDownloadService, g as downloadModel, h as downloadFile, i as startEventLoopStallMonitor, l as parseTokenizedUrl, m as deleteModelFromDisk, n as STALL_TICK_MS, o as contentTypeFor, p as collectModelFiles, r as attributeStall, s as createAuthenticatedFileServer, t as STALL_REPORT_MS, u as resolveFilePath, v as fetchJson, x as isModelDownloaded, y as getModelFilePath } from "./event-loop-stall-monitor-EXjzIxDz.mjs";
30
30
  import { C as registerLanHttpHandler, S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, b as bindPendingLanHttp, c as loadTlsCert, d as collectCertIdentity, f as CA_VALIDITY_DAYS, g as evaluateExistingCert, h as SERVER_AUTH_OID, i as writeExtraSans, l as reissueTlsLeaf, m as MAX_LEAF_VALIDITY_DAYS, n as readTlsAccessStatus, o as validateUploadedTls, p as LEAF_RENEWAL_WINDOW_DAYS, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, u as CA_COMMON_NAME, v as allFamiliesListenHost, x as closeLanHttp, y as applyLanHttp } from "./tls-IM-v7JV4.mjs";
31
- import { $ as classifyCapRoute, $n as EMPTY_CAP_ACTION_READING, $t as RUNNER_RSS_BUDGET_ENV, A as resolveHwAccel, An as OUTBOUND_QUEUE_SUSTAIN_MS, At as DeviceRegistry, B as udsChildLogToWorkerEntry, Bn as createSocketPlaneMeter, Bt as hostNodeIdOf, C as getBrokerEventBus, Cn as HEAP_SPACE_REPORT_MIN_MB, Ct as capActionName, D as subscribePassthrough, Dn as readHeapSpaces, Dt as parseCapAction, E as setNodeEventInterest, En as heapSpaceField, Et as capServiceName, F as ipcParentLink, Fn as createMeshQueueReader, Ft as resolveAddonClass, G as UDS_NO_ROUTE_PREFIX, Gn as EMPTY_SOCKET_DIRECTION, Gt as HEAP_WATCH_INTERVAL_MS, H as createUdsLoggerWithControl, Hn as diffSocketPlane, Ht as HEAP_RECLAIM_MIN_INTERVAL_MS, I as localProviderLink, In as formatMeshQueue, It as buildNpmChildEnv, J as deviceOfGetStatus, Jn as sampleSocketDirection, Jt as HUB_MAIN_RSS_BUDGET_MB, K as GET_STATUS_METHOD, Kn as createSocketDirectionCounters, Kt as HEAP_WATCH_WARN_RATIO, L as createParentUnownedCallHandler, Ln as EMPTY_SOCKET_PLANE_BASELINE, Lt as resolveNpmInvocation, M as brokerTransportLink, Mn as createOutboundQueueGate, Mt as CapabilityUnavailableError, N as buildLinkChain, Nn as formatOutboundQueueVerdict, Nt as copyBundledNativeModules, O as AddonDepsManager, On as selectReportedSpaces, Ot as deserializeTypedArrays, P as deviceCapResolverLink, Pn as MESH_QUEUE_TOP_N, Pt as installManifestNativeDeps, Q as CapRouteError, Qn as CAP_ACTION_UNLABELLED, Qt as RUNNER_HEAP_WATCH_INTERVAL_MS, R as createUdsEventBridge, Rn as SOCKET_PLANE_TOP_N, Rt as runNpm, S as clusterEventTopic, Sn as DECISIVE_HEAP_SPACES, St as NATIVE_PROVIDER_SERVICE_INFIX, T as registerEventBusService, Tn as formatHeapSpaces, Tt as capBareAction, U as LocalChildClient, Un as formatSocketPlane, Ut as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, V as createUdsLogger, Vn as createSocketPlaneReader, Vt as createAddonDataPlaneFacility, W as LocalChildRegistry, Wn as readSocketQueues, Wt as HEAP_RECLAIM_TRIGGER_MB, X as AGENT_CAP_FWD_SERVICE, Xn as socketDirectionMessages, Xt as RSS_BUDGET_REANNOUNCE_MIN_MS, Y as AGENT_CAP_FWD_ACTION, Yn as socketDirectionBytes, Yt as HUB_RSS_BUDGET_ENV, Z as CapRouteResolver, Zn as CAP_ACTION_OVERFLOW_LABEL, Zt as RSS_BUDGET_RELEASE_RATIO, _ as getWorkerDeviceRegistry, _n as ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO, a as reapProcessGroup, an as describeRss, ar as createEventPlaneMeter, at as getCapUsageRegistry, b as setHubConnected, bn as formatArrayBufferCensus, bt as createAddonService, c as runnerOwnsProcessGroup, cn as parseRssBudgetMb, cr as formatEventPlane, ct as UdsLocalTransportServer, d as summarizeMembers, dn as startHeapWatch, dt as localEndpointPath, en as ZERO_LOOP_DELAY, er as MAX_CAP_ACTIONS_PER_PEER, et as callWithServiceDiscovery, f as installManifestSystemDeps, fn as startRunnerHeapWatch, ft as FrameDecoder, g as createUdsAddonContext, gn as ARRAY_BUFFER_CENSUS_THRESHOLD_MB, h as createAddonContext, hn as ARRAY_BUFFER_CENSUS_SUSTAIN_MS, ht as createBrokerDeviceManagerApi, in as createV8Reclaimer, ir as EVENT_PLANE_TOP_N, it as __resetCapUsageRegistryForTests, j as brokerCallForCap, jn as OUTBOUND_QUEUE_THRESHOLD_BYTES, jt as CapabilityHandle, k as createKernelHwAccel, kn as OUTBOUND_QUEUE_COOLDOWN_MS, kt as serializeTypedArrays, l as signalAllRunnerGroups, ln as reclaimIntervalMs, lt as SocketChannel, m as adaptBrokerToCluster, mn as ARRAY_BUFFER_CENSUS_COOLDOWN_MS, mt as buildNativeCapProxy, nn as createDeferredHeapWatchSink, nr as createCapActionCensus, nt as CapUsageRegistry, o as registerRunnerGroup, on as hubMainRssBudget, or as createEventPlaneReader, ot as createLocalTransport, p as installManifestPythonDeps, pn as strandedMb, pt as encodeFrame, q as answerClaimedGetStatus, qn as recordSocketFrame, qt as HUB_MAIN_HEAP_WATCH_LABEL, r as defaultProcessGroupOps, rn as createLoopDelayMeter, rr as diffCapActionCensus, rt as PARENT_ROUTED_PROVIDER_ADDON_ID, s as releaseRunnerGroup, sn as nextRssBudgetState, sr as diffEventPlane, st as UdsLocalTransportClient, t as CAP_METHOD_NOT_IMPLEMENTED, tn as buildHeapSample, tr as capActionLabel, tt as readMoleculerFanoutMode, un as shouldReclaim, ut as PeerAnsweredError, v as getOrInitReadinessRegistry, vn as createArrayBufferCensusGate, vt as mountNativeCapService, w as getMoleculerEventStats, wn as emitHeapDiagnosticReport, wt as capActionSuffix, x as EVENT_TOPIC_PREFIX, xn as isArrayBufferCensusReport, xt as validateProviderRegistrations, y as getOrInitReadinessRegistryForClient, yn as createInspectorArrayBufferCensus, z as createUdsEventBus, zn as SOCKET_QUEUE_TOP_N, zt as createAddonPeerBytesFacility } from "./child-cap-dispatch-kLIiU1CG.mjs";
31
+ import { $ as classifyCapRoute, $n as EMPTY_CAP_ACTION_READING, $t as RUNNER_RSS_BUDGET_ENV, A as resolveHwAccel, An as OUTBOUND_QUEUE_SUSTAIN_MS, At as DeviceRegistry, B as udsChildLogToWorkerEntry, Bn as createSocketPlaneMeter, Bt as hostNodeIdOf, C as getBrokerEventBus, Cn as HEAP_SPACE_REPORT_MIN_MB, Ct as capActionName, D as subscribePassthrough, Dn as readHeapSpaces, Dt as parseCapAction, E as setNodeEventInterest, En as heapSpaceField, Et as capServiceName, F as ipcParentLink, Fn as createMeshQueueReader, Ft as resolveAddonClass, G as UDS_NO_ROUTE_PREFIX, Gn as EMPTY_SOCKET_DIRECTION, Gt as HEAP_WATCH_INTERVAL_MS, H as createUdsLoggerWithControl, Hn as diffSocketPlane, Ht as HEAP_RECLAIM_MIN_INTERVAL_MS, I as localProviderLink, In as formatMeshQueue, It as buildNpmChildEnv, J as deviceOfGetStatus, Jn as sampleSocketDirection, Jt as HUB_MAIN_RSS_BUDGET_MB, K as GET_STATUS_METHOD, Kn as createSocketDirectionCounters, Kt as HEAP_WATCH_WARN_RATIO, L as createParentUnownedCallHandler, Ln as EMPTY_SOCKET_PLANE_BASELINE, Lt as resolveNpmInvocation, M as brokerTransportLink, Mn as createOutboundQueueGate, Mt as CapabilityUnavailableError, N as buildLinkChain, Nn as formatOutboundQueueVerdict, Nt as copyBundledNativeModules, O as AddonDepsManager, On as selectReportedSpaces, Ot as deserializeTypedArrays, P as deviceCapResolverLink, Pn as MESH_QUEUE_TOP_N, Pt as installManifestNativeDeps, Q as CapRouteError, Qn as CAP_ACTION_UNLABELLED, Qt as RUNNER_HEAP_WATCH_INTERVAL_MS, R as createUdsEventBridge, Rn as SOCKET_PLANE_TOP_N, Rt as runNpm, S as clusterEventTopic, Sn as DECISIVE_HEAP_SPACES, St as NATIVE_PROVIDER_SERVICE_INFIX, T as registerEventBusService, Tn as formatHeapSpaces, Tt as capBareAction, U as LocalChildClient, Un as formatSocketPlane, Ut as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, V as createUdsLogger, Vn as createSocketPlaneReader, Vt as createAddonDataPlaneFacility, W as LocalChildRegistry, Wn as readSocketQueues, Wt as HEAP_RECLAIM_TRIGGER_MB, X as AGENT_CAP_FWD_SERVICE, Xn as socketDirectionMessages, Xt as RSS_BUDGET_REANNOUNCE_MIN_MS, Y as AGENT_CAP_FWD_ACTION, Yn as socketDirectionBytes, Yt as HUB_RSS_BUDGET_ENV, Z as CapRouteResolver, Zn as CAP_ACTION_OVERFLOW_LABEL, Zt as RSS_BUDGET_RELEASE_RATIO, _ as getWorkerDeviceRegistry, _n as ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO, a as reapProcessGroup, an as describeRss, ar as createEventPlaneMeter, at as getCapUsageRegistry, b as setHubConnected, bn as formatArrayBufferCensus, bt as createAddonService, c as runnerOwnsProcessGroup, cn as parseRssBudgetMb, cr as formatEventPlane, ct as UdsLocalTransportServer, d as summarizeMembers, dn as startHeapWatch, dt as localEndpointPath, en as ZERO_LOOP_DELAY, er as MAX_CAP_ACTIONS_PER_PEER, et as callWithServiceDiscovery, f as installManifestSystemDeps, fn as startRunnerHeapWatch, ft as FrameDecoder, g as createUdsAddonContext, gn as ARRAY_BUFFER_CENSUS_THRESHOLD_MB, h as createAddonContext, hn as ARRAY_BUFFER_CENSUS_SUSTAIN_MS, ht as createBrokerDeviceManagerApi, in as createV8Reclaimer, ir as EVENT_PLANE_TOP_N, it as __resetCapUsageRegistryForTests, j as brokerCallForCap, jn as OUTBOUND_QUEUE_THRESHOLD_BYTES, jt as CapabilityHandle, k as createKernelHwAccel, kn as OUTBOUND_QUEUE_COOLDOWN_MS, kt as serializeTypedArrays, l as signalAllRunnerGroups, ln as reclaimIntervalMs, lt as SocketChannel, m as adaptBrokerToCluster, mn as ARRAY_BUFFER_CENSUS_COOLDOWN_MS, mt as buildNativeCapProxy, nn as createDeferredHeapWatchSink, nr as createCapActionCensus, nt as CapUsageRegistry, o as registerRunnerGroup, on as hubMainRssBudget, or as createEventPlaneReader, ot as createLocalTransport, p as installManifestPythonDeps, pn as strandedMb, pt as encodeFrame, q as answerClaimedGetStatus, qn as recordSocketFrame, qt as HUB_MAIN_HEAP_WATCH_LABEL, r as defaultProcessGroupOps, rn as createLoopDelayMeter, rr as diffCapActionCensus, rt as PARENT_ROUTED_PROVIDER_ADDON_ID, s as releaseRunnerGroup, sn as nextRssBudgetState, sr as diffEventPlane, st as UdsLocalTransportClient, t as CAP_METHOD_NOT_IMPLEMENTED, tn as buildHeapSample, tr as capActionLabel, tt as readMoleculerFanoutMode, un as shouldReclaim, ut as PeerAnsweredError, v as getOrInitReadinessRegistry, vn as createArrayBufferCensusGate, vt as mountNativeCapService, w as getMoleculerEventStats, wn as emitHeapDiagnosticReport, wt as capActionSuffix, x as EVENT_TOPIC_PREFIX, xn as isArrayBufferCensusReport, xt as validateProviderRegistrations, y as getOrInitReadinessRegistryForClient, yn as createInspectorArrayBufferCensus, z as createUdsEventBus, zn as SOCKET_QUEUE_TOP_N, zt as createAddonPeerBytesFacility } from "./child-cap-dispatch-DZBRtBiY.mjs";
32
32
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-B1v6E07R.mjs";
33
33
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
34
34
  import { z } from "zod";
@@ -98,8 +98,30 @@ export interface LocalChildRegistryLogger {
98
98
  * The optional `logger` receives a single deduplicated INFO line the first time
99
99
  * each capName is routed child→sibling over UDS.
100
100
  */
101
+ /**
102
+ * Where the registry says that a runner came up or went away — the parent's
103
+ * kernel bus. A forked runner has no Moleculer broker (Phase F), so
104
+ * `$node.connected` never fires for it and the Moleculer-side emitter
105
+ * (`agent-registry.service.ts`) never sees one: this registry is the only place
106
+ * that knows (fix round 1 of the 2026-10-02 motion-release-order work, C1).
107
+ */
108
+ export interface ChildLifecycleEvents {
109
+ /** This parent's node id (`'hub'`, or the bare agent id): the `<node>` of `<node>/<childId>`. */
110
+ readonly parentNodeId: () => string;
111
+ /** The parent's kernel bus `emit`. Telemetry (D8): a consumer must survive a dropped event. */
112
+ readonly emit: (event: SystemEvent) => void;
113
+ }
101
114
  export interface LocalChildRegistryOptions {
102
115
  readonly server: LocalTransportServer;
116
+ /**
117
+ * Emit `WorkerOnline { workerId: '<parent>/<childId>' }` at a new
118
+ * incarnation's FIRST register — the pre-init frame `LocalChildClient.start()`
119
+ * sends before any addon module is loaded, so before `initialize()` and any
120
+ * device restore; it is emitted before that frame is acked — and
121
+ * `WorkerOffline` when the LIVE connection closes (never for a superseded
122
+ * one). Omitted: nothing is emitted.
123
+ */
124
+ readonly lifecycleEvents?: ChildLifecycleEvents;
103
125
  readonly onUnownedCall?: (input: CapCallInput) => Promise<unknown>;
104
126
  readonly logger?: LocalChildRegistryLogger;
105
127
  /**
@@ -275,6 +297,9 @@ export declare class LocalChildRegistry {
275
297
  private readonly server;
276
298
  private readonly onUnownedCall?;
277
299
  private readonly logger?;
300
+ private readonly lifecycleEvents?;
301
+ /** Per childId: the incarnation `WorkerOnline` was last said for. */
302
+ private readonly announcedIncarnation;
278
303
  private readonly getActiveSingletonAddonId?;
279
304
  private readonly resolveChildIdForAddon?;
280
305
  /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
@@ -605,5 +630,10 @@ export declare class LocalChildRegistry {
605
630
  */
606
631
  setChildLogLevel(childId: string, level: string): boolean;
607
632
  close(): Promise<void>;
633
+ /** `WorkerOnline`, once per incarnation: a re-register of the same connection says nothing. */
634
+ private announceOnline;
635
+ /** `WorkerOffline` for the LIVE connection's close (a superseded close never reaches here). */
636
+ private announceOffline;
637
+ private emitLifecycle;
608
638
  private onConnection;
609
639
  }
@@ -1,4 +1,4 @@
1
- import { Xn as asJsonObject } from "./dist-CoG8lY6H.mjs";
1
+ import { Xn as asJsonObject } from "./dist-DxkeG_0w.mjs";
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DRUzy1SF.js");
1
+ const require_dist = require("./dist-Dl2VFsPg.js");
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.331",
3
+ "version": "1.2.333",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",