@camstack/system 1.2.238 → 1.2.240

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 (57) 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/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  41. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  43. package/dist/builtins/system-config/system-config.addon.js +1 -1
  44. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  45. package/dist/builtins/winston-logging/index.js +1 -1
  46. package/dist/builtins/winston-logging/index.mjs +1 -1
  47. package/dist/{dist-D5hpgLSL.mjs → dist-CDDG1zn3.mjs} +133 -1
  48. package/dist/{dist-CHclfj0J.js → dist-Dze0l7UM.js} +133 -1
  49. package/dist/index.js +2 -2
  50. package/dist/index.mjs +2 -2
  51. package/dist/kernel/moleculer/device-event-ring.d.ts +113 -0
  52. package/dist/kernel/moleculer/event-bus-core.d.ts +18 -0
  53. package/dist/{manifest-system-deps-BEj9Dpu1.mjs → manifest-system-deps-CfR7Z90J.mjs} +136 -2
  54. package/dist/{manifest-system-deps-CrSP0Kkp.js → manifest-system-deps-CzyjTMcO.js} +136 -2
  55. package/dist/{retired-settings-keys-DRKmYztE.js → retired-settings-keys-1GWw9mup.js} +1 -1
  56. package/dist/{retired-settings-keys-bJE3qjAT.mjs → retired-settings-keys-Cbt4-K_M.mjs} +1 -1
  57. package/package.json +2 -2
@@ -6974,6 +6974,137 @@ function getCapUsageRegistry() {
6974
6974
  function __resetCapUsageRegistryForTests() {
6975
6975
  singleton = null;
6976
6976
  }
6977
+ var MIRROR_REASON_BY_CATEGORY = new Map([
6978
+ {
6979
+ category: "device.state-changed",
6980
+ reason: "Device runtime-state mirror, 69.1 % of fleet traffic. Each event is a snapshot of the slice AFTER the change; the superseded snapshot describes a state the device is no longer in, and every consumer (SystemMirror, DeviceStateHandle) reads the latest one only."
6981
+ },
6982
+ {
6983
+ category: "camera-streams.onCamStreamsChanged",
6984
+ reason: "Full stream-list snapshot per camera, 20.1 % of fleet traffic. The payload is the complete current list, not a delta, so an older list is strictly less true than the newer one."
6985
+ },
6986
+ {
6987
+ category: "system.ready-state",
6988
+ reason: "Readiness is a LEVEL, not an edge: the event reports whether a capability is ready right now. Declared for the case where it carries a deviceId; when it does not it stays in the global ring like any other unattributed event."
6989
+ }
6990
+ ].map((m) => [m.category, m.reason]));
6991
+ /**
6992
+ * Is this category declared a mirror? An unclassified category is NOT a mirror
6993
+ * — the safe default is to keep its history.
6994
+ */
6995
+ function isMirrorCategory(category) {
6996
+ return MIRROR_REASON_BY_CATEGORY.has(category);
6997
+ }
6998
+ /**
6999
+ * Non-mirror events retained per device. ~1.1 events/s fleet-wide after
7000
+ * coalescing ⇒ ~3 000/day/camera ⇒ 2 000 ≈ 16 h.
7001
+ */
7002
+ var MAX_DEVICE_RING_EVENTS = 2e3;
7003
+ function serializePayload(data) {
7004
+ try {
7005
+ const json = JSON.stringify(data);
7006
+ if (typeof json !== "string") return null;
7007
+ return {
7008
+ json,
7009
+ bytes: Buffer.byteLength(json, "utf8")
7010
+ };
7011
+ } catch {
7012
+ return null;
7013
+ }
7014
+ }
7015
+ /**
7016
+ * The event as it should be RETAINED: unchanged when its payload is within the
7017
+ * cap, otherwise a NEW event whose `data` is the marked replacement. The
7018
+ * argument is never mutated — the same object is still live on the fan-out path
7019
+ * and in the global ring.
7020
+ */
7021
+ function capEventData(event) {
7022
+ const serialized = serializePayload(event.data);
7023
+ if (serialized !== null && serialized.bytes <= 256) return event;
7024
+ const truncated = {
7025
+ __truncated: true,
7026
+ __originalBytes: serialized?.bytes ?? null,
7027
+ __preview: serialized === null ? "" : serialized.json.slice(0, 160)
7028
+ };
7029
+ return {
7030
+ ...event,
7031
+ data: truncated
7032
+ };
7033
+ }
7034
+ /**
7035
+ * The device this event is about, or `undefined` when it is about no device.
7036
+ *
7037
+ * Same rule as `matchesEventFilter` — `source.deviceId`, or `source.id` when
7038
+ * the source IS a device — so a read filtered by `deviceId` and a read served
7039
+ * from that device's ring agree on which events belong to it. A non-numeric
7040
+ * device source id yields `undefined` rather than `NaN`: an unattributable
7041
+ * event must never become a bucket of its own.
7042
+ */
7043
+ function eventDeviceId(event) {
7044
+ const explicit = event.source.deviceId;
7045
+ if (explicit !== void 0) return Number.isFinite(explicit) ? explicit : void 0;
7046
+ if (event.source.type !== "device") return void 0;
7047
+ const asNumber = Number(event.source.id);
7048
+ return Number.isFinite(asNumber) ? asNumber : void 0;
7049
+ }
7050
+ function createDeviceEventRings() {
7051
+ return { byDevice: /* @__PURE__ */ new Map() };
7052
+ }
7053
+ function ringFor(rings, deviceId) {
7054
+ const existing = rings.byDevice.get(deviceId);
7055
+ if (existing !== void 0) {
7056
+ rings.byDevice.delete(deviceId);
7057
+ rings.byDevice.set(deviceId, existing);
7058
+ return existing;
7059
+ }
7060
+ const created = {
7061
+ history: [],
7062
+ mirrors: /* @__PURE__ */ new Map()
7063
+ };
7064
+ rings.byDevice.set(deviceId, created);
7065
+ while (rings.byDevice.size > 512) {
7066
+ const oldest = rings.byDevice.keys().next();
7067
+ if (oldest.done === true) break;
7068
+ rings.byDevice.delete(oldest.value);
7069
+ }
7070
+ return created;
7071
+ }
7072
+ /**
7073
+ * Retain `event` in its device's ring, with its payload capped.
7074
+ *
7075
+ * Returns the device it was filed under, or `undefined` when the event names no
7076
+ * device — the caller has already retained it in the global ring and nothing
7077
+ * more happens here. No device is fabricated.
7078
+ */
7079
+ function recordDeviceEvent(rings, event) {
7080
+ const deviceId = eventDeviceId(event);
7081
+ if (deviceId === void 0) return void 0;
7082
+ const ring = ringFor(rings, deviceId);
7083
+ const retained = capEventData(event);
7084
+ if (isMirrorCategory(event.category)) {
7085
+ ring.mirrors.set(event.category, retained);
7086
+ return deviceId;
7087
+ }
7088
+ ring.history.push(retained);
7089
+ if (ring.history.length > 2e3) ring.history.splice(0, ring.history.length - MAX_DEVICE_RING_EVENTS);
7090
+ return deviceId;
7091
+ }
7092
+ /**
7093
+ * Everything retained for one device, oldest first — history merged with the
7094
+ * current value of each mirror, ordered by timestamp so the caller's `-limit`
7095
+ * slice means the same thing it means on the global ring.
7096
+ *
7097
+ * An unknown device yields `[]`: unknown is the truth about a camera that has
7098
+ * emitted nothing since this process started.
7099
+ */
7100
+ function getDeviceRecent(rings, deviceId) {
7101
+ const ring = rings.byDevice.get(deviceId);
7102
+ if (ring === void 0) return [];
7103
+ if (ring.mirrors.size === 0) return ring.history;
7104
+ const merged = [...ring.history, ...ring.mirrors.values()];
7105
+ merged.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
7106
+ return merged;
7107
+ }
6977
7108
  //#endregion
6978
7109
  //#region src/kernel/moleculer/event-bus-core.ts
6979
7110
  /**
@@ -6985,6 +7116,7 @@ function createSharedBusState(retainRecent = false) {
6985
7116
  return {
6986
7117
  handlers: /* @__PURE__ */ new Map(),
6987
7118
  recent: [],
7119
+ deviceRings: createDeviceEventRings(),
6988
7120
  retainRecent
6989
7121
  };
