@camstack/system 1.2.159 → 1.2.160
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.
- package/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +10 -7
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +50 -12
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +50 -12
- package/dist/builtins/backup-orchestrator/write-targets.d.ts +63 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-bindings-store.d.ts +56 -10
- package/dist/builtins/device-manager/device-manager.addon.d.ts +11 -0
- package/dist/builtins/device-manager/device-manager.addon.js +216 -81
- package/dist/builtins/device-manager/device-manager.addon.mjs +216 -81
- package/dist/builtins/device-manager/device-meta-actions.d.ts +9 -3
- package/dist/builtins/device-manager/device-meta-store.d.ts +32 -5
- package/dist/builtins/device-manager/device-queries.d.ts +7 -3
- package/dist/builtins/device-manager/write-lock.d.ts +17 -0
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/filter-compiler.d.ts +41 -2
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +15 -7
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-migration-coordinator.d.ts +3 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +63 -8
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +63 -8
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +19 -0
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-Ck2jkBZk.js → dist-CcvXUhHK.js} +74 -7
- package/dist/{dist-DLh4_rn3.mjs → dist-DKs---Vx.mjs} +74 -7
- package/dist/index.js +3 -2
- package/dist/index.mjs +3 -3
- package/dist/kernel/index.d.ts +2 -2
- package/dist/kernel/moleculer/cap-usage-registry.d.ts +132 -7
- package/dist/kernel/transport/local-child-registry.d.ts +57 -0
- package/dist/{manifest-system-deps-tZZYG3RR.mjs → manifest-system-deps-DnoPpLGp.mjs} +271 -77
- package/dist/{manifest-system-deps-8boi90D9.js → manifest-system-deps-oJMkWSX-.js} +276 -76
- package/dist/{retired-settings-keys-Bi0ZKBjb.mjs → retired-settings-keys-C3eONTvV.mjs} +1 -1
- package/dist/{retired-settings-keys-Dp_CyuCW.js → retired-settings-keys-DXZ2xe7C.js} +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
require("./dist-
|
|
2
|
+
require("./dist-CcvXUhHK.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
5
5
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -5550,6 +5550,246 @@ function createLocalTransport() {
|
|
|
5550
5550
|
};
|
|
5551
5551
|
}
|
|
5552
5552
|
//#endregion
|
|
5553
|
+
//#region src/kernel/moleculer/cap-usage-registry.ts
|
|
5554
|
+
/**
|
|
5555
|
+
* In-memory observation of tRPC cap calls between addons — the store behind
|
|
5556
|
+
* `nodes.getCapUsageGraph`.
|
|
5557
|
+
*
|
|
5558
|
+
* Storage: `Map<callerAddonId, Map<providerAddonId, Map<capName, RollingWindow>>>`.
|
|
5559
|
+
* `RollingWindow` is a fixed-size ring of 1-second buckets — default 300
|
|
5560
|
+
* buckets = 5 minutes retention. Queries narrower than the retention window
|
|
5561
|
+
* filter buckets at read time.
|
|
5562
|
+
*
|
|
5563
|
+
* ── The ring ages, and that is not free decoration ─────────────────────────
|
|
5564
|
+
* Buckets are indexed `second % retention`, so a bucket written at second S is
|
|
5565
|
+
* hit again at S + retention·k forever. Until 2026-08-30 nothing ever zeroed
|
|
5566
|
+
* them: the `lastCallAtMs` guard hid it while a triple was fully idle, but ONE
|
|
5567
|
+
* fresh call re-armed the entire stale ring. A triple that made 1000 calls and
|
|
5568
|
+
* then one call five minutes later reported **1001 calls/min instead of 1**.
|
|
5569
|
+
* An over-counted edge is worse than the empty graph this instrument shipped
|
|
5570
|
+
* with — silence invites doubt, a confident wrong number sends the next
|
|
5571
|
+
* investigation at the wrong addon.
|
|
5572
|
+
*
|
|
5573
|
+
* The fix is clear-forward: on each record, zero the buckets the ring has
|
|
5574
|
+
* ADVANCED over since the previous write, and never read past the last written
|
|
5575
|
+
* second. Amortised O(1) — a busy triple clears 0–1 buckets per call, and an
|
|
5576
|
+
* idle one clears at most `retention` once, when it wakes.
|
|
5577
|
+
*
|
|
5578
|
+
* ── Cardinality is bounded, because this map lives on hub-main ─────────────
|
|
5579
|
+
* The previous docblock claimed "~22 MB worst case … under 200 KB at ~10 active
|
|
5580
|
+
* triples". Both numbers were written for a smaller machine and the second was
|
|
5581
|
+
* an assumption, not a bound: the key space is caller × provider × cap, and on
|
|
5582
|
+
* the live hub that is 64 addons × 64 runners × ~150 caps. Nothing capped it.
|
|
5583
|
+
*
|
|
5584
|
+
* Today a ring is one `Uint32Array(retention)` — 1.2 KB of ArrayBuffer at the
|
|
5585
|
+
* default — plus the three Map entries that reach it. MEASURED (`heapUsed` +
|
|
5586
|
+
* `arrayBuffers`, node 24, `--expose-gc`): **1.7 KB per triple**, so ≈1.0 MB at
|
|
5587
|
+
* the realistic hub figure (64 callers × a handful of caps each, ≈600 triples)
|
|
5588
|
+
* and **6.3 MB at the {@link DEFAULT_MAX_TRIPLES} ceiling**. `recordCall` costs
|
|
5589
|
+
* ≈46 ns (1e6 calls in 46 ms) — at the 39 717 calls/min that started this
|
|
5590
|
+
* investigation, ≈30 µs of hub-main per second.
|
|
5591
|
+
*
|
|
5592
|
+
* Reclamation is what keeps it at the low end: a triple whose ring has entirely
|
|
5593
|
+
* aged out is dead data and is dropped on the next admission sweep. The hard
|
|
5594
|
+
* cap only exists so that a pathological key space (a caller id derived from
|
|
5595
|
+
* something unbounded) cannot take hub-main's heap with it — and when it bites,
|
|
5596
|
+
* {@link CapUsageRegistry.getStats} says how often, because an instrument that
|
|
5597
|
+
* truncates silently is the defect this whole file exists to fix (D237).
|
|
5598
|
+
*/
|
|
5599
|
+
/** Ring length in seconds when the caller does not pick one. */
|
|
5600
|
+
var DEFAULT_RETENTION_SECONDS = 300;
|
|
5601
|
+
/**
|
|
5602
|
+
* Ceiling on live `(caller, provider, cap)` triples. ≈1.5 KB each → ≈6 MB.
|
|
5603
|
+
* Roughly 6× the realistic hub figure, so it is a backstop against an
|
|
5604
|
+
* unbounded key space, not a working limit.
|
|
5605
|
+
*/
|
|
5606
|
+
var DEFAULT_MAX_TRIPLES = 4e3;
|
|
5607
|
+
/**
|
|
5608
|
+
* Provider placeholder for a call the PARENT routed rather than short-
|
|
5609
|
+
* circuiting to a sibling runner: hub-in-process (`settings-store`,
|
|
5610
|
+
* `device-manager`, the `$core-caps` bridge), or a remote node. At the layer
|
|
5611
|
+
* that records — the parent's `cap-call-out` handler — the sibling id IS the
|
|
5612
|
+
* provider and everything else has not been resolved yet.
|
|
5613
|
+
*
|
|
5614
|
+
* It is a NAMED unknown, not a dropped observation, for the reason D237 was
|
|
5615
|
+
* written: the caller is always known, and "who is hammering `settings-store`"
|
|
5616
|
+
* is the question this graph exists to answer. Sibling to
|
|
5617
|
+
* `UNRESOLVED_PROVIDER_ADDON_ID` in `trpc-links.ts`, which names the same kind
|
|
5618
|
+
* of unknown one layer up.
|
|
5619
|
+
*/
|
|
5620
|
+
var PARENT_ROUTED_PROVIDER_ADDON_ID = "(unresolved: parent-routed)";
|
|
5621
|
+
var CapUsageRegistry = class {
|
|
5622
|
+
retentionSeconds;
|
|
5623
|
+
maxTriples;
|
|
5624
|
+
map = /* @__PURE__ */ new Map();
|
|
5625
|
+
triples = 0;
|
|
5626
|
+
droppedTriples = 0;
|
|
5627
|
+
constructor(opts) {
|
|
5628
|
+
this.retentionSeconds = Math.max(1, opts?.retentionSeconds ?? DEFAULT_RETENTION_SECONDS);
|
|
5629
|
+
this.maxTriples = Math.max(1, opts?.maxTriples ?? DEFAULT_MAX_TRIPLES);
|
|
5630
|
+
}
|
|
5631
|
+
/**
|
|
5632
|
+
* Record one observed cap call.
|
|
5633
|
+
*
|
|
5634
|
+
* On the hot path: this runs once per cross-process cap call on hub-main's
|
|
5635
|
+
* event loop, which is the cluster's only queue (D181). Three Map lookups, an
|
|
5636
|
+
* integer increment, and — only when the wall clock has moved on — a bounded
|
|
5637
|
+
* clear. No allocation once a triple exists, and it NEVER throws into the
|
|
5638
|
+
* call it observes.
|
|
5639
|
+
*/
|
|
5640
|
+
recordCall(rec) {
|
|
5641
|
+
try {
|
|
5642
|
+
if (rec.callerAddonId === "" || rec.providerAddonId === "" || rec.capName === "") return;
|
|
5643
|
+
if (!Number.isFinite(rec.atMs) || rec.atMs < 0) return;
|
|
5644
|
+
const window = this.windowFor(rec);
|
|
5645
|
+
if (window === null) return;
|
|
5646
|
+
const sec = Math.floor(rec.atMs / 1e3);
|
|
5647
|
+
if (window.lastCallAtMs !== 0) {
|
|
5648
|
+
const lastSec = Math.floor(window.lastCallAtMs / 1e3);
|
|
5649
|
+
const advanced = Math.min(sec - lastSec, this.retentionSeconds);
|
|
5650
|
+
for (let k = 1; k <= advanced; k++) window.buckets[(lastSec + k) % this.retentionSeconds] = 0;
|
|
5651
|
+
}
|
|
5652
|
+
const idx = sec % this.retentionSeconds;
|
|
5653
|
+
window.buckets[idx] = (window.buckets[idx] ?? 0) + 1;
|
|
5654
|
+
if (rec.atMs > window.lastCallAtMs) window.lastCallAtMs = rec.atMs;
|
|
5655
|
+
} catch {}
|
|
5656
|
+
}
|
|
5657
|
+
getGraph(opts) {
|
|
5658
|
+
const windowSeconds = Math.max(1, Math.min(opts.windowSeconds, this.retentionSeconds));
|
|
5659
|
+
const minMs = opts.nowMs - windowSeconds * 1e3;
|
|
5660
|
+
const nowSec = Math.floor(opts.nowMs / 1e3);
|
|
5661
|
+
const out = [];
|
|
5662
|
+
for (const [caller, byProvider] of this.map) for (const [provider, byCap] of byProvider) for (const [capName, window] of byCap) {
|
|
5663
|
+
if (window.lastCallAtMs < minMs) continue;
|
|
5664
|
+
const count = this.sumWindow(window, nowSec, windowSeconds);
|
|
5665
|
+
if (count === 0) continue;
|
|
5666
|
+
const callsPerMin = count / windowSeconds * 60;
|
|
5667
|
+
out.push({
|
|
5668
|
+
callerAddonId: caller,
|
|
5669
|
+
providerAddonId: provider,
|
|
5670
|
+
capName,
|
|
5671
|
+
callsPerMin,
|
|
5672
|
+
lastCallAtMs: window.lastCallAtMs
|
|
5673
|
+
});
|
|
5674
|
+
}
|
|
5675
|
+
return out;
|
|
5676
|
+
}
|
|
5677
|
+
/** See {@link CapUsageStats}. Cheap — three counters, no scan. */
|
|
5678
|
+
getStats() {
|
|
5679
|
+
return {
|
|
5680
|
+
triples: this.triples,
|
|
5681
|
+
maxTriples: this.maxTriples,
|
|
5682
|
+
droppedTriples: this.droppedTriples
|
|
5683
|
+
};
|
|
5684
|
+
}
|
|
5685
|
+
/** Test / diagnostic helper — drops all recorded calls. */
|
|
5686
|
+
clear() {
|
|
5687
|
+
this.map.clear();
|
|
5688
|
+
this.triples = 0;
|
|
5689
|
+
this.droppedTriples = 0;
|
|
5690
|
+
}
|
|
5691
|
+
/**
|
|
5692
|
+
* Sum the buckets covering `(nowSec - windowSeconds, nowSec]`.
|
|
5693
|
+
*
|
|
5694
|
+
* The scan starts at `lastSec`, never at `nowSec`. `recordCall` clears the
|
|
5695
|
+
* buckets the ring has advanced OVER, which by definition stops at the last
|
|
5696
|
+
* write: the buckets for the seconds since then still hold whatever the
|
|
5697
|
+
* previous pass left in them, and reading `nowSec` down would count it. A
|
|
5698
|
+
* triple that went quiet for a couple of minutes and then made one call would
|
|
5699
|
+
* report the burst it made five minutes earlier.
|
|
5700
|
+
*
|
|
5701
|
+
* No lower bound is needed beyond the window itself: every bucket at or below
|
|
5702
|
+
* `lastSec - retention` was cleared by the advance that reached `lastSec`, so
|
|
5703
|
+
* it reads zero anyway. The loop is bounded by `windowSeconds ≤ retention`.
|
|
5704
|
+
*/
|
|
5705
|
+
sumWindow(window, nowSec, windowSeconds) {
|
|
5706
|
+
const lastSec = Math.floor(window.lastCallAtMs / 1e3);
|
|
5707
|
+
const from = Math.min(nowSec, lastSec);
|
|
5708
|
+
const floorSec = nowSec - windowSeconds;
|
|
5709
|
+
let count = 0;
|
|
5710
|
+
for (let s = from; s > floorSec; s--) count += window.buckets[s % this.retentionSeconds] ?? 0;
|
|
5711
|
+
return count;
|
|
5712
|
+
}
|
|
5713
|
+
/**
|
|
5714
|
+
* The ring for this triple, creating it if the ceiling allows. `null` means
|
|
5715
|
+
* the observation is dropped — counted, never silent (see
|
|
5716
|
+
* {@link CapUsageStats.droppedTriples}).
|
|
5717
|
+
*/
|
|
5718
|
+
windowFor(rec) {
|
|
5719
|
+
let byProvider = this.map.get(rec.callerAddonId);
|
|
5720
|
+
if (!byProvider) {
|
|
5721
|
+
byProvider = /* @__PURE__ */ new Map();
|
|
5722
|
+
this.map.set(rec.callerAddonId, byProvider);
|
|
5723
|
+
}
|
|
5724
|
+
let byCap = byProvider.get(rec.providerAddonId);
|
|
5725
|
+
if (!byCap) {
|
|
5726
|
+
byCap = /* @__PURE__ */ new Map();
|
|
5727
|
+
byProvider.set(rec.providerAddonId, byCap);
|
|
5728
|
+
}
|
|
5729
|
+
const existing = byCap.get(rec.capName);
|
|
5730
|
+
if (existing) return existing;
|
|
5731
|
+
if (this.triples >= this.maxTriples) {
|
|
5732
|
+
this.reclaimExpired(rec.atMs);
|
|
5733
|
+
if (this.triples >= this.maxTriples) {
|
|
5734
|
+
this.droppedTriples++;
|
|
5735
|
+
return null;
|
|
5736
|
+
}
|
|
5737
|
+
byProvider = this.map.get(rec.callerAddonId);
|
|
5738
|
+
if (!byProvider) {
|
|
5739
|
+
byProvider = /* @__PURE__ */ new Map();
|
|
5740
|
+
this.map.set(rec.callerAddonId, byProvider);
|
|
5741
|
+
}
|
|
5742
|
+
byCap = byProvider.get(rec.providerAddonId);
|
|
5743
|
+
if (!byCap) {
|
|
5744
|
+
byCap = /* @__PURE__ */ new Map();
|
|
5745
|
+
byProvider.set(rec.providerAddonId, byCap);
|
|
5746
|
+
}
|
|
5747
|
+
}
|
|
5748
|
+
const created = {
|
|
5749
|
+
buckets: new Uint32Array(this.retentionSeconds),
|
|
5750
|
+
lastCallAtMs: 0
|
|
5751
|
+
};
|
|
5752
|
+
byCap.set(rec.capName, created);
|
|
5753
|
+
this.triples++;
|
|
5754
|
+
return created;
|
|
5755
|
+
}
|
|
5756
|
+
/**
|
|
5757
|
+
* Drop every triple whose whole ring has aged out — its last call is older
|
|
5758
|
+
* than the retention window, so it can contribute to no query. O(triples),
|
|
5759
|
+
* and only reachable when the ceiling is full, so it is amortised away by the
|
|
5760
|
+
* admissions it enables.
|
|
5761
|
+
*/
|
|
5762
|
+
reclaimExpired(nowMs) {
|
|
5763
|
+
const cutoff = nowMs - this.retentionSeconds * 1e3;
|
|
5764
|
+
for (const [caller, byProvider] of this.map) {
|
|
5765
|
+
for (const [provider, byCap] of byProvider) {
|
|
5766
|
+
for (const [capName, window] of byCap) {
|
|
5767
|
+
if (window.lastCallAtMs >= cutoff) continue;
|
|
5768
|
+
byCap.delete(capName);
|
|
5769
|
+
this.triples--;
|
|
5770
|
+
}
|
|
5771
|
+
if (byCap.size === 0) byProvider.delete(provider);
|
|
5772
|
+
}
|
|
5773
|
+
if (byProvider.size === 0) this.map.delete(caller);
|
|
5774
|
+
}
|
|
5775
|
+
}
|
|
5776
|
+
};
|
|
5777
|
+
var singleton = null;
|
|
5778
|
+
/**
|
|
5779
|
+
* The registry for THIS process. Deliberately per-process: the reader
|
|
5780
|
+
* (`nodes.getCapUsageGraph` → `cap-providers.ts`) runs on hub-main, so only
|
|
5781
|
+
* writes made on hub-main are ever visible. See the blind-spot list on
|
|
5782
|
+
* `LocalChildRegistryOptions.capUsageObserver` for what that excludes.
|
|
5783
|
+
*/
|
|
5784
|
+
function getCapUsageRegistry() {
|
|
5785
|
+
if (!singleton) singleton = new CapUsageRegistry();
|
|
5786
|
+
return singleton;
|
|
5787
|
+
}
|
|
5788
|
+
/** Test helper — clears the singleton (kept module-private elsewhere). */
|
|
5789
|
+
function __resetCapUsageRegistryForTests() {
|
|
5790
|
+
singleton = null;
|
|
5791
|
+
}
|
|
5792
|
+
//#endregion
|
|
5553
5793
|
//#region src/kernel/moleculer/event-bus-core.ts
|
|
5554
5794
|
/**
|
|
5555
5795
|
* @param retainRecent - `true` ONLY for the hub main broker bus (it serves
|
|
@@ -6241,6 +6481,8 @@ var LocalChildRegistry = class {
|
|
|
6241
6481
|
isAddonPinnedCall;
|
|
6242
6482
|
/** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
|
|
6243
6483
|
capTimeoutMs;
|
|
6484
|
+
/** See {@link LocalChildRegistryOptions.capUsageObserver}. */
|
|
6485
|
+
capUsageObserver;
|
|
6244
6486
|
/** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
|
|
6245
6487
|
egressRoutedCaps = /* @__PURE__ */ new Set();
|
|
6246
6488
|
/** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
|
|
@@ -6272,6 +6514,7 @@ var LocalChildRegistry = class {
|
|
|
6272
6514
|
this.isAggregatedCollectionMethod = opts.isAggregatedCollectionMethod;
|
|
6273
6515
|
this.isAddonPinnedCall = opts.isAddonPinnedCall;
|
|
6274
6516
|
this.capTimeoutMs = opts.capTimeoutMs;
|
|
6517
|
+
this.capUsageObserver = opts.capUsageObserver;
|
|
6275
6518
|
} else {
|
|
6276
6519
|
this.server = serverOrOptions;
|
|
6277
6520
|
this.onUnownedCall = onUnownedCallArg;
|
|
@@ -6438,6 +6681,29 @@ var LocalChildRegistry = class {
|
|
|
6438
6681
|
}
|
|
6439
6682
|
return candidates[0];
|
|
6440
6683
|
}
|
|
6684
|
+
/**
|
|
6685
|
+
* Publish one cap-usage observation, if a sink is wired.
|
|
6686
|
+
*
|
|
6687
|
+
* Cost discipline — this is on the hot path (D181: hub-main's event loop is
|
|
6688
|
+
* the cluster's only queue): no sink means one undefined check; with a sink
|
|
6689
|
+
* it is one object literal and one `Date.now()`, and the sink itself is O(1).
|
|
6690
|
+
* Wrapped so a broken observer can never fail the call it observes — the
|
|
6691
|
+
* registry swallows too, and BOTH matter: this catch also covers a sink that
|
|
6692
|
+
* is not the registry.
|
|
6693
|
+
*/
|
|
6694
|
+
recordCapUsage(callerChildId, providerChildId, capName, methodName) {
|
|
6695
|
+
const sink = this.capUsageObserver;
|
|
6696
|
+
if (sink === void 0 || callerChildId === null) return;
|
|
6697
|
+
try {
|
|
6698
|
+
sink({
|
|
6699
|
+
callerAddonId: callerChildId,
|
|
6700
|
+
providerAddonId: providerChildId ?? "(unresolved: parent-routed)",
|
|
6701
|
+
capName,
|
|
6702
|
+
methodName,
|
|
6703
|
+
atMs: Date.now()
|
|
6704
|
+
});
|
|
6705
|
+
} catch {}
|
|
6706
|
+
}
|
|
6441
6707
|
/** First child whose cap manifest contains a descriptor matching `predicate`. */
|
|
6442
6708
|
findChildId(predicate) {
|
|
6443
6709
|
for (const entry of this.children.values()) if (entry.caps.some(predicate)) return entry.childId;
|
|
@@ -6707,7 +6973,9 @@ var LocalChildRegistry = class {
|
|
|
6707
6973
|
const pinTargetsThisNode = pinnedNodeId !== void 0 && this.ownNodeId !== void 0 && pinnedNodeId === this.ownNodeId;
|
|
6708
6974
|
const aggregated = pinnedNodeId === void 0 && this.isAggregatedCollectionMethod?.(out.capName, out.method) === true;
|
|
6709
6975
|
const addonPinned = pinnedNodeId === void 0 && this.isAddonPinnedCall?.(out.capName, out.method, out.args) === true;
|
|
6710
|
-
|
|
6976
|
+
const target = !(out.native === true) && !aggregated && !addonPinned && (pinnedNodeId === void 0 || pinTargetsThisNode) ? this.resolveChildId(out.capName, out.deviceId) : null;
|
|
6977
|
+
this.recordCapUsage(childId, target, out.capName, out.method);
|
|
6978
|
+
if (target !== null) {
|
|
6711
6979
|
if (!this.egressRoutedCaps.has(out.capName)) {
|
|
6712
6980
|
this.egressRoutedCaps.add(out.capName);
|
|
6713
6981
|
this.logger?.info("routed child egress over UDS", { capName: out.capName });
|
|
@@ -7859,80 +8127,6 @@ function buildLinkChain(target, localResolver, hookup) {
|
|
|
7859
8127
|
return links;
|
|
7860
8128
|
}
|
|
7861
8129
|
//#endregion
|
|
7862
|
-
//#region src/kernel/moleculer/cap-usage-registry.ts
|
|
7863
|
-
var CapUsageRegistry = class {
|
|
7864
|
-
retentionSeconds;
|
|
7865
|
-
map = /* @__PURE__ */ new Map();
|
|
7866
|
-
constructor(opts) {
|
|
7867
|
-
this.retentionSeconds = Math.max(1, opts?.retentionSeconds ?? 300);
|
|
7868
|
-
}
|
|
7869
|
-
recordCall(rec) {
|
|
7870
|
-
try {
|
|
7871
|
-
if (rec.callerAddonId === "" || rec.providerAddonId === "" || rec.capName === "") return;
|
|
7872
|
-
if (!Number.isFinite(rec.atMs) || rec.atMs < 0) return;
|
|
7873
|
-
let byProvider = this.map.get(rec.callerAddonId);
|
|
7874
|
-
if (!byProvider) {
|
|
7875
|
-
byProvider = /* @__PURE__ */ new Map();
|
|
7876
|
-
this.map.set(rec.callerAddonId, byProvider);
|
|
7877
|
-
}
|
|
7878
|
-
let byCap = byProvider.get(rec.providerAddonId);
|
|
7879
|
-
if (!byCap) {
|
|
7880
|
-
byCap = /* @__PURE__ */ new Map();
|
|
7881
|
-
byProvider.set(rec.providerAddonId, byCap);
|
|
7882
|
-
}
|
|
7883
|
-
let window = byCap.get(rec.capName);
|
|
7884
|
-
if (!window) {
|
|
7885
|
-
window = {
|
|
7886
|
-
buckets: Array.from({ length: this.retentionSeconds }, () => 0),
|
|
7887
|
-
lastCallAtMs: 0
|
|
7888
|
-
};
|
|
7889
|
-
byCap.set(rec.capName, window);
|
|
7890
|
-
}
|
|
7891
|
-
const bucketIdx = Math.floor(rec.atMs / 1e3) % this.retentionSeconds;
|
|
7892
|
-
window.buckets[bucketIdx] = (window.buckets[bucketIdx] ?? 0) + 1;
|
|
7893
|
-
if (rec.atMs > window.lastCallAtMs) window.lastCallAtMs = rec.atMs;
|
|
7894
|
-
} catch {}
|
|
7895
|
-
}
|
|
7896
|
-
getGraph(opts) {
|
|
7897
|
-
const windowSeconds = Math.max(1, Math.min(opts.windowSeconds, this.retentionSeconds));
|
|
7898
|
-
const minMs = opts.nowMs - windowSeconds * 1e3;
|
|
7899
|
-
const out = [];
|
|
7900
|
-
for (const [caller, byProvider] of this.map) for (const [provider, byCap] of byProvider) for (const [capName, window] of byCap) {
|
|
7901
|
-
if (window.lastCallAtMs < minMs) continue;
|
|
7902
|
-
const nowBucket = Math.floor(opts.nowMs / 1e3);
|
|
7903
|
-
let count = 0;
|
|
7904
|
-
for (let i = 0; i < windowSeconds; i++) {
|
|
7905
|
-
const b = (nowBucket - i + this.retentionSeconds * 1e6) % this.retentionSeconds;
|
|
7906
|
-
count += window.buckets[b] ?? 0;
|
|
7907
|
-
}
|
|
7908
|
-
if (count === 0) continue;
|
|
7909
|
-
const callsPerMin = count / windowSeconds * 60;
|
|
7910
|
-
out.push({
|
|
7911
|
-
callerAddonId: caller,
|
|
7912
|
-
providerAddonId: provider,
|
|
7913
|
-
capName,
|
|
7914
|
-
callsPerMin,
|
|
7915
|
-
lastCallAtMs: window.lastCallAtMs
|
|
7916
|
-
});
|
|
7917
|
-
}
|
|
7918
|
-
return out;
|
|
7919
|
-
}
|
|
7920
|
-
/** Test / diagnostic helper — drops all recorded calls. */
|
|
7921
|
-
clear() {
|
|
7922
|
-
this.map.clear();
|
|
7923
|
-
}
|
|
7924
|
-
};
|
|
7925
|
-
var singleton = null;
|
|
7926
|
-
/** Hub-side singleton. The first caller seeds it; subsequent calls return the same. */
|
|
7927
|
-
function getCapUsageRegistry() {
|
|
7928
|
-
if (!singleton) singleton = new CapUsageRegistry();
|
|
7929
|
-
return singleton;
|
|
7930
|
-
}
|
|
7931
|
-
/** Test helper — clears the singleton (kept module-private elsewhere). */
|
|
7932
|
-
function __resetCapUsageRegistryForTests() {
|
|
7933
|
-
singleton = null;
|
|
7934
|
-
}
|
|
7935
|
-
//#endregion
|
|
7936
8130
|
//#region src/kernel/hwaccel/hwaccel-resolver.ts
|
|
7937
8131
|
/**
|
|
7938
8132
|
* Platform-probe for hardware video decode acceleration.
|
|
@@ -9867,6 +10061,12 @@ Object.defineProperty(exports, "NATIVE_PROVIDER_SERVICE_INFIX", {
|
|
|
9867
10061
|
return NATIVE_PROVIDER_SERVICE_INFIX;
|
|
9868
10062
|
}
|
|
9869
10063
|
});
|
|
10064
|
+
Object.defineProperty(exports, "PARENT_ROUTED_PROVIDER_ADDON_ID", {
|
|
10065
|
+
enumerable: true,
|
|
10066
|
+
get: function() {
|
|
10067
|
+
return PARENT_ROUTED_PROVIDER_ADDON_ID;
|
|
10068
|
+
}
|
|
10069
|
+
});
|
|
9870
10070
|
Object.defineProperty(exports, "RSS_BUDGET_REANNOUNCE_MIN_MS", {
|
|
9871
10071
|
enumerable: true,
|
|
9872
10072
|
get: function() {
|