@camstack/system 1.0.6 → 1.0.8
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 +40 -23
- package/dist/addon-runner.mjs +20 -4
- package/dist/addon-utils.d.ts +20 -0
- package/dist/addon-utils.js +11 -0
- package/dist/addon-utils.mjs +3 -0
- package/dist/builtins/device-manager/device-manager.addon.js +8 -8
- package/dist/builtins/device-manager/device-manager.addon.mjs +8 -8
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +8 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +50 -3
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +50 -3
- package/dist/builtins/platform-probe/index.js +27 -139
- package/dist/builtins/platform-probe/index.mjs +28 -140
- package/dist/builtins/platform-probe/platform-scorer.d.ts +17 -10
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
- package/dist/custom-action-registry-BEXwC-oo.mjs +38 -0
- package/dist/custom-action-registry-vLYEFTtv.js +43 -0
- package/dist/index.js +129 -779
- package/dist/index.mjs +100 -750
- package/dist/kernel/config-manager.d.ts +4 -4
- package/dist/kernel/fs-utils.d.ts +16 -6
- package/dist/kernel/index.d.ts +1 -1
- package/dist/kernel/moleculer/device-cap-proxy.d.ts +2 -1
- package/dist/kernel/moleculer/readiness-context.d.ts +2 -1
- package/dist/kernel/transport/child-cap-protocol.d.ts +10 -0
- package/dist/{manifest-python-deps-B4BmMoGT.js → manifest-python-deps-BWURo7dc.js} +62 -88
- package/dist/{manifest-python-deps-CXbKrOdk.mjs → manifest-python-deps-BcrTzHH_.mjs} +55 -75
- package/dist/model-download-service-C7AjBsX9.mjs +668 -0
- package/dist/model-download-service-JtVQtbb6.js +752 -0
- package/dist/process/resource-monitor.d.ts +9 -0
- package/dist/{resource-monitor-ClDGFyf6.mjs → resource-monitor-BkP504Vq.mjs} +20 -1
- package/dist/{resource-monitor-IIEanuJt.js → resource-monitor-DNNomR-i.js} +21 -1
- package/package.json +6 -1
|
@@ -79,8 +79,8 @@ export declare class ConfigManager {
|
|
|
79
79
|
* as a convenience alias for legacy call sites; it performs NO runtime
|
|
80
80
|
* check and is the one documented type-level bridge in this function.
|
|
81
81
|
*/
|
|
82
|
-
get(
|
|
83
|
-
get<T>(
|
|
82
|
+
get(configPath: string): unknown;
|
|
83
|
+
get<T>(configPath: string): T | undefined;
|
|
84
84
|
private resolveConfigValue;
|
|
85
85
|
/**
|
|
86
86
|
* Write a value to the settings-store.
|
|
@@ -171,8 +171,8 @@ export declare class ConfigManager {
|
|
|
171
171
|
/** Get a value from the parsed bootstrap config.
|
|
172
172
|
* Generic overload is a documented type-level bridge — callers are responsible
|
|
173
173
|
* for passing a T that matches the config.yaml shape. */
|
|
174
|
-
getBootstrap(
|
|
175
|
-
getBootstrap<T>(
|
|
174
|
+
getBootstrap(configPath: string): unknown;
|
|
175
|
+
getBootstrap<T>(configPath: string): T | undefined;
|
|
176
176
|
/** Features accessor -- reads from settings-store when available, falls back to RUNTIME_DEFAULTS */
|
|
177
177
|
get features(): FeatureManifest;
|
|
178
178
|
/**
|
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare function ensureDir(dirPath: string): void;
|
|
6
6
|
/**
|
|
7
|
-
* Copy a directory recursively.
|
|
8
|
-
*
|
|
7
|
+
* Copy a directory recursively — ASYNC so it never blocks the event loop.
|
|
8
|
+
*
|
|
9
|
+
* The hub installs addons into `/data/addons`, which on Unraid is a slow
|
|
10
|
+
* shfs/FUSE mount. The former synchronous `fs.copyFileSync`-per-file loop
|
|
11
|
+
* blocked the Node event loop for the whole copy of a large bundle (e.g.
|
|
12
|
+
* `addon-pipeline`), which froze the hub's HTTP listener mid-`camstack deploy`
|
|
13
|
+
* (accept backlog piling up, existing connections stuck in CLOSE_WAIT). Using
|
|
14
|
+
* `fs.promises.cp` keeps the I/O off the event loop. (Node ≥18 stable.)
|
|
9
15
|
*/
|
|
10
|
-
export declare function copyDirRecursive(src: string, dest: string): void
|
|
16
|
+
export declare function copyDirRecursive(src: string, dest: string): Promise<void>;
|
|
11
17
|
/**
|
|
12
18
|
* Strip @camstack/* dependencies and devDependencies from a package.json object.
|
|
13
19
|
* Used when installing addons into the addons directory — @camstack packages
|
|
@@ -21,7 +27,7 @@ export declare function stripCamstackDeps(pkg: Record<string, unknown>): Record<
|
|
|
21
27
|
* Copies directories (not individual files) from source to destination.
|
|
22
28
|
* Skips "dist" (already handled) and glob patterns.
|
|
23
29
|
*/
|
|
24
|
-
export declare function copyExtraFileDirs(pkgJson: Record<string, unknown>, sourceDir: string, destDir: string): void
|
|
30
|
+
export declare function copyExtraFileDirs(pkgJson: Record<string, unknown>, sourceDir: string, destDir: string): Promise<void>;
|
|
25
31
|
/**
|
|
26
32
|
* Check if any file in src/ is newer than dist/.
|
|
27
33
|
* Returns true if rebuild is needed.
|
|
@@ -36,6 +42,10 @@ export declare function ensureLibraryBuilt(packageName: string, packagesDir: str
|
|
|
36
42
|
/**
|
|
37
43
|
* Install a single npm package into a target directory (package.json + dist/).
|
|
38
44
|
* No validation on camstack.addons -- works for any @camstack/* package.
|
|
39
|
-
*
|
|
45
|
+
*
|
|
46
|
+
* ASYNC: uses `execFile`/`fs.promises` throughout so a package install on a
|
|
47
|
+
* live node never blocks the event loop (the `npm pack` + tar extract + copy to
|
|
48
|
+
* the slow shfs/FUSE `/data` would otherwise freeze the HTTP listener). See
|
|
49
|
+
* `copyDirRecursive` for the wedge this prevents.
|
|
40
50
|
*/
|
|
41
|
-
export declare function
|
|
51
|
+
export declare function installPackageFromNpm(packageName: string, targetDir: string): Promise<void>;
|
package/dist/kernel/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { AddonInstallerConfig, InstallSource, InstalledPackage } from './ad
|
|
|
5
5
|
export { AddonInstaller } from './addon-installer.js';
|
|
6
6
|
export type { AddonInstallSource, AddonManifestEntry, AddonManifestFile } from './addon-manifest.js';
|
|
7
7
|
export { AddonManifest } from './addon-manifest.js';
|
|
8
|
-
export { copyDirRecursive, ensureDir, stripCamstackDeps, copyExtraFileDirs, ensureLibraryBuilt,
|
|
8
|
+
export { copyDirRecursive, ensureDir, stripCamstackDeps, copyExtraFileDirs, ensureLibraryBuilt, installPackageFromNpm, isSourceNewer, } from './fs-utils.js';
|
|
9
9
|
export { detectWorkspacePackagesDir } from './workspace-detect.js';
|
|
10
10
|
export { RESTART_MARKER_FILE, clearPendingRestart, getRestartMarkerPath, readPendingRestart, scheduleSelfRestart, writePendingRestart, } from './restart-coordinator.js';
|
|
11
11
|
export type { PendingRestartMarker, RestartKind, ScheduleSelfRestartOptions, } from './restart-coordinator.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { deviceOpsCapability
|
|
1
|
+
import { deviceOpsCapability } from '@camstack/types/addon';
|
|
2
|
+
import { AddonApi, CapabilityDefinition, DeviceManagerApi, IDevice, IEventBus, IKernelStreamProbe, IScopedLogger, InferProvider } from '@camstack/types';
|
|
2
3
|
import { ServiceBroker } from 'moleculer';
|
|
3
4
|
import { DeviceRegistry } from '../device-registry.js';
|
|
4
5
|
import { CapabilityRegistry } from '../capability-registry.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ServiceBroker } from 'moleculer';
|
|
2
|
-
import { IEventBus, IScopedLogger
|
|
2
|
+
import { IEventBus, IScopedLogger } from '@camstack/types';
|
|
3
|
+
import { ReadinessRegistry } from '@camstack/types/addon';
|
|
3
4
|
/**
|
|
4
5
|
* Minimal interface for the `LocalChildClient` surface used in UDS-mode
|
|
5
6
|
* readiness hydration. Declared here (rather than importing the concrete
|
|
@@ -23,6 +23,14 @@ export interface CapCallOutMessage {
|
|
|
23
23
|
readonly method: string;
|
|
24
24
|
readonly args: unknown;
|
|
25
25
|
readonly deviceId?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Optional per-call node pin (out-of-band; NOT part of the validated method
|
|
28
|
+
* args). When set, the parent routes this singleton/in-process cap call to
|
|
29
|
+
* the named node's provider instead of the default (hub) resolution — used to
|
|
30
|
+
* query a remote agent's in-process singleton (e.g. the agent's own
|
|
31
|
+
* `platform-probe` hardware). Set via `ctx.api`'s `onNode(nodeId)` modifier.
|
|
32
|
+
*/
|
|
33
|
+
readonly nodeId?: string;
|
|
26
34
|
}
|
|
27
35
|
/** Child → parent: a system event produced by the child to be forwarded to the hub event bus. */
|
|
28
36
|
export interface ChildEventMessage {
|
|
@@ -59,6 +67,8 @@ export interface CapCallMessage {
|
|
|
59
67
|
readonly method: string;
|
|
60
68
|
readonly args: unknown;
|
|
61
69
|
readonly deviceId?: number;
|
|
70
|
+
/** Optional per-call node pin (out-of-band routing hint; see {@link CapCallOutMessage.nodeId}). */
|
|
71
|
+
readonly nodeId?: string;
|
|
62
72
|
}
|
|
63
73
|
/** Parent → child: a system event delivered by the hub for the child to handle locally. */
|
|
64
74
|
export interface ParentEventMessage {
|
|
@@ -13,6 +13,7 @@ let node_util = require("node:util");
|
|
|
13
13
|
let node_os = require("node:os");
|
|
14
14
|
node_os = require_chunk.__toESM(node_os);
|
|
15
15
|
let node_fs_promises = require("node:fs/promises");
|
|
16
|
+
let _camstack_types_addon = require("@camstack/types/addon");
|
|
16
17
|
let _trpc_client = require("@trpc/client");
|
|
17
18
|
let node_net = require("node:net");
|
|
18
19
|
//#region src/kernel/addon-class-resolver.ts
|
|
@@ -103,7 +104,7 @@ async function installManifestNativeDeps(addonDir, pkgRaw, logger, registry) {
|
|
|
103
104
|
} catch (err) {
|
|
104
105
|
logger.warn("Failed to write native deps marker", { meta: {
|
|
105
106
|
markerFile,
|
|
106
|
-
error: (0,
|
|
107
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
107
108
|
} });
|
|
108
109
|
}
|
|
109
110
|
return;
|
|
@@ -130,7 +131,7 @@ async function installManifestNativeDeps(addonDir, pkgRaw, logger, registry) {
|
|
|
130
131
|
timeout: 3e5
|
|
131
132
|
});
|
|
132
133
|
} catch (err) {
|
|
133
|
-
throw new Error(`npm install of native deps failed for ${addonDir}: ${(0,
|
|
134
|
+
throw new Error(`npm install of native deps failed for ${addonDir}: ${(0, _camstack_types_addon.errMsg)(err)}`, { cause: err });
|
|
134
135
|
}
|
|
135
136
|
await rebuildNativeDeps(addonDir, pending.map(([name]) => name), logger);
|
|
136
137
|
try {
|
|
@@ -138,7 +139,7 @@ async function installManifestNativeDeps(addonDir, pkgRaw, logger, registry) {
|
|
|
138
139
|
} catch (err) {
|
|
139
140
|
logger.warn("Failed to write native deps marker", { meta: {
|
|
140
141
|
markerFile,
|
|
141
|
-
error: (0,
|
|
142
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
142
143
|
} });
|
|
143
144
|
}
|
|
144
145
|
}
|
|
@@ -175,7 +176,7 @@ function copyPrebuiltNativeDep(name, addonDir, logger) {
|
|
|
175
176
|
logger.warn("Prebuilt native dep copy failed — will try npm install", { meta: {
|
|
176
177
|
name,
|
|
177
178
|
source,
|
|
178
|
-
error: (0,
|
|
179
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
179
180
|
} });
|
|
180
181
|
}
|
|
181
182
|
}
|
|
@@ -208,13 +209,13 @@ function candidateHoistedDirs(name, addonDir) {
|
|
|
208
209
|
}
|
|
209
210
|
/** Read & validate `camstack.nativeDependencies`. Returns null when absent. */
|
|
210
211
|
function readNativeDeps(pkgRaw) {
|
|
211
|
-
const camstack = (0,
|
|
212
|
+
const camstack = (0, _camstack_types_addon.asJsonObject)(pkgRaw["camstack"]);
|
|
212
213
|
if (!camstack) return null;
|
|
213
|
-
const native = (0,
|
|
214
|
+
const native = (0, _camstack_types_addon.asJsonObject)(camstack["nativeDependencies"]);
|
|
214
215
|
if (!native) return null;
|
|
215
216
|
const out = {};
|
|
216
217
|
for (const [k, v] of Object.entries(native)) {
|
|
217
|
-
const range = (0,
|
|
218
|
+
const range = (0, _camstack_types_addon.asString)(v);
|
|
218
219
|
if (range) out[k] = range;
|
|
219
220
|
}
|
|
220
221
|
return Object.keys(out).length > 0 ? out : null;
|
|
@@ -281,7 +282,7 @@ async function rebuildNativeDeps(addonDir, packageNames, logger) {
|
|
|
281
282
|
} catch (err) {
|
|
282
283
|
logger.warn("Electron rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
283
284
|
addonDir,
|
|
284
|
-
error: (0,
|
|
285
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
285
286
|
} });
|
|
286
287
|
}
|
|
287
288
|
return;
|
|
@@ -299,7 +300,7 @@ async function rebuildNativeDeps(addonDir, packageNames, logger) {
|
|
|
299
300
|
} catch (err) {
|
|
300
301
|
logger.warn("npm rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
301
302
|
addonDir,
|
|
302
|
-
error: (0,
|
|
303
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
303
304
|
} });
|
|
304
305
|
}
|
|
305
306
|
}
|
|
@@ -382,43 +383,6 @@ var CapabilityHandle = class {
|
|
|
382
383
|
}
|
|
383
384
|
};
|
|
384
385
|
//#endregion
|
|
385
|
-
//#region src/kernel/custom-action-registry.ts
|
|
386
|
-
/**
|
|
387
|
-
* CustomActionRegistry — per-process registry of addon custom actions.
|
|
388
|
-
*
|
|
389
|
-
* Populated at boot from each addon's `AddonInitResult.customActions` +
|
|
390
|
-
* `handleCustomAction` handler. Rejects actions declared with scope other
|
|
391
|
-
* than 'system' (today only 'system' is runtime-supported; the descriptor
|
|
392
|
-
* allows future scopes for forward compat).
|
|
393
|
-
*/
|
|
394
|
-
var CustomActionRegistry = class {
|
|
395
|
-
byAddon = /* @__PURE__ */ new Map();
|
|
396
|
-
registerAddon(addonId, catalog, handler) {
|
|
397
|
-
const actions = /* @__PURE__ */ new Map();
|
|
398
|
-
for (const [name, spec] of Object.entries(catalog)) {
|
|
399
|
-
const scope = spec.scope ?? { kind: "system" };
|
|
400
|
-
if (scope.kind !== "system") throw new Error(`custom action '${addonId}.${name}' declared scope '${scope.kind}' — not yet implemented`);
|
|
401
|
-
actions.set(name, {
|
|
402
|
-
spec,
|
|
403
|
-
handler: (input) => handler(name, input)
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
this.byAddon.set(addonId, actions);
|
|
407
|
-
}
|
|
408
|
-
unregisterAddon(addonId) {
|
|
409
|
-
this.byAddon.delete(addonId);
|
|
410
|
-
}
|
|
411
|
-
resolve(addonId, action) {
|
|
412
|
-
return this.byAddon.get(addonId)?.get(action) ?? null;
|
|
413
|
-
}
|
|
414
|
-
listActions(addonId) {
|
|
415
|
-
return [...this.byAddon.get(addonId)?.keys() ?? []];
|
|
416
|
-
}
|
|
417
|
-
listAddons() {
|
|
418
|
-
return [...this.byAddon.keys()];
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
//#endregion
|
|
422
386
|
//#region src/kernel/device-registry.ts
|
|
423
387
|
var DeviceRegistry = class {
|
|
424
388
|
/** Primary map: every registered device keyed by its progressive
|
|
@@ -963,7 +927,7 @@ var nativeCapReadinessGeneration = typeof crypto !== "undefined" && crypto.rando
|
|
|
963
927
|
function mountNativeCapService(broker, addonId, cap) {
|
|
964
928
|
const serviceName = capServiceName(addonId, cap.name, true);
|
|
965
929
|
if (mountedNativeCapServices.has(serviceName)) return;
|
|
966
|
-
const expandedMethods = (0,
|
|
930
|
+
const expandedMethods = (0, _camstack_types_addon.expandCapMethods)(cap);
|
|
967
931
|
if (expandedMethods === void 0 || Object.keys(expandedMethods).length === 0 || typeof broker.createService !== "function") {
|
|
968
932
|
mountedNativeCapServices.add(serviceName);
|
|
969
933
|
return;
|
|
@@ -1069,7 +1033,7 @@ async function callWithServiceDiscoveryRetry(broker, actionName, input) {
|
|
|
1069
1033
|
if (!(err instanceof Error ? err.message : String(err)).includes("is not found")) throw err;
|
|
1070
1034
|
attempt++;
|
|
1071
1035
|
if (attempt === 1) broker.logger.warn(`native-cap-bridge: service not found for "${actionName}", retrying with exponential backoff…`);
|
|
1072
|
-
await (0,
|
|
1036
|
+
await (0, _camstack_types_addon.sleep)(delay);
|
|
1073
1037
|
delay = Math.min(delay * 2, BACKOFF_MAX_MS);
|
|
1074
1038
|
}
|
|
1075
1039
|
}
|
|
@@ -1174,7 +1138,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1174
1138
|
parentDeviceId,
|
|
1175
1139
|
logger: (() => {
|
|
1176
1140
|
const base = opts.logger.child(stableId);
|
|
1177
|
-
const containerDeviceId = parentDeviceId ?? (deviceMeta?.type ===
|
|
1141
|
+
const containerDeviceId = parentDeviceId ?? (deviceMeta?.type === _camstack_types_addon.DeviceType.Container ? id : null);
|
|
1178
1142
|
return base.withTags(containerDeviceId !== null ? {
|
|
1179
1143
|
deviceId: id,
|
|
1180
1144
|
containerDeviceId
|
|
@@ -1200,7 +1164,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1200
1164
|
id,
|
|
1201
1165
|
stableId,
|
|
1202
1166
|
addonId,
|
|
1203
|
-
type:
|
|
1167
|
+
type: _camstack_types_addon.DeviceType.Camera,
|
|
1204
1168
|
name: stableId,
|
|
1205
1169
|
location: null,
|
|
1206
1170
|
disabled: false,
|
|
@@ -1208,7 +1172,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1208
1172
|
metadata: null
|
|
1209
1173
|
},
|
|
1210
1174
|
fetchDevice: async (deviceId) => {
|
|
1211
|
-
return (0,
|
|
1175
|
+
return (0, _camstack_types_addon.createDeviceProxy)(api, await api.deviceManager.getBindings.query({ deviceId }));
|
|
1212
1176
|
},
|
|
1213
1177
|
get devices() {
|
|
1214
1178
|
return selfApi;
|
|
@@ -1266,7 +1230,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1266
1230
|
type: "device",
|
|
1267
1231
|
id
|
|
1268
1232
|
},
|
|
1269
|
-
category:
|
|
1233
|
+
category: _camstack_types_addon.EventCategory.DeviceBindingsChanged,
|
|
1270
1234
|
data: {
|
|
1271
1235
|
deviceId: id,
|
|
1272
1236
|
capName: cap.name,
|
|
@@ -1275,7 +1239,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1275
1239
|
nodeId
|
|
1276
1240
|
}
|
|
1277
1241
|
});
|
|
1278
|
-
(0,
|
|
1242
|
+
(0, _camstack_types_addon.emitReadiness)(eventBus, {
|
|
1279
1243
|
capName: cap.name,
|
|
1280
1244
|
scope: {
|
|
1281
1245
|
type: "device",
|
|
@@ -1513,7 +1477,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1513
1477
|
},
|
|
1514
1478
|
register: async (device) => {
|
|
1515
1479
|
registry.register(addonId, device);
|
|
1516
|
-
buildContext(device.stableId, device.id, device.parentDeviceId).registerNativeCap(
|
|
1480
|
+
buildContext(device.stableId, device.id, device.parentDeviceId).registerNativeCap(_camstack_types_addon.deviceOpsCapability, buildDeviceOpsProvider(device));
|
|
1517
1481
|
try {
|
|
1518
1482
|
await callDeviceManager(api, "registerDevice", {
|
|
1519
1483
|
addonId,
|
|
@@ -1650,7 +1614,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1650
1614
|
type: "device",
|
|
1651
1615
|
id: device.id
|
|
1652
1616
|
},
|
|
1653
|
-
category:
|
|
1617
|
+
category: _camstack_types_addon.EventCategory.DeviceReady,
|
|
1654
1618
|
data: { deviceId: device.id }
|
|
1655
1619
|
});
|
|
1656
1620
|
};
|
|
@@ -1789,7 +1753,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1789
1753
|
type: "device",
|
|
1790
1754
|
id: deviceId
|
|
1791
1755
|
},
|
|
1792
|
-
category:
|
|
1756
|
+
category: _camstack_types_addon.EventCategory.DeviceBindingsChanged,
|
|
1793
1757
|
data: {
|
|
1794
1758
|
deviceId,
|
|
1795
1759
|
capName,
|
|
@@ -1798,7 +1762,7 @@ function createBrokerDeviceManagerApi(opts) {
|
|
|
1798
1762
|
nodeId
|
|
1799
1763
|
}
|
|
1800
1764
|
});
|
|
1801
|
-
(0,
|
|
1765
|
+
(0, _camstack_types_addon.emitReadiness)(eventBus, {
|
|
1802
1766
|
capName,
|
|
1803
1767
|
scope: {
|
|
1804
1768
|
type: "device",
|
|
@@ -3684,7 +3648,8 @@ var LocalChildRegistry = class {
|
|
|
3684
3648
|
capName: out.capName,
|
|
3685
3649
|
method: out.method,
|
|
3686
3650
|
args: out.args,
|
|
3687
|
-
...out.deviceId !== void 0 ? { deviceId: out.deviceId } : {}
|
|
3651
|
+
...out.deviceId !== void 0 ? { deviceId: out.deviceId } : {},
|
|
3652
|
+
...out.nodeId !== void 0 ? { nodeId: out.nodeId } : {}
|
|
3688
3653
|
};
|
|
3689
3654
|
if (this.resolveChildId(out.capName, out.deviceId) !== null) {
|
|
3690
3655
|
if (!this.egressRoutedCaps.has(out.capName)) {
|
|
@@ -3929,7 +3894,8 @@ var LocalChildClient = class {
|
|
|
3929
3894
|
capName: input.capName,
|
|
3930
3895
|
method: input.method,
|
|
3931
3896
|
args: input.args,
|
|
3932
|
-
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {}
|
|
3897
|
+
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
|
|
3898
|
+
...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {}
|
|
3933
3899
|
};
|
|
3934
3900
|
return this.channel.request(msg);
|
|
3935
3901
|
}
|
|
@@ -4623,7 +4589,10 @@ function createParentUnownedCallHandler(deps) {
|
|
|
4623
4589
|
const deviceId = input.deviceId ?? extractDeviceId(input.args);
|
|
4624
4590
|
const resolver = deps.getResolver();
|
|
4625
4591
|
if (resolver !== null) try {
|
|
4626
|
-
const route = resolver.resolveCapRoute(input.capName,
|
|
4592
|
+
const route = resolver.resolveCapRoute(input.capName, {
|
|
4593
|
+
...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {},
|
|
4594
|
+
...deviceId !== void 0 ? { deviceId } : {}
|
|
4595
|
+
});
|
|
4627
4596
|
return await resolver.dispatch(route, input.method, input.args);
|
|
4628
4597
|
} catch (err) {
|
|
4629
4598
|
if (!(err instanceof CapRouteError) || err.reason !== "no-provider") throw err;
|
|
@@ -4660,7 +4629,7 @@ function createParentUnownedCallHandler(deps) {
|
|
|
4660
4629
|
return await brokerCallForCap(deps.broker, input.capName, input.method, input.args);
|
|
4661
4630
|
} catch (cause) {
|
|
4662
4631
|
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
4663
|
-
throw new Error(`parent could not route child unowned cap call "${input.capName}.${input.method}": ${reason}`,
|
|
4632
|
+
throw new Error(`parent could not route child unowned cap call "${input.capName}.${input.method}": ${reason}`, { cause });
|
|
4664
4633
|
}
|
|
4665
4634
|
};
|
|
4666
4635
|
}
|
|
@@ -5068,11 +5037,13 @@ function ipcParentLink(getCallOut) {
|
|
|
5068
5037
|
const input = op.input;
|
|
5069
5038
|
const inputObj = input && typeof input === "object" && !Array.isArray(input) ? input : null;
|
|
5070
5039
|
const deviceId = inputObj && typeof Reflect.get(inputObj, "deviceId") === "number" ? Reflect.get(inputObj, "deviceId") : void 0;
|
|
5040
|
+
const pinnedNodeId = (0, _camstack_types.readNodePin)(op.context);
|
|
5071
5041
|
const capCallInput = {
|
|
5072
5042
|
capName: parsed.capName,
|
|
5073
5043
|
method: parsed.method,
|
|
5074
5044
|
args: op.input,
|
|
5075
|
-
...deviceId !== void 0 ? { deviceId } : {}
|
|
5045
|
+
...deviceId !== void 0 ? { deviceId } : {},
|
|
5046
|
+
...pinnedNodeId !== void 0 ? { nodeId: pinnedNodeId } : {}
|
|
5076
5047
|
};
|
|
5077
5048
|
return observable((observer) => {
|
|
5078
5049
|
callOut(capCallInput).then((data) => {
|
|
@@ -5137,7 +5108,7 @@ var CapUsageRegistry = class {
|
|
|
5137
5108
|
let window = byCap.get(rec.capName);
|
|
5138
5109
|
if (!window) {
|
|
5139
5110
|
window = {
|
|
5140
|
-
buckets:
|
|
5111
|
+
buckets: Array.from({ length: this.retentionSeconds }, () => 0),
|
|
5141
5112
|
lastCallAtMs: 0
|
|
5142
5113
|
};
|
|
5143
5114
|
byCap.set(rec.capName, window);
|
|
@@ -5357,7 +5328,7 @@ function createAddonDataPlaneFacility(args) {
|
|
|
5357
5328
|
let server = null;
|
|
5358
5329
|
let baseUrl = "";
|
|
5359
5330
|
const route = (req, res) => {
|
|
5360
|
-
if (req.headers[
|
|
5331
|
+
if (req.headers[_camstack_types_addon.DATAPLANE_SECRET_HEADER] !== secret) {
|
|
5361
5332
|
res.writeHead(403).end();
|
|
5362
5333
|
return;
|
|
5363
5334
|
}
|
|
@@ -5902,7 +5873,7 @@ function getOrInitReadinessRegistry(broker, eventBus, logger) {
|
|
|
5902
5873
|
const bkr = broker;
|
|
5903
5874
|
const existing = brokerReadinessRegistries.get(broker);
|
|
5904
5875
|
if (existing) return existing;
|
|
5905
|
-
const registry = new
|
|
5876
|
+
const registry = new _camstack_types_addon.ReadinessRegistry({
|
|
5906
5877
|
eventBus,
|
|
5907
5878
|
sourceNodeId: bkr.nodeID,
|
|
5908
5879
|
logger
|
|
@@ -5969,7 +5940,7 @@ function getOrInitReadinessRegistry(broker, eventBus, logger) {
|
|
|
5969
5940
|
function getOrInitReadinessRegistryForClient(client, eventBus, logger, nodeId) {
|
|
5970
5941
|
const existing = clientReadinessRegistries.get(nodeId);
|
|
5971
5942
|
if (existing) return existing;
|
|
5972
|
-
const registry = new
|
|
5943
|
+
const registry = new _camstack_types_addon.ReadinessRegistry({
|
|
5973
5944
|
eventBus,
|
|
5974
5945
|
sourceNodeId: nodeId,
|
|
5975
5946
|
logger
|
|
@@ -6282,12 +6253,12 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6282
6253
|
const api = (0, _trpc_client.createTRPCClient)({ links });
|
|
6283
6254
|
const scopedLogger = options?.createLogger?.(addonId) ?? (runtime.mode === "broker" ? createRemoteLogger(runtime.broker, addonId) : createUdsLogger(runtime.client, addonId, nodeId));
|
|
6284
6255
|
const scopedEventBus = runtime.mode === "broker" ? createBrokerEventBus(runtime.broker, addonId) : createUdsEventBus(runtime.client, addonId);
|
|
6285
|
-
const workerDisposerChain = new
|
|
6256
|
+
const workerDisposerChain = new _camstack_types_addon.DisposerChain({ onError: (err, index) => {
|
|
6286
6257
|
scopedLogger.error(`Disposer #${index} threw during teardown`, { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
6287
6258
|
} });
|
|
6288
6259
|
registerWorkerDisposerChain(nodeId, addonId, workerDisposerChain);
|
|
6289
6260
|
const bindingCache = /* @__PURE__ */ new Map();
|
|
6290
|
-
scopedEventBus.subscribe({ category:
|
|
6261
|
+
scopedEventBus.subscribe({ category: _camstack_types_addon.EventCategory.DeviceBindingsChanged }, (e) => {
|
|
6291
6262
|
const data = e.data ?? {};
|
|
6292
6263
|
if (typeof data.deviceId === "number") {
|
|
6293
6264
|
bindingCache.delete(data.deviceId);
|
|
@@ -6314,16 +6285,25 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6314
6285
|
};
|
|
6315
6286
|
const writeBlob = async (coll, key, value, namespace) => {
|
|
6316
6287
|
if (!settingsApi) return;
|
|
6317
|
-
|
|
6318
|
-
namespace
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6288
|
+
try {
|
|
6289
|
+
await settingsApi.set.mutate(namespace !== void 0 ? {
|
|
6290
|
+
namespace,
|
|
6291
|
+
collection: coll,
|
|
6292
|
+
key,
|
|
6293
|
+
value
|
|
6294
|
+
} : {
|
|
6295
|
+
collection: coll,
|
|
6296
|
+
key,
|
|
6297
|
+
value
|
|
6298
|
+
});
|
|
6299
|
+
} catch (err) {
|
|
6300
|
+
const isTrpcError = err instanceof _trpc_client.TRPCClientError;
|
|
6301
|
+
scopedLogger.warn(`settings write failed (${coll}/${key}) — ${isTrpcError ? "transport error" : "store error"}`, { meta: {
|
|
6302
|
+
collection: coll,
|
|
6303
|
+
key,
|
|
6304
|
+
error: (0, _camstack_types_addon.errMsg)(err)
|
|
6305
|
+
} });
|
|
6306
|
+
}
|
|
6327
6307
|
};
|
|
6328
6308
|
const rmwChains = /* @__PURE__ */ new Map();
|
|
6329
6309
|
const serializeRmw = (coll, key, op) => {
|
|
@@ -6332,7 +6312,7 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6332
6312
|
rmwChains.set(chainKey, next);
|
|
6333
6313
|
next.finally(() => {
|
|
6334
6314
|
if (rmwChains.get(chainKey) === next) rmwChains.delete(chainKey);
|
|
6335
|
-
});
|
|
6315
|
+
}).catch(() => void 0);
|
|
6336
6316
|
return next;
|
|
6337
6317
|
};
|
|
6338
6318
|
const settingsView = {
|
|
@@ -6386,7 +6366,7 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6386
6366
|
const readinessRegistry = () => runtime.mode === "broker" ? getOrInitReadinessRegistry(runtime.broker, scopedEventBus, scopedLogger) : getOrInitReadinessRegistryForClient(runtime.client, scopedEventBus, scopedLogger, nodeId);
|
|
6387
6367
|
const capHandleCache = /* @__PURE__ */ new Map();
|
|
6388
6368
|
function getOrCreateHandle(capName, scope, timeoutMs) {
|
|
6389
|
-
const key = `${capName}::${(0,
|
|
6369
|
+
const key = `${capName}::${(0, _camstack_types_addon.scopeKey)(scope)}`;
|
|
6390
6370
|
const existing = capHandleCache.get(key);
|
|
6391
6371
|
if (existing) return existing;
|
|
6392
6372
|
const handle = new CapabilityHandle(capName, scope, readinessRegistry(), timeoutMs);
|
|
@@ -6482,10 +6462,10 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6482
6462
|
},
|
|
6483
6463
|
fetchDevice: async (deviceId) => {
|
|
6484
6464
|
const cached = bindingCache.get(deviceId);
|
|
6485
|
-
if (cached) return (0,
|
|
6465
|
+
if (cached) return (0, _camstack_types_addon.createDeviceProxy)(api, cached);
|
|
6486
6466
|
const binding = await api.deviceManager.getBindings.query({ deviceId });
|
|
6487
6467
|
bindingCache.set(deviceId, binding);
|
|
6488
|
-
return (0,
|
|
6468
|
+
return (0, _camstack_types_addon.createDeviceProxy)(api, binding);
|
|
6489
6469
|
},
|
|
6490
6470
|
useCapability(capName, scope = { type: "global" }) {
|
|
6491
6471
|
return getOrCreateHandle(capName, scope, Number.POSITIVE_INFINITY);
|
|
@@ -6615,12 +6595,6 @@ Object.defineProperty(exports, "CapabilityUnavailableError", {
|
|
|
6615
6595
|
return CapabilityUnavailableError;
|
|
6616
6596
|
}
|
|
6617
6597
|
});
|
|
6618
|
-
Object.defineProperty(exports, "CustomActionRegistry", {
|
|
6619
|
-
enumerable: true,
|
|
6620
|
-
get: function() {
|
|
6621
|
-
return CustomActionRegistry;
|
|
6622
|
-
}
|
|
6623
|
-
});
|
|
6624
6598
|
Object.defineProperty(exports, "DeviceRegistry", {
|
|
6625
6599
|
enumerable: true,
|
|
6626
6600
|
get: function() {
|