6990
7122
  }
@@ -7168,6 +7300,7 @@ function deliverShared(state, event) {
7168
7300
  if (state.retainRecent && !isHighFrequencyCategory(event.category)) {
7169
7301
  state.recent.push(event);
7170
7302
  if (state.recent.length > 1e3) state.recent.splice(0, state.recent.length - MAX_RECENT_EVENTS);
7303
+ recordDeviceEvent(state.deviceRings, event);
7171
7304
  }
7172
7305
  const delivered = /* @__PURE__ */ new Set();
7173
7306
  for (const [pattern, set] of state.handlers) {
@@ -10133,14 +10266,15 @@ function getBrokerEventBus(broker, options) {
10133
10266
  });
10134
10267
  },
10135
10268
  getRecent(filter, limit) {
10136
- const filtered = filter ? state.recent.filter((e) => {
10269
+ const source = filter?.deviceId !== void 0 ? getDeviceRecent(state.deviceRings, filter.deviceId) : state.recent;
10270
+ const filtered = filter ? source.filter((e) => {
10137
10271
  const cat = filter.category;
10138
10272
  if (cat) {
10139
10273
  const categories = typeof cat === "string" ? [cat] : Array.isArray(cat) ? cat : [];
10140
10274
  if (categories.length > 0 && !categories.some((c) => matchesPattern(String(c), e.category))) return false;
10141
10275
  }
10142
10276
  return matchesEventFilter(e, filter);
10143
- }) : state.recent;
10277
+ }) : source;
10144
10278
  return limit !== void 0 ? filtered.slice(-limit) : filtered;
10145
10279
  }
10146
10280
  };
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CHclfj0J.js");
1
+ const require_dist = require("./dist-Dze0l7UM.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?
@@ -1,4 +1,4 @@
1
- import { in as asJsonObject } from "./dist-D5hpgLSL.mjs";
1
+ import { in as asJsonObject } from "./dist-CDDG1zn3.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?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.238",
3
+ "version": "1.2.240",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",
@@ -352,7 +352,7 @@
352
352
  "typecheck": "tsc --noEmit",
353
353
  "test": "vitest run",
354
354
  "test:watch": "vitest",
355
- "publish": "npm publish --access public"
355
+ "publish:npm": "npm publish --access public"
356
356
  },
357
357
  "dependencies": {
358
358
  "@camstack/sdk": "*",