@camstack/system 1.1.18 → 1.1.19
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/index.d.ts +1 -0
- package/dist/index.js +42 -50
- package/dist/index.mjs +42 -50
- package/dist/kernel/transport/local-child-registry.d.ts +11 -0
- package/dist/{manifest-python-deps-DOAh19rY.mjs → manifest-python-deps-C1Dd9MSr.mjs} +7 -2
- package/dist/{manifest-python-deps-lZd5B4FS.js → manifest-python-deps-Dt5XNSyd.js} +7 -2
- package/dist/notification/notification-service.d.ts +29 -23
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-Dt5XNSyd.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_chunk.__toESM(node_fs);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as getWorkerNativeCapProvider, N as createUdsLoggerWithControl, P as LocalChildClient, _t as resolveAddonClass, et as getWorkerNativeCapSnapshot, gt as installManifestNativeDeps, i as createUdsAddonContext, it as validateProviderRegistrations, nt as setWorkerNativeCapsChangeListener, t as installManifestPythonDeps } from "./manifest-python-deps-
|
|
1
|
+
import { $ as getWorkerNativeCapProvider, N as createUdsLoggerWithControl, P as LocalChildClient, _t as resolveAddonClass, et as getWorkerNativeCapSnapshot, gt as installManifestNativeDeps, i as createUdsAddonContext, it as validateProviderRegistrations, nt as setWorkerNativeCapsChangeListener, t as installManifestPythonDeps } from "./manifest-python-deps-C1Dd9MSr.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as fs from "node:fs";
|
package/dist/index.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ export type { UserRecord, UserStorageAccess, UserConfigReader } from './auth/use
|
|
|
72
72
|
export { ScopedTokenManager } from './auth/scoped-token-manager.js';
|
|
73
73
|
export { scopesAllowDeviceCap } from './auth/scope-matcher.js';
|
|
74
74
|
export { NotificationService } from './notification/notification-service.js';
|
|
75
|
+
export type { NotificationTargetRef } from './notification/notification-service.js';
|
|
75
76
|
export { ToastService } from './notification/toast-service.js';
|
|
76
77
|
export type { Unsubscribe } from './notification/toast-service.js';
|
|
77
78
|
export { AddonRouteRegistry } from './addon-routes/addon-route-registry.js';
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ const require_builtins_local_auth_local_auth_addon = require("./builtins/local-a
|
|
|
20
20
|
require("./builtins/local-auth/index.js");
|
|
21
21
|
const require_builtins_device_manager_device_manager_addon = require("./builtins/device-manager/device-manager.addon.js");
|
|
22
22
|
require("./builtins/device-manager/index.js");
|
|
23
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
23
|
+
const require_manifest_python_deps = require("./manifest-python-deps-Dt5XNSyd.js");
|
|
24
24
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
25
25
|
let _camstack_types_node = require("@camstack/types/node");
|
|
26
26
|
let node_http = require("node:http");
|
|
@@ -1493,16 +1493,17 @@ function scopesAllowDeviceCap(scopes, access) {
|
|
|
1493
1493
|
//#endregion
|
|
1494
1494
|
//#region src/notification/notification-service.ts
|
|
1495
1495
|
/**
|
|
1496
|
-
* Central notification service that routes notifications to
|
|
1497
|
-
* Framework-agnostic —
|
|
1496
|
+
* Central notification service that routes canonical notifications to
|
|
1497
|
+
* configured `(addonId, targetId)` targets. Framework-agnostic —
|
|
1498
|
+
* dependencies injected via constructor.
|
|
1498
1499
|
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
1500
|
+
* Providers are resolved from the ICapabilityRegistry by `addonId` on each
|
|
1501
|
+
* call (proxy pattern). Falls back to a local map when no registry is
|
|
1502
|
+
* provided (tests / backward compat).
|
|
1502
1503
|
*/
|
|
1503
1504
|
var NotificationService = class {
|
|
1504
1505
|
logger;
|
|
1505
|
-
|
|
1506
|
+
localProviders = /* @__PURE__ */ new Map();
|
|
1506
1507
|
routing = /* @__PURE__ */ new Map();
|
|
1507
1508
|
rateLimits = /* @__PURE__ */ new Map();
|
|
1508
1509
|
lastSent = /* @__PURE__ */ new Map();
|
|
@@ -1510,35 +1511,28 @@ var NotificationService = class {
|
|
|
1510
1511
|
constructor(logger) {
|
|
1511
1512
|
this.logger = logger;
|
|
1512
1513
|
}
|
|
1513
|
-
/** Set the registry for live
|
|
1514
|
+
/** Set the registry for live provider lookup. Called once during boot. */
|
|
1514
1515
|
setRegistry(registry) {
|
|
1515
1516
|
this.registry = registry;
|
|
1516
1517
|
}
|
|
1517
|
-
/** Resolve
|
|
1518
|
-
|
|
1519
|
-
if (this.registry)
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}
|
|
1527
|
-
/** Register an output in the local fallback map (used when no registry is set). */
|
|
1528
|
-
registerLocalOutput(output) {
|
|
1529
|
-
this.localOutputs.set(output.id, output);
|
|
1530
|
-
this.logger.info("Notification output added", { meta: {
|
|
1531
|
-
name: output.name,
|
|
1532
|
-
outputId: output.id
|
|
1533
|
-
} });
|
|
1518
|
+
/** Resolve the collection provider for an addon — registry first, then local map. */
|
|
1519
|
+
resolveProvider(addonId) {
|
|
1520
|
+
if (this.registry) return this.registry.getProviderByAddon("notification-output", addonId) ?? void 0;
|
|
1521
|
+
return this.localProviders.get(addonId);
|
|
1522
|
+
}
|
|
1523
|
+
/** Register a provider in the local fallback map (used when no registry is set). */
|
|
1524
|
+
registerLocalProvider(addonId, provider) {
|
|
1525
|
+
this.localProviders.set(addonId, provider);
|
|
1526
|
+
this.logger.info("Notification provider added", { meta: { addonId } });
|
|
1534
1527
|
}
|
|
1535
|
-
/** Remove
|
|
1536
|
-
|
|
1537
|
-
this.
|
|
1538
|
-
this.logger.info("Notification
|
|
1528
|
+
/** Remove a provider from the local fallback map. */
|
|
1529
|
+
unregisterLocalProvider(addonId) {
|
|
1530
|
+
this.localProviders.delete(addonId);
|
|
1531
|
+
this.logger.info("Notification provider removed", { meta: { addonId } });
|
|
1539
1532
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1533
|
+
/** Route a category to a set of `(addonId, targetId)` targets. */
|
|
1534
|
+
setRouting(category, targets) {
|
|
1535
|
+
this.routing.set(category, [...targets]);
|
|
1542
1536
|
}
|
|
1543
1537
|
setRateLimit(category, minIntervalMs) {
|
|
1544
1538
|
this.rateLimits.set(category, minIntervalMs);
|
|
@@ -1554,38 +1548,36 @@ var NotificationService = class {
|
|
|
1554
1548
|
return;
|
|
1555
1549
|
}
|
|
1556
1550
|
}
|
|
1557
|
-
const
|
|
1558
|
-
if (
|
|
1551
|
+
const targets = this.routing.get(category) ?? this.routing.get("*") ?? [];
|
|
1552
|
+
if (targets.length === 0) {
|
|
1559
1553
|
this.logger.debug("No routing configured for category", { meta: { category } });
|
|
1560
1554
|
return;
|
|
1561
1555
|
}
|
|
1562
|
-
const currentOutputs = this.outputs;
|
|
1563
1556
|
this.lastSent.set(rateLimitKey, notification.timestamp);
|
|
1564
|
-
|
|
1557
|
+
const { category: _category, timestamp: _timestamp, ...canonical } = notification;
|
|
1558
|
+
await Promise.allSettled(targets.map(async (ref) => {
|
|
1559
|
+
const provider = this.resolveProvider(ref.addonId);
|
|
1560
|
+
if (!provider) {
|
|
1561
|
+
this.logger.debug("No provider for target", { meta: { addonId: ref.addonId } });
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1565
1564
|
try {
|
|
1566
|
-
await
|
|
1565
|
+
await provider.send({
|
|
1566
|
+
targetId: ref.targetId,
|
|
1567
|
+
notification: canonical
|
|
1568
|
+
});
|
|
1567
1569
|
} catch (err) {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
error:
|
|
1570
|
+
this.logger.error("Notification target failed", { meta: {
|
|
1571
|
+
addonId: ref.addonId,
|
|
1572
|
+
targetId: ref.targetId,
|
|
1573
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
1572
1574
|
} });
|
|
1573
1575
|
}
|
|
1574
1576
|
}));
|
|
1575
1577
|
}
|
|
1576
|
-
getOutputs() {
|
|
1577
|
-
return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({
|
|
1578
|
-
id,
|
|
1579
|
-
name,
|
|
1580
|
-
icon
|
|
1581
|
-
}));
|
|
1582
|
-
}
|
|
1583
1578
|
getRouting() {
|
|
1584
1579
|
return this.routing;
|
|
1585
1580
|
}
|
|
1586
|
-
getOutput(id) {
|
|
1587
|
-
return this.outputs.get(id);
|
|
1588
|
-
}
|
|
1589
1581
|
};
|
|
1590
1582
|
//#endregion
|
|
1591
1583
|
//#region src/notification/toast-service.ts
|
package/dist/index.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { LocalAuthAddon, a as require_ms, c as __esmMin, d as __toCommonJS, f as
|
|
|
18
18
|
import "./builtins/local-auth/index.mjs";
|
|
19
19
|
import { DeviceManagerAddon } from "./builtins/device-manager/device-manager.addon.mjs";
|
|
20
20
|
import "./builtins/device-manager/index.mjs";
|
|
21
|
-
import { A as createUdsEventBus, B as CapRouteError, C as ipcParentLink, D as createHubCapForwardService, E as HUB_CAP_FWD_SERVICE, F as LocalChildRegistry, G as UdsLocalTransportServer, H as callWithServiceDiscovery, I as UDS_NO_ROUTE_PREFIX, J as FrameDecoder, K as SocketChannel, L as AGENT_CAP_FWD_ACTION, M as createUdsLogger, N as createUdsLoggerWithControl, O as createParentUnownedCallHandler, P as LocalChildClient, Q as createBrokerDeviceManagerApi, R as AGENT_CAP_FWD_SERVICE, S as ipcChildLink, T as HUB_CAP_FWD_ACTION, U as createLocalTransport, V as classifyCapRoute, W as UdsLocalTransportClient, X as buildNativeCapProxy, Y as encodeFrame, Z as buildUdsNativeCapProxy, _ as __resetCapUsageRegistryForTests, _t as resolveAddonClass, a as getWorkerDeviceRegistry, at as NATIVE_PROVIDER_SERVICE_INFIX, b as brokerTransportLink, c as setHubConnected, ct as capBareAction, d as registerEventBusService, dt as deserializeTypedArrays, f as AddonDepsManager, ft as serializeTypedArrays, g as CapUsageRegistry, gt as installManifestNativeDeps, h as createHwAccelService, ht as CapabilityUnavailableError, i as createUdsAddonContext, it as validateProviderRegistrations, j as udsChildLogToWorkerEntry, k as createUdsEventBridge, l as EVENT_TOPIC_PREFIX, lt as capServiceName, m as resolveHwAccel, mt as CapabilityHandle, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as capActionName, p as createKernelHwAccel, pt as DeviceRegistry, q as localEndpointPath, r as createAddonContext, rt as createAddonService, s as getOrInitReadinessRegistryForClient, st as capActionSuffix, t as installManifestPythonDeps, tt as mountNativeCapService, u as getBrokerEventBus, ut as parseCapAction, v as getCapUsageRegistry, w as localProviderLink, x as buildLinkChain, y as brokerCallForCap, z as CapRouteResolver } from "./manifest-python-deps-
|
|
21
|
+
import { A as createUdsEventBus, B as CapRouteError, C as ipcParentLink, D as createHubCapForwardService, E as HUB_CAP_FWD_SERVICE, F as LocalChildRegistry, G as UdsLocalTransportServer, H as callWithServiceDiscovery, I as UDS_NO_ROUTE_PREFIX, J as FrameDecoder, K as SocketChannel, L as AGENT_CAP_FWD_ACTION, M as createUdsLogger, N as createUdsLoggerWithControl, O as createParentUnownedCallHandler, P as LocalChildClient, Q as createBrokerDeviceManagerApi, R as AGENT_CAP_FWD_SERVICE, S as ipcChildLink, T as HUB_CAP_FWD_ACTION, U as createLocalTransport, V as classifyCapRoute, W as UdsLocalTransportClient, X as buildNativeCapProxy, Y as encodeFrame, Z as buildUdsNativeCapProxy, _ as __resetCapUsageRegistryForTests, _t as resolveAddonClass, a as getWorkerDeviceRegistry, at as NATIVE_PROVIDER_SERVICE_INFIX, b as brokerTransportLink, c as setHubConnected, ct as capBareAction, d as registerEventBusService, dt as deserializeTypedArrays, f as AddonDepsManager, ft as serializeTypedArrays, g as CapUsageRegistry, gt as installManifestNativeDeps, h as createHwAccelService, ht as CapabilityUnavailableError, i as createUdsAddonContext, it as validateProviderRegistrations, j as udsChildLogToWorkerEntry, k as createUdsEventBridge, l as EVENT_TOPIC_PREFIX, lt as capServiceName, m as resolveHwAccel, mt as CapabilityHandle, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as capActionName, p as createKernelHwAccel, pt as DeviceRegistry, q as localEndpointPath, r as createAddonContext, rt as createAddonService, s as getOrInitReadinessRegistryForClient, st as capActionSuffix, t as installManifestPythonDeps, tt as mountNativeCapService, u as getBrokerEventBus, ut as parseCapAction, v as getCapUsageRegistry, w as localProviderLink, x as buildLinkChain, y as brokerCallForCap, z as CapRouteResolver } from "./manifest-python-deps-C1Dd9MSr.mjs";
|
|
22
22
|
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
23
23
|
import { PYTHON_VERSION, buildBinaryPath, downloadBinary, ensureBinary, ensureFfmpeg, ensurePython, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
24
24
|
import { request } from "node:http";
|
|
@@ -1485,16 +1485,17 @@ function scopesAllowDeviceCap(scopes, access) {
|
|
|
1485
1485
|
//#endregion
|
|
1486
1486
|
//#region src/notification/notification-service.ts
|
|
1487
1487
|
/**
|
|
1488
|
-
* Central notification service that routes notifications to
|
|
1489
|
-
* Framework-agnostic —
|
|
1488
|
+
* Central notification service that routes canonical notifications to
|
|
1489
|
+
* configured `(addonId, targetId)` targets. Framework-agnostic —
|
|
1490
|
+
* dependencies injected via constructor.
|
|
1490
1491
|
*
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1492
|
+
* Providers are resolved from the ICapabilityRegistry by `addonId` on each
|
|
1493
|
+
* call (proxy pattern). Falls back to a local map when no registry is
|
|
1494
|
+
* provided (tests / backward compat).
|
|
1494
1495
|
*/
|
|
1495
1496
|
var NotificationService = class {
|
|
1496
1497
|
logger;
|
|
1497
|
-
|
|
1498
|
+
localProviders = /* @__PURE__ */ new Map();
|
|
1498
1499
|
routing = /* @__PURE__ */ new Map();
|
|
1499
1500
|
rateLimits = /* @__PURE__ */ new Map();
|
|
1500
1501
|
lastSent = /* @__PURE__ */ new Map();
|
|
@@ -1502,35 +1503,28 @@ var NotificationService = class {
|
|
|
1502
1503
|
constructor(logger) {
|
|
1503
1504
|
this.logger = logger;
|
|
1504
1505
|
}
|
|
1505
|
-
/** Set the registry for live
|
|
1506
|
+
/** Set the registry for live provider lookup. Called once during boot. */
|
|
1506
1507
|
setRegistry(registry) {
|
|
1507
1508
|
this.registry = registry;
|
|
1508
1509
|
}
|
|
1509
|
-
/** Resolve
|
|
1510
|
-
|
|
1511
|
-
if (this.registry)
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
}
|
|
1519
|
-
/** Register an output in the local fallback map (used when no registry is set). */
|
|
1520
|
-
registerLocalOutput(output) {
|
|
1521
|
-
this.localOutputs.set(output.id, output);
|
|
1522
|
-
this.logger.info("Notification output added", { meta: {
|
|
1523
|
-
name: output.name,
|
|
1524
|
-
outputId: output.id
|
|
1525
|
-
} });
|
|
1510
|
+
/** Resolve the collection provider for an addon — registry first, then local map. */
|
|
1511
|
+
resolveProvider(addonId) {
|
|
1512
|
+
if (this.registry) return this.registry.getProviderByAddon("notification-output", addonId) ?? void 0;
|
|
1513
|
+
return this.localProviders.get(addonId);
|
|
1514
|
+
}
|
|
1515
|
+
/** Register a provider in the local fallback map (used when no registry is set). */
|
|
1516
|
+
registerLocalProvider(addonId, provider) {
|
|
1517
|
+
this.localProviders.set(addonId, provider);
|
|
1518
|
+
this.logger.info("Notification provider added", { meta: { addonId } });
|
|
1526
1519
|
}
|
|
1527
|
-
/** Remove
|
|
1528
|
-
|
|
1529
|
-
this.
|
|
1530
|
-
this.logger.info("Notification
|
|
1520
|
+
/** Remove a provider from the local fallback map. */
|
|
1521
|
+
unregisterLocalProvider(addonId) {
|
|
1522
|
+
this.localProviders.delete(addonId);
|
|
1523
|
+
this.logger.info("Notification provider removed", { meta: { addonId } });
|
|
1531
1524
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1525
|
+
/** Route a category to a set of `(addonId, targetId)` targets. */
|
|
1526
|
+
setRouting(category, targets) {
|
|
1527
|
+
this.routing.set(category, [...targets]);
|
|
1534
1528
|
}
|
|
1535
1529
|
setRateLimit(category, minIntervalMs) {
|
|
1536
1530
|
this.rateLimits.set(category, minIntervalMs);
|
|
@@ -1546,38 +1540,36 @@ var NotificationService = class {
|
|
|
1546
1540
|
return;
|
|
1547
1541
|
}
|
|
1548
1542
|
}
|
|
1549
|
-
const
|
|
1550
|
-
if (
|
|
1543
|
+
const targets = this.routing.get(category) ?? this.routing.get("*") ?? [];
|
|
1544
|
+
if (targets.length === 0) {
|
|
1551
1545
|
this.logger.debug("No routing configured for category", { meta: { category } });
|
|
1552
1546
|
return;
|
|
1553
1547
|
}
|
|
1554
|
-
const currentOutputs = this.outputs;
|
|
1555
1548
|
this.lastSent.set(rateLimitKey, notification.timestamp);
|
|
1556
|
-
|
|
1549
|
+
const { category: _category, timestamp: _timestamp, ...canonical } = notification;
|
|
1550
|
+
await Promise.allSettled(targets.map(async (ref) => {
|
|
1551
|
+
const provider = this.resolveProvider(ref.addonId);
|
|
1552
|
+
if (!provider) {
|
|
1553
|
+
this.logger.debug("No provider for target", { meta: { addonId: ref.addonId } });
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1557
1556
|
try {
|
|
1558
|
-
await
|
|
1557
|
+
await provider.send({
|
|
1558
|
+
targetId: ref.targetId,
|
|
1559
|
+
notification: canonical
|
|
1560
|
+
});
|
|
1559
1561
|
} catch (err) {
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
error:
|
|
1562
|
+
this.logger.error("Notification target failed", { meta: {
|
|
1563
|
+
addonId: ref.addonId,
|
|
1564
|
+
targetId: ref.targetId,
|
|
1565
|
+
error: errMsg(err)
|
|
1564
1566
|
} });
|
|
1565
1567
|
}
|
|
1566
1568
|
}));
|
|
1567
1569
|
}
|
|
1568
|
-
getOutputs() {
|
|
1569
|
-
return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({
|
|
1570
|
-
id,
|
|
1571
|
-
name,
|
|
1572
|
-
icon
|
|
1573
|
-
}));
|
|
1574
|
-
}
|
|
1575
1570
|
getRouting() {
|
|
1576
1571
|
return this.routing;
|
|
1577
1572
|
}
|
|
1578
|
-
getOutput(id) {
|
|
1579
|
-
return this.outputs.get(id);
|
|
1580
|
-
}
|
|
1581
1573
|
};
|
|
1582
1574
|
//#endregion
|
|
1583
1575
|
//#region src/notification/toast-service.ts
|
|
@@ -38,6 +38,16 @@ export interface LocalChildRegistryOptions {
|
|
|
38
38
|
* preference is set or the cap is not a singleton.
|
|
39
39
|
*/
|
|
40
40
|
readonly getActiveSingletonAddonId?: (capName: string) => string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve an addonId to its runner/child id — the addon's
|
|
43
|
+
* `execution.group` when it declares one, else the addon id itself
|
|
44
|
+
* (`resolveRunnerId`). Needed so the active-singleton preference (which
|
|
45
|
+
* is expressed as an addonId) can be matched against the registry's
|
|
46
|
+
* candidate CHILD ids: a grouped addon's child id is the group name, not
|
|
47
|
+
* its own id. Omitted → identity (addonId === childId), preserving the
|
|
48
|
+
* solo-runner behaviour for every ungrouped addon.
|
|
49
|
+
*/
|
|
50
|
+
readonly resolveChildIdForAddon?: (addonId: string) => string;
|
|
41
51
|
}
|
|
42
52
|
/**
|
|
43
53
|
* Parent-side authority for local addon-runners reachable over a
|
|
@@ -56,6 +66,7 @@ export declare class LocalChildRegistry {
|
|
|
56
66
|
private readonly onUnownedCall?;
|
|
57
67
|
private readonly logger?;
|
|
58
68
|
private readonly getActiveSingletonAddonId?;
|
|
69
|
+
private readonly resolveChildIdForAddon?;
|
|
59
70
|
/** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
|
|
60
71
|
private readonly egressRoutedCaps;
|
|
61
72
|
/**
|
|
@@ -3776,6 +3776,7 @@ var LocalChildRegistry = class {
|
|
|
3776
3776
|
onUnownedCall;
|
|
3777
3777
|
logger;
|
|
3778
3778
|
getActiveSingletonAddonId;
|
|
3779
|
+
resolveChildIdForAddon;
|
|
3779
3780
|
/** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
|
|
3780
3781
|
egressRoutedCaps = /* @__PURE__ */ new Set();
|
|
3781
3782
|
/**
|
|
@@ -3796,6 +3797,7 @@ var LocalChildRegistry = class {
|
|
|
3796
3797
|
this.onUnownedCall = opts.onUnownedCall;
|
|
3797
3798
|
this.logger = opts.logger;
|
|
3798
3799
|
this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
|
|
3800
|
+
this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
|
|
3799
3801
|
} else {
|
|
3800
3802
|
this.server = serverOrOptions;
|
|
3801
3803
|
this.onUnownedCall = onUnownedCallArg;
|
|
@@ -3829,8 +3831,11 @@ var LocalChildRegistry = class {
|
|
|
3829
3831
|
const candidates = this.findAllChildIds((cap) => cap.capName === capName && cap.deviceId === void 0);
|
|
3830
3832
|
if (candidates.length === 0) return null;
|
|
3831
3833
|
if (candidates.length === 1) return candidates[0];
|
|
3832
|
-
const
|
|
3833
|
-
if (
|
|
3834
|
+
const preferredAddonId = this.getActiveSingletonAddonId?.(capName) ?? null;
|
|
3835
|
+
if (preferredAddonId !== null) {
|
|
3836
|
+
const preferredChildId = this.resolveChildIdForAddon?.(preferredAddonId) ?? preferredAddonId;
|
|
3837
|
+
if (candidates.includes(preferredChildId)) return preferredChildId;
|
|
3838
|
+
}
|
|
3834
3839
|
return candidates[0];
|
|
3835
3840
|
}
|
|
3836
3841
|
/** First child whose cap manifest contains a descriptor matching `predicate`. */
|
|
@@ -3778,6 +3778,7 @@ var LocalChildRegistry = class {
|
|
|
3778
3778
|
onUnownedCall;
|
|
3779
3779
|
logger;
|
|
3780
3780
|
getActiveSingletonAddonId;
|
|
3781
|
+
resolveChildIdForAddon;
|
|
3781
3782
|
/** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
|
|
3782
3783
|
egressRoutedCaps = /* @__PURE__ */ new Set();
|
|
3783
3784
|
/**
|
|
@@ -3798,6 +3799,7 @@ var LocalChildRegistry = class {
|
|
|
3798
3799
|
this.onUnownedCall = opts.onUnownedCall;
|
|
3799
3800
|
this.logger = opts.logger;
|
|
3800
3801
|
this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
|
|
3802
|
+
this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
|
|
3801
3803
|
} else {
|
|
3802
3804
|
this.server = serverOrOptions;
|
|
3803
3805
|
this.onUnownedCall = onUnownedCallArg;
|
|
@@ -3831,8 +3833,11 @@ var LocalChildRegistry = class {
|
|
|
3831
3833
|
const candidates = this.findAllChildIds((cap) => cap.capName === capName && cap.deviceId === void 0);
|
|
3832
3834
|
if (candidates.length === 0) return null;
|
|
3833
3835
|
if (candidates.length === 1) return candidates[0];
|
|
3834
|
-
const
|
|
3835
|
-
if (
|
|
3836
|
+
const preferredAddonId = this.getActiveSingletonAddonId?.(capName) ?? null;
|
|
3837
|
+
if (preferredAddonId !== null) {
|
|
3838
|
+
const preferredChildId = this.resolveChildIdForAddon?.(preferredAddonId) ?? preferredAddonId;
|
|
3839
|
+
if (candidates.includes(preferredChildId)) return preferredChildId;
|
|
3840
|
+
}
|
|
3836
3841
|
return candidates[0];
|
|
3837
3842
|
}
|
|
3838
3843
|
/** First child whose cap manifest contains a descriptor matching `predicate`. */
|
|
@@ -1,37 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { INotificationOutputProvider, RoutedNotification, ICapabilityRegistry } from '@camstack/types';
|
|
2
2
|
import { IScopedLogger } from '../logging/scoped-logger.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A routing destination: one target (`targetId`) owned by one provider
|
|
5
|
+
* (`addonId`). The notifiers addon and the HA addon each register a
|
|
6
|
+
* `notification-output` collection provider; the service resolves the
|
|
7
|
+
* provider by `addonId` and dispatches to the specific target.
|
|
8
|
+
*/
|
|
9
|
+
export interface NotificationTargetRef {
|
|
10
|
+
readonly addonId: string;
|
|
11
|
+
readonly targetId: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Central notification service that routes canonical notifications to
|
|
15
|
+
* configured `(addonId, targetId)` targets. Framework-agnostic —
|
|
16
|
+
* dependencies injected via constructor.
|
|
6
17
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
18
|
+
* Providers are resolved from the ICapabilityRegistry by `addonId` on each
|
|
19
|
+
* call (proxy pattern). Falls back to a local map when no registry is
|
|
20
|
+
* provided (tests / backward compat).
|
|
10
21
|
*/
|
|
11
22
|
export declare class NotificationService {
|
|
12
23
|
private readonly logger;
|
|
13
|
-
private readonly
|
|
24
|
+
private readonly localProviders;
|
|
14
25
|
private readonly routing;
|
|
15
26
|
private readonly rateLimits;
|
|
16
27
|
private readonly lastSent;
|
|
17
28
|
private registry;
|
|
18
29
|
constructor(logger: IScopedLogger);
|
|
19
|
-
/** Set the registry for live
|
|
30
|
+
/** Set the registry for live provider lookup. Called once during boot. */
|
|
20
31
|
setRegistry(registry: ICapabilityRegistry): void;
|
|
21
|
-
/** Resolve
|
|
22
|
-
private
|
|
23
|
-
/** Register
|
|
24
|
-
|
|
25
|
-
/** Remove
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
/** Resolve the collection provider for an addon — registry first, then local map. */
|
|
33
|
+
private resolveProvider;
|
|
34
|
+
/** Register a provider in the local fallback map (used when no registry is set). */
|
|
35
|
+
registerLocalProvider(addonId: string, provider: INotificationOutputProvider): void;
|
|
36
|
+
/** Remove a provider from the local fallback map. */
|
|
37
|
+
unregisterLocalProvider(addonId: string): void;
|
|
38
|
+
/** Route a category to a set of `(addonId, targetId)` targets. */
|
|
39
|
+
setRouting(category: string, targets: readonly NotificationTargetRef[]): void;
|
|
28
40
|
setRateLimit(category: string, minIntervalMs: number): void;
|
|
29
|
-
notify(notification:
|
|
30
|
-
|
|
31
|
-
id: string;
|
|
32
|
-
name: string;
|
|
33
|
-
icon: string;
|
|
34
|
-
}>;
|
|
35
|
-
getRouting(): ReadonlyMap<string, string[]>;
|
|
36
|
-
getOutput(id: string): INotificationOutput | undefined;
|
|
41
|
+
notify(notification: RoutedNotification): Promise<void>;
|
|
42
|
+
getRouting(): ReadonlyMap<string, NotificationTargetRef[]>;
|
|
37
43
|
}
|