@camstack/system 1.0.4 → 1.0.5
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 +27 -1
- package/dist/addon-runner.mjs +27 -1
- package/dist/builtins/local-auth/local-auth.addon.js +5 -1518
- package/dist/builtins/local-auth/local-auth.addon.mjs +2 -1503
- package/dist/framework-resolver-hook.mjs +48 -0
- package/dist/graceful-fs-BoR9GuPS.mjs +1423 -0
- package/dist/graceful-fs-lg19SZNz.js +1434 -0
- package/dist/index.js +635 -1751
- package/dist/index.mjs +745 -1854
- package/dist/kernel/addon-installer.d.ts +20 -0
- package/dist/kernel/host-externals.d.ts +12 -0
- package/dist/kernel/index.d.ts +7 -0
- package/dist/kernel/lifecycle/framework-staging.d.ts +15 -0
- package/dist/kernel/lifecycle/job-journal.d.ts +19 -0
- package/dist/kernel/lifecycle/lifecycle-job-engine.d.ts +98 -0
- package/dist/kernel/lifecycle/staging-area.d.ts +22 -0
- package/dist/kernel/moleculer/addon-context-factory.d.ts +13 -1
- package/dist/kernel/moleculer/register-framework-resolver.d.ts +8 -0
- package/dist/{main-rtjOwPBR.mjs → main-BOG1xxwD.mjs} +2 -2
- package/dist/{main-DNnMW7Z2.js → main-B_G1JH3Q.js} +31 -31
- package/dist/{manifest-python-deps-D1DbAQEv.js → manifest-python-deps-B4BmMoGT.js} +259 -0
- package/dist/{manifest-python-deps-DZsKTbs1.mjs → manifest-python-deps-CXbKrOdk.mjs} +256 -2
- package/dist/semver-BQBSy1FJ.mjs +1504 -0
- package/dist/semver-D3n3E_fi.js +1515 -0
- package/package.json +3 -2
|
@@ -7,6 +7,9 @@ let node_path = require("node:path");
|
|
|
7
7
|
node_path = require_chunk.__toESM(node_path);
|
|
8
8
|
let _camstack_types = require("@camstack/types");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
10
|
+
node_crypto = require_chunk.__toESM(node_crypto);
|
|
11
|
+
let node_child_process = require("node:child_process");
|
|
12
|
+
let node_util = require("node:util");
|
|
10
13
|
let node_os = require("node:os");
|
|
11
14
|
node_os = require_chunk.__toESM(node_os);
|
|
12
15
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -52,6 +55,255 @@ function resolveAddonClass(mod) {
|
|
|
52
55
|
if (namedAddon) return namedAddon;
|
|
53
56
|
}
|
|
54
57
|
//#endregion
|
|
58
|
+
//#region src/kernel/deps/manifest-native-deps.ts
|
|
59
|
+
var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
60
|
+
/**
|
|
61
|
+
* Native node modules an addon needs at runtime but cannot be bundled
|
|
62
|
+
* (`.node` binary files require ABI-matched compilation). Mirror of the
|
|
63
|
+
* Python `requirements.txt` pattern in `manifest-python-deps.ts` —
|
|
64
|
+
* declared in the addon's `package.json` under `camstack.nativeDependencies`,
|
|
65
|
+
* installed per-addon at install time so the host's regular `npm install`
|
|
66
|
+
* doesn't pull in the union of every camera driver's native deps.
|
|
67
|
+
*
|
|
68
|
+
* Phase E of the bundles + builder modernization spec
|
|
69
|
+
* (`docs/superpowers/specs/2026-05-09-bundles-and-builder-modernization-design.md`).
|
|
70
|
+
*
|
|
71
|
+
* Idempotent: hashes the `nativeDependencies` map and writes a marker
|
|
72
|
+
* to `<addonDir>/.camstack-native-deps-installed`. Re-installing only
|
|
73
|
+
* happens when the declared set changes.
|
|
74
|
+
*
|
|
75
|
+
* Failure modes:
|
|
76
|
+
* - manifest doesn't declare `nativeDependencies` (or declares empty) → no-op
|
|
77
|
+
* - `npm install` fails → throws (caller decides whether to abort install)
|
|
78
|
+
* - rebuild step fails → logs warning + continues (install may still
|
|
79
|
+
* work if prebuilt binaries shipped in the package cover the host
|
|
80
|
+
* ABI; surface a clear error at first `import` of the native module
|
|
81
|
+
* otherwise).
|
|
82
|
+
*/
|
|
83
|
+
async function installManifestNativeDeps(addonDir, pkgRaw, logger, registry) {
|
|
84
|
+
const native = readNativeDeps(pkgRaw);
|
|
85
|
+
if (native == null || Object.keys(native).length === 0) return;
|
|
86
|
+
const markerFile = node_path.join(addonDir, ".camstack-native-deps-installed");
|
|
87
|
+
const markerHash = hashDeclaration(native);
|
|
88
|
+
if (markerMatches(markerFile, markerHash)) {
|
|
89
|
+
logger.debug("Native deps already installed (marker matches)", { meta: {
|
|
90
|
+
addonDir,
|
|
91
|
+
count: Object.keys(native).length
|
|
92
|
+
} });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const pending = Object.entries(native).filter(([name]) => !copyPrebuiltNativeDep(name, addonDir, logger));
|
|
96
|
+
if (pending.length === 0) {
|
|
97
|
+
logger.info("Native deps satisfied from prebuilt host modules (offline)", { meta: {
|
|
98
|
+
addonDir,
|
|
99
|
+
count: Object.keys(native).length
|
|
100
|
+
} });
|
|
101
|
+
try {
|
|
102
|
+
node_fs.writeFileSync(markerFile, markerHash);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
logger.warn("Failed to write native deps marker", { meta: {
|
|
105
|
+
markerFile,
|
|
106
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
107
|
+
} });
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const specs = pending.map(([name, range]) => `${name}@${range}`);
|
|
112
|
+
logger.info("Installing native dependencies", { meta: {
|
|
113
|
+
addonDir,
|
|
114
|
+
specs
|
|
115
|
+
} });
|
|
116
|
+
const args = [
|
|
117
|
+
"install",
|
|
118
|
+
"--no-save",
|
|
119
|
+
"--no-package-lock",
|
|
120
|
+
"--no-audit",
|
|
121
|
+
"--no-fund",
|
|
122
|
+
"--omit=dev",
|
|
123
|
+
"--omit=peer",
|
|
124
|
+
...registry ? ["--registry", registry] : [],
|
|
125
|
+
...specs
|
|
126
|
+
];
|
|
127
|
+
try {
|
|
128
|
+
await execFileAsync("npm", args, {
|
|
129
|
+
cwd: addonDir,
|
|
130
|
+
timeout: 3e5
|
|
131
|
+
});
|
|
132
|
+
} catch (err) {
|
|
133
|
+
throw new Error(`npm install of native deps failed for ${addonDir}: ${(0, _camstack_types.errMsg)(err)}`, { cause: err });
|
|
134
|
+
}
|
|
135
|
+
await rebuildNativeDeps(addonDir, pending.map(([name]) => name), logger);
|
|
136
|
+
try {
|
|
137
|
+
node_fs.writeFileSync(markerFile, markerHash);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
logger.warn("Failed to write native deps marker", { meta: {
|
|
140
|
+
markerFile,
|
|
141
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
142
|
+
} });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Satisfy a native dep from an already-built copy on the host instead of a
|
|
147
|
+
* runtime `npm install`. Searches NODE_PATH and the node_modules dirs above
|
|
148
|
+
* `addonDir` for `<name>` carrying a compiled binary, and copies the whole
|
|
149
|
+
* package into `<addonDir>/node_modules/<name>`. Safe: returns false on any
|
|
150
|
+
* miss/error so the caller falls back to the network install.
|
|
151
|
+
*/
|
|
152
|
+
function copyPrebuiltNativeDep(name, addonDir, logger) {
|
|
153
|
+
const target = node_path.join(addonDir, "node_modules", name);
|
|
154
|
+
if (hasBuiltBinary(target)) return true;
|
|
155
|
+
for (const source of candidateHoistedDirs(name, addonDir)) {
|
|
156
|
+
if (source === target) continue;
|
|
157
|
+
if (!hasBuiltBinary(source)) continue;
|
|
158
|
+
try {
|
|
159
|
+
node_fs.rmSync(target, {
|
|
160
|
+
recursive: true,
|
|
161
|
+
force: true
|
|
162
|
+
});
|
|
163
|
+
node_fs.mkdirSync(node_path.dirname(target), { recursive: true });
|
|
164
|
+
node_fs.cpSync(source, target, {
|
|
165
|
+
recursive: true,
|
|
166
|
+
dereference: true
|
|
167
|
+
});
|
|
168
|
+
logger.info("Native dep copied from prebuilt host module (offline)", { meta: {
|
|
169
|
+
name,
|
|
170
|
+
source,
|
|
171
|
+
target
|
|
172
|
+
} });
|
|
173
|
+
return true;
|
|
174
|
+
} catch (err) {
|
|
175
|
+
logger.warn("Prebuilt native dep copy failed — will try npm install", { meta: {
|
|
176
|
+
name,
|
|
177
|
+
source,
|
|
178
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
179
|
+
} });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
/** A package dir is "built" when it carries a compiled `.node` or a prebuilds tree. */
|
|
185
|
+
function hasBuiltBinary(pkgDir) {
|
|
186
|
+
if (!node_fs.existsSync(node_path.join(pkgDir, "package.json"))) return false;
|
|
187
|
+
const releaseDir = node_path.join(pkgDir, "build", "Release");
|
|
188
|
+
try {
|
|
189
|
+
if (node_fs.existsSync(releaseDir) && node_fs.readdirSync(releaseDir).some((f) => f.endsWith(".node"))) return true;
|
|
190
|
+
} catch {}
|
|
191
|
+
return node_fs.existsSync(node_path.join(pkgDir, "prebuilds"));
|
|
192
|
+
}
|
|
193
|
+
/** Candidate hoisted locations for `<name>`: NODE_PATH entries + ancestors of `addonDir`. */
|
|
194
|
+
function candidateHoistedDirs(name, addonDir) {
|
|
195
|
+
const dirs = [];
|
|
196
|
+
const nodePath = process.env["NODE_PATH"];
|
|
197
|
+
if (nodePath) {
|
|
198
|
+
for (const p of nodePath.split(node_path.delimiter)) if (p) dirs.push(node_path.join(p, name));
|
|
199
|
+
}
|
|
200
|
+
let cur = addonDir;
|
|
201
|
+
for (let i = 0; i < 10; i++) {
|
|
202
|
+
dirs.push(node_path.join(cur, "node_modules", name));
|
|
203
|
+
const parent = node_path.dirname(cur);
|
|
204
|
+
if (parent === cur) break;
|
|
205
|
+
cur = parent;
|
|
206
|
+
}
|
|
207
|
+
return dirs;
|
|
208
|
+
}
|
|
209
|
+
/** Read & validate `camstack.nativeDependencies`. Returns null when absent. */
|
|
210
|
+
function readNativeDeps(pkgRaw) {
|
|
211
|
+
const camstack = (0, _camstack_types.asJsonObject)(pkgRaw["camstack"]);
|
|
212
|
+
if (!camstack) return null;
|
|
213
|
+
const native = (0, _camstack_types.asJsonObject)(camstack["nativeDependencies"]);
|
|
214
|
+
if (!native) return null;
|
|
215
|
+
const out = {};
|
|
216
|
+
for (const [k, v] of Object.entries(native)) {
|
|
217
|
+
const range = (0, _camstack_types.asString)(v);
|
|
218
|
+
if (range) out[k] = range;
|
|
219
|
+
}
|
|
220
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
221
|
+
}
|
|
222
|
+
/** SHA-256 of the canonical-keyed declaration — drives marker idempotency. */
|
|
223
|
+
function hashDeclaration(deps) {
|
|
224
|
+
const canonical = Object.keys(deps).toSorted().map((k) => `${k}@${deps[k]}`).join("\n");
|
|
225
|
+
return node_crypto.createHash("sha256").update(canonical).digest("hex");
|
|
226
|
+
}
|
|
227
|
+
function markerMatches(markerFile, expected) {
|
|
228
|
+
try {
|
|
229
|
+
return node_fs.readFileSync(markerFile, "utf-8").trim() === expected;
|
|
230
|
+
} catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Rebuild native modules against the host's runtime ABI.
|
|
236
|
+
*
|
|
237
|
+
* Detection: `process.versions.electron` is set when running inside
|
|
238
|
+
* Electron's main/renderer process (set even when `ELECTRON_RUN_AS_NODE`
|
|
239
|
+
* isn't), giving us a reliable signal. Plain Node leaves it undefined.
|
|
240
|
+
*
|
|
241
|
+
* Electron path: tries `@electron/rebuild` programmatically, falling
|
|
242
|
+
* back to `npx electron-rebuild` if the package isn't directly available.
|
|
243
|
+
* Node path: `npm rebuild --prefix <addonDir>` re-runs the install
|
|
244
|
+
* scripts of every package under that directory.
|
|
245
|
+
*
|
|
246
|
+
* Failures here are non-fatal: many native packages ship prebuilt
|
|
247
|
+
* binaries that cover both ABIs, so the rebuild may be unnecessary.
|
|
248
|
+
* The first `import` of an actually-mismatched binary throws a clear
|
|
249
|
+
* error that points the operator at this rebuild step.
|
|
250
|
+
*/
|
|
251
|
+
async function rebuildNativeDeps(addonDir, packageNames, logger) {
|
|
252
|
+
if (typeof process.versions.electron === "string") {
|
|
253
|
+
const electronVersion = process.versions.electron;
|
|
254
|
+
logger.info("Rebuilding native deps for Electron", { meta: {
|
|
255
|
+
addonDir,
|
|
256
|
+
electronVersion,
|
|
257
|
+
packages: packageNames
|
|
258
|
+
} });
|
|
259
|
+
try {
|
|
260
|
+
const rebuildModule = await Promise.resolve().then(() => /* @__PURE__ */ require_chunk.__toESM(require("./main-B_G1JH3Q.js").default)).catch(() => null);
|
|
261
|
+
if (rebuildModule?.rebuild) {
|
|
262
|
+
await rebuildModule.rebuild({
|
|
263
|
+
buildPath: addonDir,
|
|
264
|
+
electronVersion,
|
|
265
|
+
onlyModules: packageNames
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
logger.warn("@electron/rebuild not available — falling back to npx", { meta: { addonDir } });
|
|
270
|
+
await execFileAsync("npx", [
|
|
271
|
+
"--yes",
|
|
272
|
+
"electron-rebuild",
|
|
273
|
+
"-m",
|
|
274
|
+
addonDir,
|
|
275
|
+
"-v",
|
|
276
|
+
electronVersion
|
|
277
|
+
], {
|
|
278
|
+
cwd: addonDir,
|
|
279
|
+
timeout: 6e5
|
|
280
|
+
});
|
|
281
|
+
} catch (err) {
|
|
282
|
+
logger.warn("Electron rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
283
|
+
addonDir,
|
|
284
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
285
|
+
} });
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
logger.info("Rebuilding native deps for Node", { meta: {
|
|
290
|
+
addonDir,
|
|
291
|
+
nodeAbi: process.versions.modules,
|
|
292
|
+
packages: packageNames
|
|
293
|
+
} });
|
|
294
|
+
try {
|
|
295
|
+
await execFileAsync("npm", ["rebuild", ...packageNames], {
|
|
296
|
+
cwd: addonDir,
|
|
297
|
+
timeout: 6e5
|
|
298
|
+
});
|
|
299
|
+
} catch (err) {
|
|
300
|
+
logger.warn("npm rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
301
|
+
addonDir,
|
|
302
|
+
error: (0, _camstack_types.errMsg)(err)
|
|
303
|
+
} });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
55
307
|
//#region src/kernel/capability-handle.ts
|
|
56
308
|
var CapabilityUnavailableError = class extends Error {
|
|
57
309
|
capName;
|
|
@@ -6183,6 +6435,7 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6183
6435
|
localNodeId: nodeId,
|
|
6184
6436
|
storage: storage ?? void 0,
|
|
6185
6437
|
capabilityRegistry: options?.capabilityRegistry,
|
|
6438
|
+
...options?.listStorageLocationDeclarations ? { listStorageLocationDeclarations: options.listStorageLocationDeclarations } : {},
|
|
6186
6439
|
readinessRegistry: readinessRegistry(),
|
|
6187
6440
|
deviceRegistry: workerDeviceRegistry,
|
|
6188
6441
|
devices: createBrokerDeviceManagerApi({
|
|
@@ -6632,6 +6885,12 @@ Object.defineProperty(exports, "getWorkerNativeCapSnapshot", {
|
|
|
6632
6885
|
return getWorkerNativeCapSnapshot;
|
|
6633
6886
|
}
|
|
6634
6887
|
});
|
|
6888
|
+
Object.defineProperty(exports, "installManifestNativeDeps", {
|
|
6889
|
+
enumerable: true,
|
|
6890
|
+
get: function() {
|
|
6891
|
+
return installManifestNativeDeps;
|
|
6892
|
+
}
|
|
6893
|
+
});
|
|
6635
6894
|
Object.defineProperty(exports, "installManifestPythonDeps", {
|
|
6636
6895
|
enumerable: true,
|
|
6637
6896
|
get: function() {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { o as __toESM } from "./chunk-CNf5ZN-e.mjs";
|
|
1
2
|
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
2
3
|
import { createServer } from "node:http";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path$1 from "node:path";
|
|
5
6
|
import { isAbsolute, join } from "node:path";
|
|
6
|
-
import { DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, createDeviceProxy, deviceOpsCapability, emitReadiness, expandCapMethods, scopeKey, sleep } from "@camstack/types";
|
|
7
|
+
import { DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, scopeKey, sleep } from "@camstack/types";
|
|
8
|
+
import * as crypto$1 from "node:crypto";
|
|
7
9
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { promisify } from "node:util";
|
|
8
12
|
import * as os from "node:os";
|
|
9
13
|
import { tmpdir } from "node:os";
|
|
10
14
|
import { unlink } from "node:fs/promises";
|
|
@@ -50,6 +54,255 @@ function resolveAddonClass(mod) {
|
|
|
50
54
|
if (namedAddon) return namedAddon;
|
|
51
55
|
}
|
|
52
56
|
//#endregion
|
|
57
|
+
//#region src/kernel/deps/manifest-native-deps.ts
|
|
58
|
+
var execFileAsync = promisify(execFile);
|
|
59
|
+
/**
|
|
60
|
+
* Native node modules an addon needs at runtime but cannot be bundled
|
|
61
|
+
* (`.node` binary files require ABI-matched compilation). Mirror of the
|
|
62
|
+
* Python `requirements.txt` pattern in `manifest-python-deps.ts` —
|
|
63
|
+
* declared in the addon's `package.json` under `camstack.nativeDependencies`,
|
|
64
|
+
* installed per-addon at install time so the host's regular `npm install`
|
|
65
|
+
* doesn't pull in the union of every camera driver's native deps.
|
|
66
|
+
*
|
|
67
|
+
* Phase E of the bundles + builder modernization spec
|
|
68
|
+
* (`docs/superpowers/specs/2026-05-09-bundles-and-builder-modernization-design.md`).
|
|
69
|
+
*
|
|
70
|
+
* Idempotent: hashes the `nativeDependencies` map and writes a marker
|
|
71
|
+
* to `<addonDir>/.camstack-native-deps-installed`. Re-installing only
|
|
72
|
+
* happens when the declared set changes.
|
|
73
|
+
*
|
|
74
|
+
* Failure modes:
|
|
75
|
+
* - manifest doesn't declare `nativeDependencies` (or declares empty) → no-op
|
|
76
|
+
* - `npm install` fails → throws (caller decides whether to abort install)
|
|
77
|
+
* - rebuild step fails → logs warning + continues (install may still
|
|
78
|
+
* work if prebuilt binaries shipped in the package cover the host
|
|
79
|
+
* ABI; surface a clear error at first `import` of the native module
|
|
80
|
+
* otherwise).
|
|
81
|
+
*/
|
|
82
|
+
async function installManifestNativeDeps(addonDir, pkgRaw, logger, registry) {
|
|
83
|
+
const native = readNativeDeps(pkgRaw);
|
|
84
|
+
if (native == null || Object.keys(native).length === 0) return;
|
|
85
|
+
const markerFile = path$1.join(addonDir, ".camstack-native-deps-installed");
|
|
86
|
+
const markerHash = hashDeclaration(native);
|
|
87
|
+
if (markerMatches(markerFile, markerHash)) {
|
|
88
|
+
logger.debug("Native deps already installed (marker matches)", { meta: {
|
|
89
|
+
addonDir,
|
|
90
|
+
count: Object.keys(native).length
|
|
91
|
+
} });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const pending = Object.entries(native).filter(([name]) => !copyPrebuiltNativeDep(name, addonDir, logger));
|
|
95
|
+
if (pending.length === 0) {
|
|
96
|
+
logger.info("Native deps satisfied from prebuilt host modules (offline)", { meta: {
|
|
97
|
+
addonDir,
|
|
98
|
+
count: Object.keys(native).length
|
|
99
|
+
} });
|
|
100
|
+
try {
|
|
101
|
+
fs.writeFileSync(markerFile, markerHash);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
logger.warn("Failed to write native deps marker", { meta: {
|
|
104
|
+
markerFile,
|
|
105
|
+
error: errMsg(err)
|
|
106
|
+
} });
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const specs = pending.map(([name, range]) => `${name}@${range}`);
|
|
111
|
+
logger.info("Installing native dependencies", { meta: {
|
|
112
|
+
addonDir,
|
|
113
|
+
specs
|
|
114
|
+
} });
|
|
115
|
+
const args = [
|
|
116
|
+
"install",
|
|
117
|
+
"--no-save",
|
|
118
|
+
"--no-package-lock",
|
|
119
|
+
"--no-audit",
|
|
120
|
+
"--no-fund",
|
|
121
|
+
"--omit=dev",
|
|
122
|
+
"--omit=peer",
|
|
123
|
+
...registry ? ["--registry", registry] : [],
|
|
124
|
+
...specs
|
|
125
|
+
];
|
|
126
|
+
try {
|
|
127
|
+
await execFileAsync("npm", args, {
|
|
128
|
+
cwd: addonDir,
|
|
129
|
+
timeout: 3e5
|
|
130
|
+
});
|
|
131
|
+
} catch (err) {
|
|
132
|
+
throw new Error(`npm install of native deps failed for ${addonDir}: ${errMsg(err)}`, { cause: err });
|
|
133
|
+
}
|
|
134
|
+
await rebuildNativeDeps(addonDir, pending.map(([name]) => name), logger);
|
|
135
|
+
try {
|
|
136
|
+
fs.writeFileSync(markerFile, markerHash);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
logger.warn("Failed to write native deps marker", { meta: {
|
|
139
|
+
markerFile,
|
|
140
|
+
error: errMsg(err)
|
|
141
|
+
} });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Satisfy a native dep from an already-built copy on the host instead of a
|
|
146
|
+
* runtime `npm install`. Searches NODE_PATH and the node_modules dirs above
|
|
147
|
+
* `addonDir` for `<name>` carrying a compiled binary, and copies the whole
|
|
148
|
+
* package into `<addonDir>/node_modules/<name>`. Safe: returns false on any
|
|
149
|
+
* miss/error so the caller falls back to the network install.
|
|
150
|
+
*/
|
|
151
|
+
function copyPrebuiltNativeDep(name, addonDir, logger) {
|
|
152
|
+
const target = path$1.join(addonDir, "node_modules", name);
|
|
153
|
+
if (hasBuiltBinary(target)) return true;
|
|
154
|
+
for (const source of candidateHoistedDirs(name, addonDir)) {
|
|
155
|
+
if (source === target) continue;
|
|
156
|
+
if (!hasBuiltBinary(source)) continue;
|
|
157
|
+
try {
|
|
158
|
+
fs.rmSync(target, {
|
|
159
|
+
recursive: true,
|
|
160
|
+
force: true
|
|
161
|
+
});
|
|
162
|
+
fs.mkdirSync(path$1.dirname(target), { recursive: true });
|
|
163
|
+
fs.cpSync(source, target, {
|
|
164
|
+
recursive: true,
|
|
165
|
+
dereference: true
|
|
166
|
+
});
|
|
167
|
+
logger.info("Native dep copied from prebuilt host module (offline)", { meta: {
|
|
168
|
+
name,
|
|
169
|
+
source,
|
|
170
|
+
target
|
|
171
|
+
} });
|
|
172
|
+
return true;
|
|
173
|
+
} catch (err) {
|
|
174
|
+
logger.warn("Prebuilt native dep copy failed — will try npm install", { meta: {
|
|
175
|
+
name,
|
|
176
|
+
source,
|
|
177
|
+
error: errMsg(err)
|
|
178
|
+
} });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
/** A package dir is "built" when it carries a compiled `.node` or a prebuilds tree. */
|
|
184
|
+
function hasBuiltBinary(pkgDir) {
|
|
185
|
+
if (!fs.existsSync(path$1.join(pkgDir, "package.json"))) return false;
|
|
186
|
+
const releaseDir = path$1.join(pkgDir, "build", "Release");
|
|
187
|
+
try {
|
|
188
|
+
if (fs.existsSync(releaseDir) && fs.readdirSync(releaseDir).some((f) => f.endsWith(".node"))) return true;
|
|
189
|
+
} catch {}
|
|
190
|
+
return fs.existsSync(path$1.join(pkgDir, "prebuilds"));
|
|
191
|
+
}
|
|
192
|
+
/** Candidate hoisted locations for `<name>`: NODE_PATH entries + ancestors of `addonDir`. */
|
|
193
|
+
function candidateHoistedDirs(name, addonDir) {
|
|
194
|
+
const dirs = [];
|
|
195
|
+
const nodePath = process.env["NODE_PATH"];
|
|
196
|
+
if (nodePath) {
|
|
197
|
+
for (const p of nodePath.split(path$1.delimiter)) if (p) dirs.push(path$1.join(p, name));
|
|
198
|
+
}
|
|
199
|
+
let cur = addonDir;
|
|
200
|
+
for (let i = 0; i < 10; i++) {
|
|
201
|
+
dirs.push(path$1.join(cur, "node_modules", name));
|
|
202
|
+
const parent = path$1.dirname(cur);
|
|
203
|
+
if (parent === cur) break;
|
|
204
|
+
cur = parent;
|
|
205
|
+
}
|
|
206
|
+
return dirs;
|
|
207
|
+
}
|
|
208
|
+
/** Read & validate `camstack.nativeDependencies`. Returns null when absent. */
|
|
209
|
+
function readNativeDeps(pkgRaw) {
|
|
210
|
+
const camstack = asJsonObject(pkgRaw["camstack"]);
|
|
211
|
+
if (!camstack) return null;
|
|
212
|
+
const native = asJsonObject(camstack["nativeDependencies"]);
|
|
213
|
+
if (!native) return null;
|
|
214
|
+
const out = {};
|
|
215
|
+
for (const [k, v] of Object.entries(native)) {
|
|
216
|
+
const range = asString(v);
|
|
217
|
+
if (range) out[k] = range;
|
|
218
|
+
}
|
|
219
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
220
|
+
}
|
|
221
|
+
/** SHA-256 of the canonical-keyed declaration — drives marker idempotency. */
|
|
222
|
+
function hashDeclaration(deps) {
|
|
223
|
+
const canonical = Object.keys(deps).toSorted().map((k) => `${k}@${deps[k]}`).join("\n");
|
|
224
|
+
return crypto$1.createHash("sha256").update(canonical).digest("hex");
|
|
225
|
+
}
|
|
226
|
+
function markerMatches(markerFile, expected) {
|
|
227
|
+
try {
|
|
228
|
+
return fs.readFileSync(markerFile, "utf-8").trim() === expected;
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Rebuild native modules against the host's runtime ABI.
|
|
235
|
+
*
|
|
236
|
+
* Detection: `process.versions.electron` is set when running inside
|
|
237
|
+
* Electron's main/renderer process (set even when `ELECTRON_RUN_AS_NODE`
|
|
238
|
+
* isn't), giving us a reliable signal. Plain Node leaves it undefined.
|
|
239
|
+
*
|
|
240
|
+
* Electron path: tries `@electron/rebuild` programmatically, falling
|
|
241
|
+
* back to `npx electron-rebuild` if the package isn't directly available.
|
|
242
|
+
* Node path: `npm rebuild --prefix <addonDir>` re-runs the install
|
|
243
|
+
* scripts of every package under that directory.
|
|
244
|
+
*
|
|
245
|
+
* Failures here are non-fatal: many native packages ship prebuilt
|
|
246
|
+
* binaries that cover both ABIs, so the rebuild may be unnecessary.
|
|
247
|
+
* The first `import` of an actually-mismatched binary throws a clear
|
|
248
|
+
* error that points the operator at this rebuild step.
|
|
249
|
+
*/
|
|
250
|
+
async function rebuildNativeDeps(addonDir, packageNames, logger) {
|
|
251
|
+
if (typeof process.versions.electron === "string") {
|
|
252
|
+
const electronVersion = process.versions.electron;
|
|
253
|
+
logger.info("Rebuilding native deps for Electron", { meta: {
|
|
254
|
+
addonDir,
|
|
255
|
+
electronVersion,
|
|
256
|
+
packages: packageNames
|
|
257
|
+
} });
|
|
258
|
+
try {
|
|
259
|
+
const rebuildModule = await import("./main-BOG1xxwD.mjs").then((m) => /* @__PURE__ */ __toESM(m.default)).catch(() => null);
|
|
260
|
+
if (rebuildModule?.rebuild) {
|
|
261
|
+
await rebuildModule.rebuild({
|
|
262
|
+
buildPath: addonDir,
|
|
263
|
+
electronVersion,
|
|
264
|
+
onlyModules: packageNames
|
|
265
|
+
});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
logger.warn("@electron/rebuild not available — falling back to npx", { meta: { addonDir } });
|
|
269
|
+
await execFileAsync("npx", [
|
|
270
|
+
"--yes",
|
|
271
|
+
"electron-rebuild",
|
|
272
|
+
"-m",
|
|
273
|
+
addonDir,
|
|
274
|
+
"-v",
|
|
275
|
+
electronVersion
|
|
276
|
+
], {
|
|
277
|
+
cwd: addonDir,
|
|
278
|
+
timeout: 6e5
|
|
279
|
+
});
|
|
280
|
+
} catch (err) {
|
|
281
|
+
logger.warn("Electron rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
282
|
+
addonDir,
|
|
283
|
+
error: errMsg(err)
|
|
284
|
+
} });
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
logger.info("Rebuilding native deps for Node", { meta: {
|
|
289
|
+
addonDir,
|
|
290
|
+
nodeAbi: process.versions.modules,
|
|
291
|
+
packages: packageNames
|
|
292
|
+
} });
|
|
293
|
+
try {
|
|
294
|
+
await execFileAsync("npm", ["rebuild", ...packageNames], {
|
|
295
|
+
cwd: addonDir,
|
|
296
|
+
timeout: 6e5
|
|
297
|
+
});
|
|
298
|
+
} catch (err) {
|
|
299
|
+
logger.warn("npm rebuild failed (continuing — prebuilt binary may be present)", { meta: {
|
|
300
|
+
addonDir,
|
|
301
|
+
error: errMsg(err)
|
|
302
|
+
} });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
53
306
|
//#region src/kernel/capability-handle.ts
|
|
54
307
|
var CapabilityUnavailableError = class extends Error {
|
|
55
308
|
capName;
|
|
@@ -6181,6 +6434,7 @@ async function buildAddonContext(runtime, declaration, dataDir, options) {
|
|
|
6181
6434
|
localNodeId: nodeId,
|
|
6182
6435
|
storage: storage ?? void 0,
|
|
6183
6436
|
capabilityRegistry: options?.capabilityRegistry,
|
|
6437
|
+
...options?.listStorageLocationDeclarations ? { listStorageLocationDeclarations: options.listStorageLocationDeclarations } : {},
|
|
6184
6438
|
readinessRegistry: readinessRegistry(),
|
|
6185
6439
|
deviceRegistry: workerDeviceRegistry,
|
|
6186
6440
|
devices: createBrokerDeviceManagerApi({
|
|
@@ -6312,4 +6566,4 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
|
|
|
6312
6566
|
await deps.installPythonRequirements(reqAbs);
|
|
6313
6567
|
}
|
|
6314
6568
|
//#endregion
|
|
6315
|
-
export { setWorkerNativeCapsChangeListener as $, createUdsLoggerWithControl as A, createLocalTransport as B, ipcParentLink as C, createUdsEventBus as D, createUdsEventBridge as E, CapRouteError as F, FrameDecoder as G, UdsLocalTransportServer as H, classifyCapRoute as I, buildUdsNativeCapProxy as J, encodeFrame as K, LocalChildClient as L, AGENT_CAP_FWD_SERVICE as M, CapRouteResolver as N, udsChildLogToWorkerEntry as O, callWithServiceDiscovery as P, mountNativeCapService as Q, LocalChildRegistry as R, ipcChildLink as S, createParentUnownedCallHandler as T, SocketChannel as U, UdsLocalTransportClient as V, localEndpointPath as W, getWorkerNativeCapProvider as X, createBrokerDeviceManagerApi as Y, getWorkerNativeCapSnapshot as Z, __resetCapUsageRegistryForTests as _, getWorkerDeviceRegistry as a, capBareAction as at, brokerTransportLink as b, setHubConnected as c, deserializeTypedArrays as ct, registerEventBusService as d, CustomActionRegistry as dt, createAddonService as et, AddonDepsManager as f, CapabilityHandle as ft, CapUsageRegistry as g, createHwAccelService as h, createUdsAddonContext as i, capActionSuffix as it, AGENT_CAP_FWD_ACTION as j, createUdsLogger as k, EVENT_TOPIC_PREFIX as l, serializeTypedArrays as lt, resolveHwAccel as m,
|
|
6569
|
+
export { setWorkerNativeCapsChangeListener as $, createUdsLoggerWithControl as A, createLocalTransport as B, ipcParentLink as C, createUdsEventBus as D, createUdsEventBridge as E, CapRouteError as F, FrameDecoder as G, UdsLocalTransportServer as H, classifyCapRoute as I, buildUdsNativeCapProxy as J, encodeFrame as K, LocalChildClient as L, AGENT_CAP_FWD_SERVICE as M, CapRouteResolver as N, udsChildLogToWorkerEntry as O, callWithServiceDiscovery as P, mountNativeCapService as Q, LocalChildRegistry as R, ipcChildLink as S, createParentUnownedCallHandler as T, SocketChannel as U, UdsLocalTransportClient as V, localEndpointPath as W, getWorkerNativeCapProvider as X, createBrokerDeviceManagerApi as Y, getWorkerNativeCapSnapshot as Z, __resetCapUsageRegistryForTests as _, getWorkerDeviceRegistry as a, capBareAction as at, brokerTransportLink as b, setHubConnected as c, deserializeTypedArrays as ct, registerEventBusService as d, CustomActionRegistry as dt, createAddonService as et, AddonDepsManager as f, CapabilityHandle as ft, CapUsageRegistry as g, createHwAccelService as h, resolveAddonClass as ht, createUdsAddonContext as i, capActionSuffix as it, AGENT_CAP_FWD_ACTION as j, createUdsLogger as k, EVENT_TOPIC_PREFIX as l, serializeTypedArrays as lt, resolveHwAccel as m, installManifestNativeDeps as mt, adaptBrokerToCluster as n, NATIVE_PROVIDER_SERVICE_INFIX as nt, getOrInitReadinessRegistry as o, capServiceName as ot, createKernelHwAccel as p, CapabilityUnavailableError as pt, buildNativeCapProxy as q, createAddonContext as r, capActionName as rt, getOrInitReadinessRegistryForClient as s, parseCapAction as st, installManifestPythonDeps as t, validateProviderRegistrations as tt, getBrokerEventBus as u, DeviceRegistry as ut, getCapUsageRegistry as v, localProviderLink as w, buildLinkChain as x, brokerCallForCap as y, UDS_NO_ROUTE_PREFIX as z };
|