@camstack/system 1.0.7 → 1.1.0
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 +3 -3
- package/dist/addon-runner.mjs +3 -3
- package/dist/addon-utils.js +1 -1
- package/dist/addon-utils.mjs +1 -1
- 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/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/index.js +153 -78
- package/dist/index.mjs +153 -79
- package/dist/kernel/addon-installer.d.ts +20 -0
- package/dist/kernel/config-manager.d.ts +4 -4
- package/dist/kernel/fs-utils.d.ts +16 -6
- package/dist/kernel/index.d.ts +2 -1
- package/dist/kernel/moleculer/addon-deploy-source.d.ts +16 -0
- package/dist/kernel/transport/child-cap-protocol.d.ts +10 -0
- package/dist/{manifest-python-deps-eBDj5HEY.js → manifest-python-deps-BWURo7dc.js} +34 -17
- package/dist/{manifest-python-deps-CoJXeb9u.mjs → manifest-python-deps-BcrTzHH_.mjs} +54 -37
- package/dist/{model-download-service-JtVQtbb6.js → model-download-service-1eEOkNeS.js} +35 -5
- package/dist/{model-download-service-C7AjBsX9.mjs → model-download-service-RxAOiYvX.mjs} +35 -5
- package/package.json +1 -1
|
@@ -161,7 +161,7 @@ var StorageOrchestratorService = class {
|
|
|
161
161
|
const resolver = this.nodeLocalResolver;
|
|
162
162
|
if (!resolver) return;
|
|
163
163
|
let stamped = 0;
|
|
164
|
-
for (const [id, loc] of
|
|
164
|
+
for (const [id, loc] of Array.from(this.locations)) {
|
|
165
165
|
if (loc.nodeId) continue;
|
|
166
166
|
if (resolver(loc.providerId) !== true) continue;
|
|
167
167
|
const updated = {
|
|
@@ -301,7 +301,7 @@ var StorageOrchestratorService = class {
|
|
|
301
301
|
this.logger.warn("storage-orchestrator: skipping prune — no location declarations loaded (fail-safe)");
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
|
-
for (const [id, loc] of
|
|
304
|
+
for (const [id, loc] of Array.from(this.locations)) {
|
|
305
305
|
if (this.registry.cardinalityOf(loc.type) !== null) continue;
|
|
306
306
|
if (loc.isSystem) {
|
|
307
307
|
this.locations.delete(id);
|
|
@@ -154,7 +154,7 @@ var StorageOrchestratorService = class {
|
|
|
154
154
|
const resolver = this.nodeLocalResolver;
|
|
155
155
|
if (!resolver) return;
|
|
156
156
|
let stamped = 0;
|
|
157
|
-
for (const [id, loc] of
|
|
157
|
+
for (const [id, loc] of Array.from(this.locations)) {
|
|
158
158
|
if (loc.nodeId) continue;
|
|
159
159
|
if (resolver(loc.providerId) !== true) continue;
|
|
160
160
|
const updated = {
|
|
@@ -294,7 +294,7 @@ var StorageOrchestratorService = class {
|
|
|
294
294
|
this.logger.warn("storage-orchestrator: skipping prune — no location declarations loaded (fail-safe)");
|
|
295
295
|
return;
|
|
296
296
|
}
|
|
297
|
-
for (const [id, loc] of
|
|
297
|
+
for (const [id, loc] of Array.from(this.locations)) {
|
|
298
298
|
if (this.registry.cardinalityOf(loc.type) !== null) continue;
|
|
299
299
|
if (loc.isSystem) {
|
|
300
300
|
this.locations.delete(id);
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_model_download_service = require("./model-download-service-
|
|
3
|
+
const require_model_download_service = require("./model-download-service-1eEOkNeS.js");
|
|
4
4
|
const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
|
|
5
5
|
const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
|
|
6
6
|
const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
|
|
@@ -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-BWURo7dc.js");
|
|
24
24
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
25
25
|
const require_graceful_fs$1 = require("./graceful-fs-lg19SZNz.js");
|
|
26
26
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -183,7 +183,7 @@ function proxyToUpstream(opts) {
|
|
|
183
183
|
}
|
|
184
184
|
//#endregion
|
|
185
185
|
//#region src/python/python-env-manager.ts
|
|
186
|
-
var execFileAsync$
|
|
186
|
+
var execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
|
|
187
187
|
var PythonEnvManager = class {
|
|
188
188
|
venvPath;
|
|
189
189
|
cachedProbe = null;
|
|
@@ -193,12 +193,12 @@ var PythonEnvManager = class {
|
|
|
193
193
|
async probe() {
|
|
194
194
|
if (this.cachedProbe) return this.cachedProbe;
|
|
195
195
|
for (const cmd of ["python3", "python"]) try {
|
|
196
|
-
const { stdout } = await execFileAsync$
|
|
196
|
+
const { stdout } = await execFileAsync$3(cmd, ["--version"]);
|
|
197
197
|
const version = stdout.trim().replace("Python ", "");
|
|
198
198
|
const major = parseInt(version.split(".")[0] ?? "0", 10);
|
|
199
199
|
const minor = parseInt(version.split(".")[1] ?? "0", 10);
|
|
200
200
|
if (major < 3 || major === 3 && minor < 10) continue;
|
|
201
|
-
const { stdout: pathOut } = await execFileAsync$
|
|
201
|
+
const { stdout: pathOut } = await execFileAsync$3(cmd, ["-c", "import sys; print(sys.executable)"]);
|
|
202
202
|
this.cachedProbe = {
|
|
203
203
|
available: true,
|
|
204
204
|
version,
|
|
@@ -214,13 +214,13 @@ var PythonEnvManager = class {
|
|
|
214
214
|
async ensure(options) {
|
|
215
215
|
const probe = await this.probe();
|
|
216
216
|
if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
|
|
217
|
-
if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$
|
|
217
|
+
if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$3(probe.path, [
|
|
218
218
|
"-m",
|
|
219
219
|
"venv",
|
|
220
220
|
this.venvPath
|
|
221
221
|
]);
|
|
222
222
|
const venvPython = node_path.join(this.venvPath, "bin", "python");
|
|
223
|
-
if (options.packages.length > 0) await execFileAsync$
|
|
223
|
+
if (options.packages.length > 0) await execFileAsync$3(venvPython, [
|
|
224
224
|
"-m",
|
|
225
225
|
"pip",
|
|
226
226
|
"install",
|
|
@@ -1419,12 +1419,11 @@ var StorageManager = class {
|
|
|
1419
1419
|
return namespace ? this.createNamespacedLocation(location, namespace) : location;
|
|
1420
1420
|
}
|
|
1421
1421
|
createLegacyShim() {
|
|
1422
|
-
const self = this;
|
|
1423
1422
|
return {
|
|
1424
1423
|
async initialize() {},
|
|
1425
1424
|
async shutdown() {},
|
|
1426
|
-
getLocation(name) {
|
|
1427
|
-
return
|
|
1425
|
+
getLocation: (name) => {
|
|
1426
|
+
return this.getLocation(name);
|
|
1428
1427
|
}
|
|
1429
1428
|
};
|
|
1430
1429
|
}
|
|
@@ -1700,7 +1699,7 @@ function matchPath(pattern, path) {
|
|
|
1700
1699
|
}
|
|
1701
1700
|
//#endregion
|
|
1702
1701
|
//#region src/tls/cert-manager.ts
|
|
1703
|
-
var execFileAsync$
|
|
1702
|
+
var execFileAsync$2 = (0, node_util.promisify)(node_child_process.execFile);
|
|
1704
1703
|
/**
|
|
1705
1704
|
* Ensure a self-signed TLS certificate exists in the given directory.
|
|
1706
1705
|
* Generates one if missing. Returns paths to cert and key files.
|
|
@@ -1737,7 +1736,7 @@ async function ensureTlsCert(dataDir, options) {
|
|
|
1737
1736
|
for (const dns of sanDns) sanParts.push(`DNS:${dns}`);
|
|
1738
1737
|
for (const ip of sanIps) sanParts.push(`IP:${ip}`);
|
|
1739
1738
|
const sanString = sanParts.join(",");
|
|
1740
|
-
await execFileAsync$
|
|
1739
|
+
await execFileAsync$2("openssl", [
|
|
1741
1740
|
"req",
|
|
1742
1741
|
"-x509",
|
|
1743
1742
|
"-newkey",
|
|
@@ -2570,6 +2569,7 @@ var AddonEngineManager = class {
|
|
|
2570
2569
|
};
|
|
2571
2570
|
//#endregion
|
|
2572
2571
|
//#region src/kernel/fs-utils.ts
|
|
2572
|
+
var execFileAsync$1 = (0, node_util.promisify)(node_child_process.execFile);
|
|
2573
2573
|
/**
|
|
2574
2574
|
* Ensure a directory exists (recursive).
|
|
2575
2575
|
* Single source of truth — replaces scattered mkdirSync calls.
|
|
@@ -2578,18 +2578,20 @@ function ensureDir(dirPath) {
|
|
|
2578
2578
|
node_fs.mkdirSync(dirPath, { recursive: true });
|
|
2579
2579
|
}
|
|
2580
2580
|
/**
|
|
2581
|
-
* Copy a directory recursively.
|
|
2582
|
-
*
|
|
2581
|
+
* Copy a directory recursively — ASYNC so it never blocks the event loop.
|
|
2582
|
+
*
|
|
2583
|
+
* The hub installs addons into `/data/addons`, which on Unraid is a slow
|
|
2584
|
+
* shfs/FUSE mount. The former synchronous `fs.copyFileSync`-per-file loop
|
|
2585
|
+
* blocked the Node event loop for the whole copy of a large bundle (e.g.
|
|
2586
|
+
* `addon-pipeline`), which froze the hub's HTTP listener mid-`camstack deploy`
|
|
2587
|
+
* (accept backlog piling up, existing connections stuck in CLOSE_WAIT). Using
|
|
2588
|
+
* `fs.promises.cp` keeps the I/O off the event loop. (Node ≥18 stable.)
|
|
2583
2589
|
*/
|
|
2584
|
-
function copyDirRecursive(src, dest) {
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
const destPath = node_path.join(dest, entry.name);
|
|
2590
|
-
if (entry.isDirectory()) copyDirRecursive(srcPath, destPath);
|
|
2591
|
-
else node_fs.copyFileSync(srcPath, destPath);
|
|
2592
|
-
}
|
|
2590
|
+
async function copyDirRecursive(src, dest) {
|
|
2591
|
+
await node_fs.promises.cp(src, dest, {
|
|
2592
|
+
recursive: true,
|
|
2593
|
+
force: true
|
|
2594
|
+
});
|
|
2593
2595
|
}
|
|
2594
2596
|
/**
|
|
2595
2597
|
* Strip @camstack/* dependencies and devDependencies from a package.json object.
|
|
@@ -2619,7 +2621,7 @@ function stripCamstackDeps(pkg) {
|
|
|
2619
2621
|
* Copies directories (not individual files) from source to destination.
|
|
2620
2622
|
* Skips "dist" (already handled) and glob patterns.
|
|
2621
2623
|
*/
|
|
2622
|
-
function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
|
|
2624
|
+
async function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
|
|
2623
2625
|
const rawFiles = pkgJson.files;
|
|
2624
2626
|
if (!Array.isArray(rawFiles)) return;
|
|
2625
2627
|
for (const fileEntry of rawFiles) {
|
|
@@ -2628,11 +2630,11 @@ function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
|
|
|
2628
2630
|
const srcPath = node_path.join(sourceDir, fileEntry);
|
|
2629
2631
|
if (!node_fs.existsSync(srcPath)) continue;
|
|
2630
2632
|
const destPath = node_path.join(destDir, fileEntry);
|
|
2631
|
-
const stat = node_fs.
|
|
2632
|
-
if (stat.isDirectory()) copyDirRecursive(srcPath, destPath);
|
|
2633
|
+
const stat = await node_fs.promises.stat(srcPath);
|
|
2634
|
+
if (stat.isDirectory()) await copyDirRecursive(srcPath, destPath);
|
|
2633
2635
|
else if (stat.isFile()) {
|
|
2634
2636
|
ensureDir(node_path.dirname(destPath));
|
|
2635
|
-
node_fs.
|
|
2637
|
+
await node_fs.promises.copyFile(srcPath, destPath);
|
|
2636
2638
|
}
|
|
2637
2639
|
}
|
|
2638
2640
|
}
|
|
@@ -2677,12 +2679,16 @@ function ensureLibraryBuilt(packageName, packagesDir) {
|
|
|
2677
2679
|
/**
|
|
2678
2680
|
* Install a single npm package into a target directory (package.json + dist/).
|
|
2679
2681
|
* No validation on camstack.addons -- works for any @camstack/* package.
|
|
2680
|
-
*
|
|
2682
|
+
*
|
|
2683
|
+
* ASYNC: uses `execFile`/`fs.promises` throughout so a package install on a
|
|
2684
|
+
* live node never blocks the event loop (the `npm pack` + tar extract + copy to
|
|
2685
|
+
* the slow shfs/FUSE `/data` would otherwise freeze the HTTP listener). See
|
|
2686
|
+
* `copyDirRecursive` for the wedge this prevents.
|
|
2681
2687
|
*/
|
|
2682
|
-
function
|
|
2683
|
-
const tmpDir = node_fs.
|
|
2688
|
+
async function installPackageFromNpm(packageName, targetDir) {
|
|
2689
|
+
const tmpDir = await node_fs.promises.mkdtemp(node_path.join(node_os.tmpdir(), "camstack-install-"));
|
|
2684
2690
|
try {
|
|
2685
|
-
const
|
|
2691
|
+
const { stdout } = await execFileAsync$1("npm", [
|
|
2686
2692
|
"pack",
|
|
2687
2693
|
packageName,
|
|
2688
2694
|
"--pack-destination",
|
|
@@ -2690,12 +2696,13 @@ function installPackageFromNpmSync(packageName, targetDir) {
|
|
|
2690
2696
|
], {
|
|
2691
2697
|
timeout: 12e4,
|
|
2692
2698
|
encoding: "utf-8"
|
|
2693
|
-
})
|
|
2699
|
+
});
|
|
2700
|
+
const tgzFilename = stdout.trim().split("\n").pop()?.trim();
|
|
2694
2701
|
if (!tgzFilename) throw new Error("npm pack produced no output");
|
|
2695
2702
|
const tgzPath = node_path.join(tmpDir, tgzFilename);
|
|
2696
2703
|
const extractDir = node_path.join(tmpDir, "extracted");
|
|
2697
2704
|
ensureDir(extractDir);
|
|
2698
|
-
|
|
2705
|
+
await execFileAsync$1("tar", [
|
|
2699
2706
|
"-xzf",
|
|
2700
2707
|
tgzPath,
|
|
2701
2708
|
"-C",
|
|
@@ -2703,20 +2710,20 @@ function installPackageFromNpmSync(packageName, targetDir) {
|
|
|
2703
2710
|
], { timeout: 3e4 });
|
|
2704
2711
|
const packageSubDir = node_path.join(extractDir, "package");
|
|
2705
2712
|
const srcPkgJsonDir = node_fs.existsSync(node_path.join(packageSubDir, "package.json")) ? packageSubDir : extractDir;
|
|
2706
|
-
node_fs.
|
|
2713
|
+
await node_fs.promises.rm(targetDir, {
|
|
2707
2714
|
recursive: true,
|
|
2708
2715
|
force: true
|
|
2709
2716
|
});
|
|
2710
2717
|
ensureDir(targetDir);
|
|
2711
|
-
node_fs.
|
|
2718
|
+
await node_fs.promises.copyFile(node_path.join(srcPkgJsonDir, "package.json"), node_path.join(targetDir, "package.json"));
|
|
2712
2719
|
const distSrc = node_path.join(srcPkgJsonDir, "dist");
|
|
2713
|
-
if (node_fs.existsSync(distSrc)) copyDirRecursive(distSrc, node_path.join(targetDir, "dist"));
|
|
2720
|
+
if (node_fs.existsSync(distSrc)) await copyDirRecursive(distSrc, node_path.join(targetDir, "dist"));
|
|
2714
2721
|
try {
|
|
2715
|
-
const npmPkg = (0, _camstack_types.asJsonObject)((0, _camstack_types.parseJsonUnknown)(node_fs.
|
|
2716
|
-
if (npmPkg) copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir);
|
|
2722
|
+
const npmPkg = (0, _camstack_types.asJsonObject)((0, _camstack_types.parseJsonUnknown)(await node_fs.promises.readFile(node_path.join(srcPkgJsonDir, "package.json"), "utf-8")));
|
|
2723
|
+
if (npmPkg) await copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir);
|
|
2717
2724
|
} catch {}
|
|
2718
2725
|
} finally {
|
|
2719
|
-
node_fs.
|
|
2726
|
+
await node_fs.promises.rm(tmpDir, {
|
|
2720
2727
|
recursive: true,
|
|
2721
2728
|
force: true
|
|
2722
2729
|
});
|
|
@@ -3166,15 +3173,15 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3166
3173
|
await this.ensureBuilt(packageName, sourceDir, pkgData);
|
|
3167
3174
|
const distDir = node_path.join(sourceDir, "dist");
|
|
3168
3175
|
if (!node_fs.existsSync(distDir)) throw new Error(`${packageName} has no dist/ after build`);
|
|
3169
|
-
node_fs.
|
|
3176
|
+
await node_fs.promises.rm(targetDir, {
|
|
3170
3177
|
recursive: true,
|
|
3171
3178
|
force: true
|
|
3172
3179
|
});
|
|
3173
3180
|
ensureDir(targetDir);
|
|
3174
|
-
node_fs.
|
|
3175
|
-
copyDirRecursive(distDir, node_path.join(targetDir, "dist"));
|
|
3176
|
-
copyExtraFileDirs(pkgData, sourceDir, targetDir);
|
|
3177
|
-
node_fs.
|
|
3181
|
+
await node_fs.promises.writeFile(node_path.join(targetDir, "package.json"), JSON.stringify(stripCamstackDeps(pkgData), null, 2));
|
|
3182
|
+
await copyDirRecursive(distDir, node_path.join(targetDir, "dist"));
|
|
3183
|
+
await copyExtraFileDirs(pkgData, sourceDir, targetDir);
|
|
3184
|
+
await node_fs.promises.writeFile(node_path.join(targetDir, ".install-source"), "local");
|
|
3178
3185
|
const localPkgVersion = (0, _camstack_types.asString)(pkgData.version, "0.0.0");
|
|
3179
3186
|
this.manifest.upsert(packageName, {
|
|
3180
3187
|
version: localPkgVersion,
|
|
@@ -3277,6 +3284,66 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3277
3284
|
node_fs.writeFileSync(tgzPath, buf);
|
|
3278
3285
|
return tgzPath;
|
|
3279
3286
|
}
|
|
3287
|
+
/**
|
|
3288
|
+
* Evict an existing install dir by atomic rename-aside, then best-effort
|
|
3289
|
+
* delete the aside copy.
|
|
3290
|
+
*
|
|
3291
|
+
* Why not a plain `fs.promises.rm(targetDir, {recursive})`: during a
|
|
3292
|
+
* `camstack deploy` the addon's live runner still holds its native
|
|
3293
|
+
* prebuilds (`.node`/`.so`) open. On the hub's shfs/FUSE `/data/addons`,
|
|
3294
|
+
* a recursive rm of a held subdir fails `ENOTEMPTY` mid-walk and leaves
|
|
3295
|
+
* the dir gutted. A rename only touches the dirent (metadata), so it
|
|
3296
|
+
* succeeds with the inodes still open — the old runner keeps its fds on
|
|
3297
|
+
* the moved inodes until it restarts.
|
|
3298
|
+
*
|
|
3299
|
+
* The aside copy is removed best-effort: the held native libs are only
|
|
3300
|
+
* released once the post-install `restartAddon` recycles the runner, so a
|
|
3301
|
+
* failure to delete it now must NOT fail the install. Any residue is swept
|
|
3302
|
+
* on the next deploy.
|
|
3303
|
+
*/
|
|
3304
|
+
async evictInstallDir(targetDir) {
|
|
3305
|
+
if (!node_fs.existsSync(targetDir)) return;
|
|
3306
|
+
const graveyard = node_path.join(this.addonsDir, ".evicting");
|
|
3307
|
+
ensureDir(graveyard);
|
|
3308
|
+
await this.sweepGraveyard(graveyard);
|
|
3309
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3310
|
+
const flatName = node_path.relative(this.addonsDir, targetDir).replace(/[/\\]/g, "-");
|
|
3311
|
+
const asideDir = node_path.join(graveyard, `${flatName}-${ts}`);
|
|
3312
|
+
try {
|
|
3313
|
+
node_fs.renameSync(targetDir, asideDir);
|
|
3314
|
+
} catch (renameErr) {
|
|
3315
|
+
if (renameErr.code === "EXDEV") {
|
|
3316
|
+
await node_fs.promises.rm(targetDir, {
|
|
3317
|
+
recursive: true,
|
|
3318
|
+
force: true
|
|
3319
|
+
});
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
throw renameErr;
|
|
3323
|
+
}
|
|
3324
|
+
await node_fs.promises.rm(asideDir, {
|
|
3325
|
+
recursive: true,
|
|
3326
|
+
force: true
|
|
3327
|
+
}).catch((cleanupErr) => {
|
|
3328
|
+
this.logger.debug("evictInstallDir: aside cleanup deferred (likely held open)", { meta: {
|
|
3329
|
+
asideDir,
|
|
3330
|
+
error: (0, _camstack_types.errMsg)(cleanupErr)
|
|
3331
|
+
} });
|
|
3332
|
+
});
|
|
3333
|
+
}
|
|
3334
|
+
/** Best-effort removal of leftover `.evicting/*` dirs from earlier deploys. */
|
|
3335
|
+
async sweepGraveyard(graveyard) {
|
|
3336
|
+
let entries;
|
|
3337
|
+
try {
|
|
3338
|
+
entries = node_fs.readdirSync(graveyard);
|
|
3339
|
+
} catch {
|
|
3340
|
+
return;
|
|
3341
|
+
}
|
|
3342
|
+
await Promise.all(entries.map((name) => node_fs.promises.rm(node_path.join(graveyard, name), {
|
|
3343
|
+
recursive: true,
|
|
3344
|
+
force: true
|
|
3345
|
+
}).catch(() => void 0)));
|
|
3346
|
+
}
|
|
3280
3347
|
/** Install addon from a tgz file (uploaded or downloaded) */
|
|
3281
3348
|
async installFromTgz(tgzPath) {
|
|
3282
3349
|
const tmpDir = node_fs.mkdtempSync(node_path.join(node_os.tmpdir(), "camstack-addon-install-"));
|
|
@@ -3294,17 +3361,14 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3294
3361
|
if (!pkgView) throw new Error(`Invalid package.json at ${pkgJsonPath}`);
|
|
3295
3362
|
if (!pkgView.camstackAddons) throw new Error(`Package ${pkgView.name} has no camstack.addons manifest`);
|
|
3296
3363
|
const targetDir = node_path.join(this.addonsDir, pkgView.name);
|
|
3297
|
-
|
|
3298
|
-
recursive: true,
|
|
3299
|
-
force: true
|
|
3300
|
-
});
|
|
3364
|
+
await this.evictInstallDir(targetDir);
|
|
3301
3365
|
ensureDir(targetDir);
|
|
3302
3366
|
const sourceDir = node_path.dirname(pkgJsonPath);
|
|
3303
3367
|
const strippedManifest = stripCamstackDeps(pkgView.raw);
|
|
3304
|
-
node_fs.
|
|
3368
|
+
await node_fs.promises.writeFile(node_path.join(targetDir, "package.json"), JSON.stringify(strippedManifest, null, 2));
|
|
3305
3369
|
const sourceDist = node_path.join(sourceDir, "dist");
|
|
3306
|
-
if (node_fs.existsSync(sourceDist)) copyDirRecursive(sourceDist, node_path.join(targetDir, "dist"));
|
|
3307
|
-
copyExtraFileDirs(pkgView.raw, sourceDir, targetDir);
|
|
3370
|
+
if (node_fs.existsSync(sourceDist)) await copyDirRecursive(sourceDist, node_path.join(targetDir, "dist"));
|
|
3371
|
+
await copyExtraFileDirs(pkgView.raw, sourceDir, targetDir);
|
|
3308
3372
|
const strippedRuntimeDeps = strippedManifest["dependencies"];
|
|
3309
3373
|
if (strippedRuntimeDeps != null && typeof strippedRuntimeDeps === "object" && Object.keys(strippedRuntimeDeps).length > 0) {
|
|
3310
3374
|
this.logger.info(`${pkgView.name} — installing runtime dependencies`, { meta: { targetDir } });
|
|
@@ -3328,7 +3392,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3328
3392
|
try {
|
|
3329
3393
|
await require_manifest_python_deps.installManifestNativeDeps(targetDir, pkgView.raw, this.logger, this.registry);
|
|
3330
3394
|
} catch (nativeErr) {
|
|
3331
|
-
node_fs.
|
|
3395
|
+
await node_fs.promises.rm(targetDir, {
|
|
3332
3396
|
recursive: true,
|
|
3333
3397
|
force: true
|
|
3334
3398
|
});
|
|
@@ -3343,7 +3407,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3343
3407
|
version: pkgView.version
|
|
3344
3408
|
};
|
|
3345
3409
|
} finally {
|
|
3346
|
-
node_fs.
|
|
3410
|
+
await node_fs.promises.rm(tmpDir, {
|
|
3347
3411
|
recursive: true,
|
|
3348
3412
|
force: true
|
|
3349
3413
|
});
|
|
@@ -4111,7 +4175,7 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
4111
4175
|
const bare = this.bareAddonId(addonId);
|
|
4112
4176
|
const nodeMap = this.singletonNodeOverrides.get(capabilityName);
|
|
4113
4177
|
if (nodeMap) {
|
|
4114
|
-
for (const [nodeId, ov] of
|
|
4178
|
+
for (const [nodeId, ov] of Array.from(nodeMap)) if (ov === bare) nodeMap.delete(nodeId);
|
|
4115
4179
|
if (nodeMap.size === 0) this.singletonNodeOverrides.delete(capabilityName);
|
|
4116
4180
|
}
|
|
4117
4181
|
this.logger.info("Provider unregistered from capability", {
|
|
@@ -7388,20 +7452,20 @@ var ConfigManager = class ConfigManager {
|
|
|
7388
7452
|
setSettingsStore(store) {
|
|
7389
7453
|
this.settingsStore = store;
|
|
7390
7454
|
}
|
|
7391
|
-
get(
|
|
7392
|
-
return this.resolveConfigValue(
|
|
7455
|
+
get(configPath) {
|
|
7456
|
+
return this.resolveConfigValue(configPath);
|
|
7393
7457
|
}
|
|
7394
|
-
resolveConfigValue(
|
|
7395
|
-
const bootstrapValue = this.getFromBootstrap(
|
|
7458
|
+
resolveConfigValue(configPath) {
|
|
7459
|
+
const bootstrapValue = this.getFromBootstrap(configPath);
|
|
7396
7460
|
if (bootstrapValue !== void 0) return bootstrapValue;
|
|
7397
7461
|
if (this.settingsStore !== null) {
|
|
7398
|
-
const storeValue = this.settingsStore.getSystem(
|
|
7462
|
+
const storeValue = this.settingsStore.getSystem(configPath);
|
|
7399
7463
|
if (storeValue !== void 0) return storeValue;
|
|
7400
|
-
const nested = this.getNestedFromSystemSettings(
|
|
7464
|
+
const nested = this.getNestedFromSystemSettings(configPath);
|
|
7401
7465
|
if (nested !== null) return nested;
|
|
7402
7466
|
}
|
|
7403
|
-
if (
|
|
7404
|
-
return this.getFromRuntimeDefaults(
|
|
7467
|
+
if (configPath in _camstack_types.RUNTIME_DEFAULTS) return _camstack_types.RUNTIME_DEFAULTS[configPath];
|
|
7468
|
+
return this.getFromRuntimeDefaults(configPath) ?? void 0;
|
|
7405
7469
|
}
|
|
7406
7470
|
/**
|
|
7407
7471
|
* Write a value to the settings-store.
|
|
@@ -7617,8 +7681,8 @@ var ConfigManager = class ConfigManager {
|
|
|
7617
7681
|
};
|
|
7618
7682
|
this.saveRuntimeState();
|
|
7619
7683
|
}
|
|
7620
|
-
getBootstrap(
|
|
7621
|
-
return this.getFromBootstrap(
|
|
7684
|
+
getBootstrap(configPath) {
|
|
7685
|
+
return this.getFromBootstrap(configPath);
|
|
7622
7686
|
}
|
|
7623
7687
|
/** Features accessor -- reads from settings-store when available, falls back to RUNTIME_DEFAULTS */
|
|
7624
7688
|
get features() {
|
|
@@ -7708,8 +7772,8 @@ var ConfigManager = class ConfigManager {
|
|
|
7708
7772
|
* Deep-set a value in a nested plain object using a dot-notation path.
|
|
7709
7773
|
* Returns a new object (immutable).
|
|
7710
7774
|
*/
|
|
7711
|
-
setNested(obj,
|
|
7712
|
-
const [head, ...rest] =
|
|
7775
|
+
setNested(obj, configPath, value) {
|
|
7776
|
+
const [head, ...rest] = configPath.split(".");
|
|
7713
7777
|
if (!head) return obj;
|
|
7714
7778
|
if (rest.length === 0) return {
|
|
7715
7779
|
...obj,
|
|
@@ -7749,8 +7813,8 @@ var ConfigManager = class ConfigManager {
|
|
|
7749
7813
|
warnDefaultCredentials() {
|
|
7750
7814
|
if (this.bootstrapConfig.auth.adminPassword === "changeme") console.warn("[ConfigManager] Warning: Using default admin password \"changeme\". Set auth.adminPassword in your config.yaml or the CAMSTACK_ADMIN_PASS env var.");
|
|
7751
7815
|
}
|
|
7752
|
-
getFromBootstrap(
|
|
7753
|
-
const keys =
|
|
7816
|
+
getFromBootstrap(configPath) {
|
|
7817
|
+
const keys = configPath.split(".");
|
|
7754
7818
|
let current = this.bootstrapConfig;
|
|
7755
7819
|
for (const key of keys) {
|
|
7756
7820
|
if (!isRecord(current)) return void 0;
|
|
@@ -7758,8 +7822,8 @@ var ConfigManager = class ConfigManager {
|
|
|
7758
7822
|
}
|
|
7759
7823
|
return current;
|
|
7760
7824
|
}
|
|
7761
|
-
getFromRuntimeDefaults(
|
|
7762
|
-
const prefix =
|
|
7825
|
+
getFromRuntimeDefaults(configPath) {
|
|
7826
|
+
const prefix = configPath + ".";
|
|
7763
7827
|
const result = {};
|
|
7764
7828
|
let found = false;
|
|
7765
7829
|
for (const [key, value] of Object.entries(_camstack_types.RUNTIME_DEFAULTS)) if (key.startsWith(prefix)) {
|
|
@@ -7774,10 +7838,10 @@ var ConfigManager = class ConfigManager {
|
|
|
7774
7838
|
* e.g. path='features' matches keys 'features.streaming', 'features.notifications', etc.
|
|
7775
7839
|
* Returns an object keyed by the sub-key, or undefined if nothing is found.
|
|
7776
7840
|
*/
|
|
7777
|
-
getNestedFromSystemSettings(
|
|
7841
|
+
getNestedFromSystemSettings(configPath) {
|
|
7778
7842
|
if (this.settingsStore === null) return null;
|
|
7779
7843
|
const all = this.settingsStore.getAllSystem();
|
|
7780
|
-
const prefix =
|
|
7844
|
+
const prefix = configPath + ".";
|
|
7781
7845
|
const result = {};
|
|
7782
7846
|
let found = false;
|
|
7783
7847
|
for (const [key, value] of Object.entries(all)) if (key.startsWith(prefix)) {
|
|
@@ -89897,6 +89961,15 @@ function normalizeHubUrl(raw, defaultPort) {
|
|
|
89897
89961
|
return `${/:\d+$/.test(hostPort) ? hostPort : `${hostPort}:${defaultPort}`}/${nodeId}`;
|
|
89898
89962
|
}
|
|
89899
89963
|
//#endregion
|
|
89964
|
+
//#region src/kernel/moleculer/addon-deploy-source.ts
|
|
89965
|
+
function isAddonDeploySource(v) {
|
|
89966
|
+
if (!v || typeof v !== "object") return false;
|
|
89967
|
+
const o = v;
|
|
89968
|
+
if (o["kind"] === "npm") return typeof o["version"] === "string";
|
|
89969
|
+
if (o["kind"] === "hub-http") return typeof o["url"] === "string" && typeof o["token"] === "string" && typeof o["sha256"] === "string" && typeof o["bytes"] === "number";
|
|
89970
|
+
return false;
|
|
89971
|
+
}
|
|
89972
|
+
//#endregion
|
|
89900
89973
|
//#region src/kernel/moleculer/core-cap-service.ts
|
|
89901
89974
|
/**
|
|
89902
89975
|
* Default Moleculer service name for the hub core-capability bridge.
|
|
@@ -90938,7 +91011,7 @@ function createProcessService(parentNodeId, dataDir, deps, parentTcpPort, parent
|
|
|
90938
91011
|
respawned.restartCount = prevRestartCount + 1;
|
|
90939
91012
|
});
|
|
90940
91013
|
restarted.push(name);
|
|
90941
|
-
} catch
|
|
91014
|
+
} catch {
|
|
90942
91015
|
failed.push(name);
|
|
90943
91016
|
}
|
|
90944
91017
|
return {
|
|
@@ -91333,8 +91406,8 @@ var LifecycleJobEngine = class {
|
|
|
91333
91406
|
} finally {
|
|
91334
91407
|
clearTimeout(timer);
|
|
91335
91408
|
}
|
|
91336
|
-
if (packages.length === 0) throw new Error("stageFramework returned no packages");
|
|
91337
91409
|
const [firstPackage] = packages;
|
|
91410
|
+
if (!firstPackage) throw new Error("stageFramework returned no packages");
|
|
91338
91411
|
this.advance(job.jobId, task, "staged", { stagedPath: firstPackage.stagedPath });
|
|
91339
91412
|
requestFrameworkSwap({
|
|
91340
91413
|
jobId: job.jobId,
|
|
@@ -91357,14 +91430,15 @@ var LifecycleJobEngine = class {
|
|
|
91357
91430
|
*/
|
|
91358
91431
|
async fetchAddonsBounded(job, addonTasks) {
|
|
91359
91432
|
const limit = Math.max(1, this.deps.fetchConcurrency ?? DEFAULT_FETCH_CONCURRENCY);
|
|
91360
|
-
const outcomes =
|
|
91433
|
+
const outcomes = Array.from({ length: addonTasks.length });
|
|
91361
91434
|
let nextIndex = 0;
|
|
91362
91435
|
const worker = async () => {
|
|
91363
91436
|
for (;;) {
|
|
91364
91437
|
const index = nextIndex;
|
|
91365
91438
|
nextIndex += 1;
|
|
91366
|
-
|
|
91367
|
-
|
|
91439
|
+
const addonTask = addonTasks[index];
|
|
91440
|
+
if (addonTask === void 0) return;
|
|
91441
|
+
outcomes[index] = await this.fetchAddonTask(job, addonTask);
|
|
91368
91442
|
}
|
|
91369
91443
|
};
|
|
91370
91444
|
const workerCount = Math.min(limit, addonTasks.length);
|
|
@@ -91732,7 +91806,7 @@ exports.getWorkerDeviceRegistry = require_manifest_python_deps.getWorkerDeviceRe
|
|
|
91732
91806
|
exports.hashClusterSecret = hashClusterSecret;
|
|
91733
91807
|
exports.installManifestNativeDeps = require_manifest_python_deps.installManifestNativeDeps;
|
|
91734
91808
|
exports.installManifestPythonDeps = require_manifest_python_deps.installManifestPythonDeps;
|
|
91735
|
-
exports.
|
|
91809
|
+
exports.installPackageFromNpm = installPackageFromNpm;
|
|
91736
91810
|
Object.defineProperty(exports, "installPythonPackages", {
|
|
91737
91811
|
enumerable: true,
|
|
91738
91812
|
get: function() {
|
|
@@ -91747,6 +91821,7 @@ Object.defineProperty(exports, "installPythonRequirements", {
|
|
|
91747
91821
|
});
|
|
91748
91822
|
exports.ipcChildLink = require_manifest_python_deps.ipcChildLink;
|
|
91749
91823
|
exports.ipcParentLink = require_manifest_python_deps.ipcParentLink;
|
|
91824
|
+
exports.isAddonDeploySource = isAddonDeploySource;
|
|
91750
91825
|
exports.isClusterSecretMismatchError = isClusterSecretMismatchError;
|
|
91751
91826
|
exports.isInfraCapability = isInfraCapability;
|
|
91752
91827
|
exports.isModelDownloaded = require_model_download_service.isModelDownloaded;
|