@camstack/server 1.0.2 → 1.0.4
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/api/addon-upload.js +17 -3
- package/dist/api/bridge-addons.router.js +1 -1
- package/dist/api/capabilities.router.js +3 -3
- package/dist/api/core/cap-providers.js +3 -3
- package/dist/api/core/logs.router.js +1 -1
- package/dist/api/core/notifications.router.js +1 -1
- package/dist/api/core/repl.router.js +1 -1
- package/dist/api/health/health.routes.js +7 -2
- package/dist/api/trpc/cap-route-error-formatter.js +3 -3
- package/dist/api/trpc/core-cap-bridge.js +2 -2
- package/dist/api/trpc/generated-cap-routers.js +4 -4
- package/dist/boot/boot-config.js +2 -2
- package/dist/boot/post-boot.service.js +2 -2
- package/dist/core/addon/addon-call-gateway.js +1 -1
- package/dist/core/addon/addon-package.service.js +37 -43
- package/dist/core/addon/addon-registry.service.js +61 -51
- package/dist/core/addon-bridge/addon-bridge.service.js +6 -6
- package/dist/core/addon-pages/addon-pages.service.js +1 -1
- package/dist/core/auth/auth.service.js +2 -2
- package/dist/core/config/config.schema.js +4 -4
- package/dist/core/config/config.service.js +2 -2
- package/dist/core/events/event-bus.service.js +2 -2
- package/dist/core/feature/feature.service.js +2 -2
- package/dist/core/lifecycle/lifecycle-state-machine.js +3 -3
- package/dist/core/logging/log-ring-buffer.js +3 -3
- package/dist/core/logging/logging.service.js +3 -3
- package/dist/core/logging/scoped-logger.js +3 -3
- package/dist/core/moleculer/cap-route-authority.js +2 -2
- package/dist/core/moleculer/moleculer.service.js +22 -22
- package/dist/core/network/network-quality.service.js +2 -2
- package/dist/core/notification/notification-wrapper.service.js +2 -2
- package/dist/core/notification/toast-wrapper.service.js +2 -2
- package/dist/core/repl/repl-engine.service.js +2 -2
- package/dist/core/storage/fs-storage-backend.js +3 -3
- package/dist/core/storage/storage-location-manager.js +3 -3
- package/dist/core/storage/storage.service.js +2 -2
- package/dist/launcher.js +18 -12
- package/dist/main.js +17 -4
- package/package.json +3 -3
|
@@ -38,11 +38,11 @@ exports.AddonRegistryService = void 0;
|
|
|
38
38
|
const os = __importStar(require("node:os"));
|
|
39
39
|
const addon_row_manifest_1 = require("./addon-row-manifest");
|
|
40
40
|
const types_1 = require("@camstack/types");
|
|
41
|
-
const
|
|
42
|
-
const
|
|
41
|
+
const system_1 = require("@camstack/system");
|
|
42
|
+
const system_2 = require("@camstack/system");
|
|
43
43
|
const client_1 = require("@trpc/client");
|
|
44
|
-
const
|
|
45
|
-
const
|
|
44
|
+
const system_3 = require("@camstack/system");
|
|
45
|
+
const system_4 = require("@camstack/system");
|
|
46
46
|
const node_crypto_1 = require("node:crypto");
|
|
47
47
|
const path = __importStar(require("node:path"));
|
|
48
48
|
const fs = __importStar(require("node:fs"));
|
|
@@ -55,7 +55,7 @@ const types_3 = require("@camstack/types");
|
|
|
55
55
|
* Type predicate: true when an `ISettingsBackend` also satisfies the
|
|
56
56
|
* sync `ISettingsStore` contract (system/addon/device key-value ops)
|
|
57
57
|
* that ConfigManager expects. The default `SqliteSettingsBackend` in
|
|
58
|
-
* `@camstack/
|
|
58
|
+
* `@camstack/system` implements both surfaces; forked addon backends may
|
|
59
59
|
* not, in which case we skip the ConfigService wiring.
|
|
60
60
|
*/
|
|
61
61
|
function isSettingsStore(backend) {
|
|
@@ -174,7 +174,7 @@ class AddonRegistryService {
|
|
|
174
174
|
// Task 7.1: hub-wide registry of addon custom actions. Populated on
|
|
175
175
|
// each addon's initialize() (in-process path); Task 7.2 will dispatch
|
|
176
176
|
// through this from the `api.addons.custom` tRPC procedure.
|
|
177
|
-
customActionRegistry = new
|
|
177
|
+
customActionRegistry = new system_1.CustomActionRegistry();
|
|
178
178
|
/**
|
|
179
179
|
* AddonIds whose group-runner disconnect is operator-initiated (update /
|
|
180
180
|
* restart / uninstall). The Moleculer `$node.disconnected` handler skips
|
|
@@ -209,7 +209,7 @@ class AddonRegistryService {
|
|
|
209
209
|
getByName: (capName) => reg.getSingleton(capName) ?? reg.getAllProviders(capName)[0] ?? null,
|
|
210
210
|
};
|
|
211
211
|
const client = (0, client_1.createTRPCClient)({
|
|
212
|
-
links: [(0,
|
|
212
|
+
links: [(0, system_2.localProviderLink)(resolver), (0, system_2.brokerTransportLink)(this.moleculer.broker)],
|
|
213
213
|
});
|
|
214
214
|
this.brokerApi = client;
|
|
215
215
|
}
|
|
@@ -225,7 +225,7 @@ class AddonRegistryService {
|
|
|
225
225
|
integrationRegistry = null;
|
|
226
226
|
// Device architecture — in-memory registry of live IDevice instances.
|
|
227
227
|
// Persistence is owned by the `device-manager` capability addon.
|
|
228
|
-
deviceRegistry = new
|
|
228
|
+
deviceRegistry = new system_1.DeviceRegistry();
|
|
229
229
|
/**
|
|
230
230
|
* Typed accessor for the Moleculer broker. The Moleculer `index.d.ts`
|
|
231
231
|
* chains through `eventemitter2`, whose package.json has no `types`
|
|
@@ -249,7 +249,7 @@ class AddonRegistryService {
|
|
|
249
249
|
this.moleculer = moleculer;
|
|
250
250
|
this.streamProbe = streamProbe;
|
|
251
251
|
this.logger = this.loggingService.createLogger('AddonRegistry');
|
|
252
|
-
this.addonLoader = new
|
|
252
|
+
this.addonLoader = new system_1.AddonLoader(this.loggingService.createLogger('AddonLoader'));
|
|
253
253
|
// Kernel-level addon health monitor — drives the 5-min boot grace
|
|
254
254
|
// window + aggressive auto-retry loop (60s/120s/300s, never gives
|
|
255
255
|
// up). Failures and recoveries are recorded by the load + init
|
|
@@ -257,13 +257,13 @@ class AddonRegistryService {
|
|
|
257
257
|
// reattempt failed addons. Operator visibility comes through
|
|
258
258
|
// AddonLoadFailed / AddonLoadRecovered events consumed by
|
|
259
259
|
// AlertCenter (see addon-health-monitor.ts spec).
|
|
260
|
-
this.healthMonitor = new
|
|
260
|
+
this.healthMonitor = new system_1.AddonHealthMonitor({
|
|
261
261
|
eventBus: this.eventBusService,
|
|
262
262
|
logger: this.loggingService.createLogger('AddonHealthMonitor'),
|
|
263
263
|
retryFn: (packageName) => this.tryReloadPackage(packageName),
|
|
264
264
|
});
|
|
265
265
|
// Create capability registry with config reader for singleton preferences
|
|
266
|
-
this.capabilityRegistry = new
|
|
266
|
+
this.capabilityRegistry = new system_1.CapabilityRegistry(this.loggingService.createLogger('CapabilityRegistry'), this.eventBusService);
|
|
267
267
|
this.capabilityRegistry.setConfigReader((capability) => {
|
|
268
268
|
try {
|
|
269
269
|
return this.configService.get(`capabilities.singleton.${capability}`) ?? undefined;
|
|
@@ -386,9 +386,12 @@ class AddonRegistryService {
|
|
|
386
386
|
return;
|
|
387
387
|
this.capabilityRegistry.setSingletonActiveAddon(data.capName, data.addonId ?? null);
|
|
388
388
|
});
|
|
389
|
-
// 2. Load all addons from
|
|
389
|
+
// 2. Load all addons from the addons directory (including core builtins).
|
|
390
|
+
// Honors CAMSTACK_ADDONS_DIR (a `node_modules`-shaped dir on Docker/Electron
|
|
391
|
+
// so forked ESM addon runners resolve @camstack/* via walk-up — see the
|
|
392
|
+
// launcher). Defaults to `<dataDir>/addons` for dev.
|
|
390
393
|
const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
|
|
391
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
394
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
392
395
|
await this.addonLoader.loadFromDirectory(addonsDir);
|
|
393
396
|
// Hand pre-init load failures (broken package.json, missing
|
|
394
397
|
// dist, import-time errors) to the health monitor so its retry
|
|
@@ -447,7 +450,7 @@ class AddonRegistryService {
|
|
|
447
450
|
});
|
|
448
451
|
// Platform probing is no longer orchestrated by the backend. The
|
|
449
452
|
// `platform-probe` capability (shipped as a core builtin under
|
|
450
|
-
// `@camstack/
|
|
453
|
+
// `@camstack/system/dist/builtins/platform-probe/` since Phase B of
|
|
451
454
|
// the bundles refactor) exposes hardware + scored backends via
|
|
452
455
|
// `ctx.api.platformProbe.*`; inference addons auto-configure
|
|
453
456
|
// inside their own `onInitialize`.
|
|
@@ -481,7 +484,7 @@ class AddonRegistryService {
|
|
|
481
484
|
// genuinely has no cross-process provider and the fallback returns null — wrappers
|
|
482
485
|
// cleanly fall through to their own secondary strategy.
|
|
483
486
|
{
|
|
484
|
-
const { buildNativeCapProxy } = await Promise.resolve().then(() => __importStar(require('@camstack/
|
|
487
|
+
const { buildNativeCapProxy } = await Promise.resolve().then(() => __importStar(require('@camstack/system')));
|
|
485
488
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- moleculer types unresolvable; see `broker` getter docstring
|
|
486
489
|
const broker = this.moleculer.broker;
|
|
487
490
|
this.capabilityRegistry.setNativeFallback((capName, deviceId) => {
|
|
@@ -561,7 +564,7 @@ class AddonRegistryService {
|
|
|
561
564
|
// one were declared — the mechanism stays available as an explicit
|
|
562
565
|
// opt-in for future co-location needs.
|
|
563
566
|
//
|
|
564
|
-
// `@camstack/
|
|
567
|
+
// `@camstack/system` builtins and `placement: 'agent-only'` addons are
|
|
565
568
|
// excluded from the plan (filtered inside `buildAddonGroupPlan`).
|
|
566
569
|
// A failed runner spawn is logged and the addon surfaces as
|
|
567
570
|
// `addon.error` — there is NO in-process-on-the-hub fallback (it
|
|
@@ -590,7 +593,7 @@ class AddonRegistryService {
|
|
|
590
593
|
}
|
|
591
594
|
}
|
|
592
595
|
}
|
|
593
|
-
// In-process boot for `@camstack/
|
|
596
|
+
// In-process boot for `@camstack/system` builtins. Core builtins stay
|
|
594
597
|
// resident on the hub process — they provide the storage / settings
|
|
595
598
|
// / logging infrastructure every forked runner depends on, reachable
|
|
596
599
|
// via the hub broker, so `buildAddonGroupPlan` excludes them from
|
|
@@ -599,14 +602,14 @@ class AddonRegistryService {
|
|
|
599
602
|
// storage→settings→logging), then the remaining builtins in
|
|
600
603
|
// capability-dependency order.
|
|
601
604
|
//
|
|
602
|
-
// A core builtin is identified by `packageName === "@camstack/
|
|
605
|
+
// A core builtin is identified by `packageName === "@camstack/system"`,
|
|
603
606
|
// NOT by the absence of an `execution` declaration — a builtin may
|
|
604
607
|
// still declare `execution` (e.g. `platform-probe`); the package
|
|
605
608
|
// boundary is the selection criterion.
|
|
606
|
-
const isCoreBuiltin = (id) => this.addonEntries.get(id)?.packageName === '@camstack/
|
|
609
|
+
const isCoreBuiltin = (id) => this.addonEntries.get(id)?.packageName === '@camstack/system';
|
|
607
610
|
// Pass 1 — infrastructure builtins. A failed REQUIRED infra cap
|
|
608
611
|
// aborts boot: nothing downstream can run without storage/settings.
|
|
609
|
-
for (const infra of
|
|
612
|
+
for (const infra of system_1.INFRA_CAPABILITIES) {
|
|
610
613
|
const addonId = this.findAddonForCapability(infra.name, allIds);
|
|
611
614
|
if (addonId) {
|
|
612
615
|
const entry = this.addonEntries.get(addonId);
|
|
@@ -642,7 +645,7 @@ class AddonRegistryService {
|
|
|
642
645
|
}
|
|
643
646
|
// Pass 2 — remaining core builtins, in capability-dependency order.
|
|
644
647
|
const bootOrder = this.capabilityRegistry.getBootOrder();
|
|
645
|
-
const infraNames = new Set(
|
|
648
|
+
const infraNames = new Set(system_1.INFRA_CAPABILITIES.map((c) => c.name));
|
|
646
649
|
for (const capName of bootOrder) {
|
|
647
650
|
if (infraNames.has(capName))
|
|
648
651
|
continue; // Handled in pass 1
|
|
@@ -783,7 +786,7 @@ class AddonRegistryService {
|
|
|
783
786
|
*/
|
|
784
787
|
async tryReloadPackage(packageName) {
|
|
785
788
|
const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
|
|
786
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
789
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
787
790
|
const addonDir = path.join(addonsDir, packageName);
|
|
788
791
|
if (!fs.existsSync(addonDir)) {
|
|
789
792
|
throw new Error(`Package directory missing: ${addonDir}`);
|
|
@@ -1055,10 +1058,10 @@ class AddonRegistryService {
|
|
|
1055
1058
|
// subprocess. The runner-spawn pass during initial boot already
|
|
1056
1059
|
// spawned every eligible addon; `initializeAddon` is the per-addon
|
|
1057
1060
|
// entry point reached by the hot-load / restart flows (and by the
|
|
1058
|
-
// Pass 1/2/3 in-process boot for `@camstack/
|
|
1061
|
+
// Pass 1/2/3 in-process boot for `@camstack/system` builtins). Fork
|
|
1059
1062
|
// only when the addon declares an `execution` block, ships an
|
|
1060
1063
|
// on-disk `addonDir`, and is not `agent-only`; otherwise (only
|
|
1061
|
-
// `@camstack/
|
|
1064
|
+
// `@camstack/system` builtins reach the in-process path below) it
|
|
1062
1065
|
// boots in-process on the hub.
|
|
1063
1066
|
if (this.isForkedAddonEntry(entry)) {
|
|
1064
1067
|
// D5: one-addon-one-process. A forked addon ALWAYS boots in its
|
|
@@ -1129,7 +1132,7 @@ class AddonRegistryService {
|
|
|
1129
1132
|
// D4: wrapper behaviour is read from the cap DEFINITION. The runtime
|
|
1130
1133
|
// ProviderRegistration.kind/defaultActive are deprecated hints — if an
|
|
1131
1134
|
// addon still sets them and they disagree, warn (the cap def wins).
|
|
1132
|
-
const kindDrift = (0,
|
|
1135
|
+
const kindDrift = (0, system_1.describeProviderKindDrift)(capName, reg.capability, {
|
|
1133
1136
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- this IS the drift detector; it reads the deprecated hint on purpose
|
|
1134
1137
|
kind: reg.kind,
|
|
1135
1138
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- this IS the drift detector; it reads the deprecated hint on purpose
|
|
@@ -1181,7 +1184,7 @@ class AddonRegistryService {
|
|
|
1181
1184
|
if (provider)
|
|
1182
1185
|
capturedProviders.set(capName, provider);
|
|
1183
1186
|
}
|
|
1184
|
-
(0,
|
|
1187
|
+
(0, system_1.validateProviderRegistrations)(id, entry.declaration, capturedProviders, this.logger);
|
|
1185
1188
|
}
|
|
1186
1189
|
await this.restoreAddonDevices(id, entry.addon);
|
|
1187
1190
|
entry.initialized = true;
|
|
@@ -1196,7 +1199,7 @@ class AddonRegistryService {
|
|
|
1196
1199
|
return Object.keys(def.methods);
|
|
1197
1200
|
};
|
|
1198
1201
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- createAddonService return type unresolvable due to upstream eventemitter2/moleculer type chain
|
|
1199
|
-
const schema = (0,
|
|
1202
|
+
const schema = (0, system_1.createAddonService)(entry.addon, entry.declaration, {
|
|
1200
1203
|
methodResolver,
|
|
1201
1204
|
providers: capturedProviders,
|
|
1202
1205
|
});
|
|
@@ -1380,7 +1383,7 @@ class AddonRegistryService {
|
|
|
1380
1383
|
}
|
|
1381
1384
|
// D5: a forked addon ALWAYS restarts via `$process.restart` above
|
|
1382
1385
|
// (process restart — no in-process hot-reload of a live forked
|
|
1383
|
-
// addon). This branch is reached only by `@camstack/
|
|
1386
|
+
// addon). This branch is reached only by `@camstack/system` builtins
|
|
1384
1387
|
// — they have no runner and legitimately reload in-process:
|
|
1385
1388
|
// shutdown, unregister, re-initialize, re-wire.
|
|
1386
1389
|
if (entry.initialized && entry.addon.shutdown) {
|
|
@@ -1469,7 +1472,7 @@ class AddonRegistryService {
|
|
|
1469
1472
|
}
|
|
1470
1473
|
findAddonDirOnDisk(addonId) {
|
|
1471
1474
|
const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
|
|
1472
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
1475
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
1473
1476
|
if (!fs.existsSync(addonsDir))
|
|
1474
1477
|
return null;
|
|
1475
1478
|
const visit = (pkgDir) => {
|
|
@@ -1570,7 +1573,7 @@ class AddonRegistryService {
|
|
|
1570
1573
|
* True when the entry boots in its own forked runner. This MUST mirror
|
|
1571
1574
|
* the fork authority `buildAddonGroupPlan`, which spawns a runner for
|
|
1572
1575
|
* every addon that ships an on-disk `addonDir` + a manifest
|
|
1573
|
-
* `declaration`, is NOT a `@camstack/
|
|
1576
|
+
* `declaration`, is NOT a `@camstack/system` builtin, and is NOT
|
|
1574
1577
|
* `agent-only`. The `execution` block is OPTIONAL — an addon with no
|
|
1575
1578
|
* `execution` declaration still forks on its own dedicated runner
|
|
1576
1579
|
* (`resolveRunnerId` falls back to the addon id). Requiring `execution`
|
|
@@ -1579,13 +1582,13 @@ class AddonRegistryService {
|
|
|
1579
1582
|
* in-process by this predicate, so its route-mount took the co-located
|
|
1580
1583
|
* path and received the async UDS cap proxy whose `getRoutes()` returns
|
|
1581
1584
|
* a Promise (→ `getRoutes(...).map is not a function`). Only
|
|
1582
|
-
* `@camstack/
|
|
1585
|
+
* `@camstack/system` builtins boot in-process on the hub. The type
|
|
1583
1586
|
* predicate narrows both `addonDir` and `declaration` for callers.
|
|
1584
1587
|
*/
|
|
1585
1588
|
isForkedAddonEntry(entry) {
|
|
1586
1589
|
return !!(entry.declaration &&
|
|
1587
1590
|
entry.addonDir &&
|
|
1588
|
-
entry.packageName !== '@camstack/
|
|
1591
|
+
entry.packageName !== '@camstack/system' &&
|
|
1589
1592
|
(0, types_1.resolveAddonPlacement)(entry.declaration) !== 'agent-only');
|
|
1590
1593
|
}
|
|
1591
1594
|
/** Per-entry helper used by `listAddons()` to mark a row removable / not. */
|
|
@@ -1675,7 +1678,7 @@ class AddonRegistryService {
|
|
|
1675
1678
|
*/
|
|
1676
1679
|
scanFailedToLoadPackages(seenPackages) {
|
|
1677
1680
|
const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
|
|
1678
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
1681
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
1679
1682
|
if (!fs.existsSync(addonsDir))
|
|
1680
1683
|
return [];
|
|
1681
1684
|
const out = [];
|
|
@@ -1791,7 +1794,7 @@ class AddonRegistryService {
|
|
|
1791
1794
|
async listAddonProcesses() {
|
|
1792
1795
|
const result = [];
|
|
1793
1796
|
// Collect hub PID and fetch stats
|
|
1794
|
-
const { getPidStats } = await Promise.resolve().then(() => __importStar(require('@camstack/
|
|
1797
|
+
const { getPidStats } = await Promise.resolve().then(() => __importStar(require('@camstack/system')));
|
|
1795
1798
|
const pidStats = await getPidStats([process.pid]);
|
|
1796
1799
|
// In-process addons
|
|
1797
1800
|
const hubStats = pidStats.get(process.pid);
|
|
@@ -1832,9 +1835,9 @@ class AddonRegistryService {
|
|
|
1832
1835
|
*/
|
|
1833
1836
|
async loadNewAddons() {
|
|
1834
1837
|
const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
|
|
1835
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
1838
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
1836
1839
|
// Create a fresh loader to discover what's on disk (for diffing against existing)
|
|
1837
|
-
const freshLoader = new
|
|
1840
|
+
const freshLoader = new system_1.AddonLoader(this.loggingService.createLogger('AddonLoader'));
|
|
1838
1841
|
await freshLoader.loadFromDirectory(addonsDir);
|
|
1839
1842
|
const loaded = [];
|
|
1840
1843
|
const failed = [];
|
|
@@ -1916,7 +1919,7 @@ class AddonRegistryService {
|
|
|
1916
1919
|
// D5: every non-core addon lives in its own runner subprocess. The
|
|
1917
1920
|
// uninstall consolidation is "stop the runner"; the runner exits and
|
|
1918
1921
|
// re-handshakes the hub WITHOUT the removed addon (D3 machinery).
|
|
1919
|
-
// Only `@camstack/
|
|
1922
|
+
// Only `@camstack/system` builtins — which have no runner — take the
|
|
1920
1923
|
// in-process `shutdown()` + disposer-drain path.
|
|
1921
1924
|
const onDiskIds = new Set(freshLoader.listAddons().map((a) => a.declaration.id));
|
|
1922
1925
|
for (const [id, entry] of this.addonEntries) {
|
|
@@ -1948,7 +1951,7 @@ class AddonRegistryService {
|
|
|
1948
1951
|
}
|
|
1949
1952
|
}
|
|
1950
1953
|
else if (entry.initialized) {
|
|
1951
|
-
// `@camstack/
|
|
1954
|
+
// `@camstack/system` builtin — reload model is in-process.
|
|
1952
1955
|
try {
|
|
1953
1956
|
await entry.addon.shutdown();
|
|
1954
1957
|
}
|
|
@@ -2047,7 +2050,7 @@ class AddonRegistryService {
|
|
|
2047
2050
|
this.configService.setSettingsStore(provider);
|
|
2048
2051
|
}
|
|
2049
2052
|
this.storageService.setSettingsBackend(provider);
|
|
2050
|
-
this.integrationRegistry = new
|
|
2053
|
+
this.integrationRegistry = new system_4.IntegrationRegistry(provider);
|
|
2051
2054
|
void this.integrationRegistry.initialize().then(() => {
|
|
2052
2055
|
this.logger.info('IntegrationRegistry initialized', { meta: { phase: 'v2' } });
|
|
2053
2056
|
});
|
|
@@ -2129,7 +2132,7 @@ class AddonRegistryService {
|
|
|
2129
2132
|
if (!routeProvider)
|
|
2130
2133
|
return;
|
|
2131
2134
|
// ── Forked addon: fetch handler-stripped routes over UDS (F3) ──────
|
|
2132
|
-
// EVERY non-`@camstack/
|
|
2135
|
+
// EVERY non-`@camstack/system` addon forks (the fork authority is
|
|
2133
2136
|
// `buildAddonGroupPlan`, which does NOT require an `execution` block — an
|
|
2134
2137
|
// addon like `auth-oidc` with no `execution` still runs in its own
|
|
2135
2138
|
// runner). `isForkedAddonEntry` now mirrors that rule. For a forked addon
|
|
@@ -2163,7 +2166,7 @@ class AddonRegistryService {
|
|
|
2163
2166
|
});
|
|
2164
2167
|
return;
|
|
2165
2168
|
}
|
|
2166
|
-
// ── Co-located addon (`@camstack/
|
|
2169
|
+
// ── Co-located addon (`@camstack/system` builtin): live handlers, register
|
|
2167
2170
|
// the provider directly. The route handlers run in-process against the
|
|
2168
2171
|
// real Fastify reply, so no wire bridge is needed.
|
|
2169
2172
|
addonRouteRegistry.registerRoutes(routeProvider.id, routeProvider);
|
|
@@ -2404,7 +2407,7 @@ class AddonRegistryService {
|
|
|
2404
2407
|
probe: (url, options) => this.streamProbe.probe(url, options),
|
|
2405
2408
|
probeField: (key, value) => this.streamProbe.probeField(key, value),
|
|
2406
2409
|
};
|
|
2407
|
-
const deviceManagerApi = (0,
|
|
2410
|
+
const deviceManagerApi = (0, system_1.createBrokerDeviceManagerApi)({
|
|
2408
2411
|
api: this.getBrokerApi(),
|
|
2409
2412
|
addonId,
|
|
2410
2413
|
nodeId: this.broker.nodeID,
|
|
@@ -2418,11 +2421,11 @@ class AddonRegistryService {
|
|
|
2418
2421
|
const rr = this.moleculer.readinessRegistry;
|
|
2419
2422
|
const capHandleCache = new Map();
|
|
2420
2423
|
function getOrCreateHandle(capName, scope, timeoutMs) {
|
|
2421
|
-
const key = `${capName}::${(0,
|
|
2424
|
+
const key = `${capName}::${(0, system_1.scopeKey)(scope)}`;
|
|
2422
2425
|
const existing = capHandleCache.get(key);
|
|
2423
2426
|
if (existing)
|
|
2424
2427
|
return existing;
|
|
2425
|
-
const handle = new
|
|
2428
|
+
const handle = new system_1.CapabilityHandle(capName, scope, rr, timeoutMs);
|
|
2426
2429
|
capHandleCache.set(key, handle);
|
|
2427
2430
|
return handle;
|
|
2428
2431
|
}
|
|
@@ -2455,15 +2458,15 @@ class AddonRegistryService {
|
|
|
2455
2458
|
return registry.capabilityRegistry.getSingleton(capName) ?? undefined;
|
|
2456
2459
|
},
|
|
2457
2460
|
},
|
|
2458
|
-
deps: new
|
|
2461
|
+
deps: new system_3.AddonDepsManager(dataDir, logger),
|
|
2459
2462
|
kernel: {
|
|
2460
2463
|
localNodeId: this.broker.nodeID,
|
|
2461
2464
|
storage: storageProvider ?? undefined,
|
|
2462
2465
|
deviceRegistry: this.deviceRegistry ?? undefined,
|
|
2463
2466
|
devices: deviceManagerApi,
|
|
2464
|
-
cluster: { broker: (0,
|
|
2467
|
+
cluster: { broker: (0, system_1.adaptBrokerToCluster)(this.moleculer.broker) },
|
|
2465
2468
|
streamProbe: kernelStreamProbe,
|
|
2466
|
-
hwaccel: (0,
|
|
2469
|
+
hwaccel: (0, system_1.createKernelHwAccel)(),
|
|
2467
2470
|
capabilityRegistry: this.capabilityRegistry,
|
|
2468
2471
|
// Per-addon storage-location declarations across every installed
|
|
2469
2472
|
// addon — surfaced from the kernel's AddonLoader so the
|
|
@@ -2567,7 +2570,7 @@ class AddonRegistryService {
|
|
|
2567
2570
|
* passes a live JS reference across a process boundary any more.
|
|
2568
2571
|
*
|
|
2569
2572
|
* Addons with `placement: 'agent-only'` are dropped (they don't run on
|
|
2570
|
-
* the hub). `@camstack/
|
|
2573
|
+
* the hub). `@camstack/system` builtins are dropped too — they stay
|
|
2571
2574
|
* in-process on the hub (every forked runner connects to the hub
|
|
2572
2575
|
* broker via static-URL TCP transit, so cap providers hosted on the
|
|
2573
2576
|
* hub broker are reachable from any runner with one hop; moving them
|
|
@@ -2583,7 +2586,7 @@ class AddonRegistryService {
|
|
|
2583
2586
|
const entry = this.addonEntries.get(id);
|
|
2584
2587
|
if (!entry?.declaration || !entry.addonDir)
|
|
2585
2588
|
continue;
|
|
2586
|
-
if (entry.packageName === '@camstack/
|
|
2589
|
+
if (entry.packageName === '@camstack/system')
|
|
2587
2590
|
continue;
|
|
2588
2591
|
const placement = (0, types_1.resolveAddonPlacement)(entry.declaration);
|
|
2589
2592
|
if (placement === 'agent-only')
|
|
@@ -2631,7 +2634,7 @@ class AddonRegistryService {
|
|
|
2631
2634
|
for (const { addonId } of addons) {
|
|
2632
2635
|
await this.registerForkedAddonCustomActions(addonId, runnerId);
|
|
2633
2636
|
// Mark the entry initialized so the in-process core-builtin boot
|
|
2634
|
-
// passes skip it (those passes only touch `@camstack/
|
|
2637
|
+
// passes skip it (those passes only touch `@camstack/system`).
|
|
2635
2638
|
const entry = this.addonEntries.get(addonId);
|
|
2636
2639
|
if (entry) {
|
|
2637
2640
|
entry.initialized = true;
|
|
@@ -2701,7 +2704,14 @@ class AddonRegistryService {
|
|
|
2701
2704
|
// Cache-bust so a hot-updated bundle is re-read instead of served
|
|
2702
2705
|
// from Node's ESM module cache.
|
|
2703
2706
|
const cacheBustedUrl = `${(0, node_url_1.pathToFileURL)(entryPath).href}?t=${Date.now()}`;
|
|
2704
|
-
|
|
2707
|
+
// A plain `await import()` here is downleveled by tsc (the backend builds
|
|
2708
|
+
// with `module: CommonJS`) into a `require()`-based shim. `require()` then
|
|
2709
|
+
// treats the `?t=…` cache-bust query as part of the literal filename and
|
|
2710
|
+
// throws MODULE_NOT_FOUND for EVERY forked addon — so no forked addon's
|
|
2711
|
+
// custom-action catalog ever loaded. Use a native dynamic import the
|
|
2712
|
+
// compiler won't rewrite, so Node's ESM loader handles the query string.
|
|
2713
|
+
const nativeImport = new Function('specifier', 'return import(specifier)');
|
|
2714
|
+
const modUnknown = await nativeImport(cacheBustedUrl);
|
|
2705
2715
|
catalog =
|
|
2706
2716
|
modUnknown && typeof modUnknown === 'object'
|
|
2707
2717
|
? modUnknown['customActions']
|
|
@@ -69,9 +69,9 @@ class AddonBridgeService {
|
|
|
69
69
|
// Initialize installer eagerly in constructor (no async needed).
|
|
70
70
|
// This ensures install/uninstall works even before onModuleInit completes.
|
|
71
71
|
try {
|
|
72
|
-
const kernel = require('@camstack/
|
|
72
|
+
const kernel = require('@camstack/system');
|
|
73
73
|
const dataDir = process.env.CAMSTACK_DATA ?? 'camstack-data';
|
|
74
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
74
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
75
75
|
const workspacePackagesDir = kernel.detectWorkspacePackagesDir(__dirname);
|
|
76
76
|
this.installer = new kernel.AddonInstaller({
|
|
77
77
|
addonsDir,
|
|
@@ -87,10 +87,10 @@ class AddonBridgeService {
|
|
|
87
87
|
async onModuleInit() {
|
|
88
88
|
this.logger.info('Initializing addon bridge (package management only)...');
|
|
89
89
|
try {
|
|
90
|
-
const kernel = await Promise.resolve().then(() => __importStar(require('@camstack/
|
|
90
|
+
const kernel = await Promise.resolve().then(() => __importStar(require('@camstack/system')));
|
|
91
91
|
this.loader = new kernel.AddonLoader(this.logger.child('AddonLoader'));
|
|
92
92
|
const dataDir = process.env.CAMSTACK_DATA ?? 'camstack-data';
|
|
93
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
93
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
94
94
|
await this.loader.loadFromDirectory(addonsDir);
|
|
95
95
|
this.available = true;
|
|
96
96
|
this.logger.info('Addon bridge initialized', {
|
|
@@ -134,10 +134,10 @@ class AddonBridgeService {
|
|
|
134
134
|
this.logger.warn('reloadPackages called but bridge is unavailable — skipping');
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
|
-
const kernel = await Promise.resolve().then(() => __importStar(require('@camstack/
|
|
137
|
+
const kernel = await Promise.resolve().then(() => __importStar(require('@camstack/system')));
|
|
138
138
|
this.loader = new kernel.AddonLoader(this.logger.child('AddonLoader'));
|
|
139
139
|
const dataDir = process.env.CAMSTACK_DATA ?? 'camstack-data';
|
|
140
|
-
const addonsDir = path.resolve(dataDir, 'addons');
|
|
140
|
+
const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
|
|
141
141
|
await this.loader.loadFromDirectory(addonsDir);
|
|
142
142
|
this.logger.info('Reloaded', { meta: { count: this.loader.listAddons().length } });
|
|
143
143
|
}
|
|
@@ -42,7 +42,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
42
42
|
*
|
|
43
43
|
* The public listing surface (`addonPages.listPages` on the AppRouter)
|
|
44
44
|
* has been split out of this class — it now lives in the
|
|
45
|
-
* `addon-pages-aggregator` builtin (`@camstack/
|
|
45
|
+
* `addon-pages-aggregator` builtin (`@camstack/system/builtins/...`)
|
|
46
46
|
* which walks every `addon-pages-source` collection provider and
|
|
47
47
|
* stamps versioned `bundleUrl`s. The split lets both ends flow through
|
|
48
48
|
* codegen instead of relying on a hand-written wrapper.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AuthService = void 0;
|
|
4
|
-
const
|
|
5
|
-
class AuthService extends
|
|
4
|
+
const system_1 = require("@camstack/system");
|
|
5
|
+
class AuthService extends system_1.AuthManager {
|
|
6
6
|
constructor(config) {
|
|
7
7
|
super(config);
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RUNTIME_DEFAULTS = exports.bootstrapSchema = void 0;
|
|
4
|
-
// Re-export from @camstack/
|
|
5
|
-
var
|
|
6
|
-
Object.defineProperty(exports, "bootstrapSchema", { enumerable: true, get: function () { return
|
|
7
|
-
Object.defineProperty(exports, "RUNTIME_DEFAULTS", { enumerable: true, get: function () { return
|
|
4
|
+
// Re-export from @camstack/system
|
|
5
|
+
var system_1 = require("@camstack/system");
|
|
6
|
+
Object.defineProperty(exports, "bootstrapSchema", { enumerable: true, get: function () { return system_1.bootstrapSchema; } });
|
|
7
|
+
Object.defineProperty(exports, "RUNTIME_DEFAULTS", { enumerable: true, get: function () { return system_1.RUNTIME_DEFAULTS; } });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConfigService = void 0;
|
|
4
|
-
const
|
|
5
|
-
class ConfigService extends
|
|
4
|
+
const system_1 = require("@camstack/system");
|
|
5
|
+
class ConfigService extends system_1.ConfigManager {
|
|
6
6
|
constructor(configPath) {
|
|
7
7
|
super(configPath);
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EventBusService = void 0;
|
|
4
|
-
const
|
|
4
|
+
const system_1 = require("@camstack/system");
|
|
5
5
|
/**
|
|
6
6
|
* Hub-side event bus. Pre-broker boot the service buffers nothing —
|
|
7
7
|
* subscribers / emits are no-ops until `attachBroker` lands the
|
|
@@ -36,7 +36,7 @@ class EventBusService {
|
|
|
36
36
|
if (this.broker === broker)
|
|
37
37
|
return;
|
|
38
38
|
this.broker = broker;
|
|
39
|
-
const inner = (0,
|
|
39
|
+
const inner = (0, system_1.getBrokerEventBus)(broker);
|
|
40
40
|
this.inner = inner;
|
|
41
41
|
// Replay deferred subscriptions onto the real bus.
|
|
42
42
|
for (const sub of this.deferredSubs) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FeatureService = void 0;
|
|
4
|
-
const
|
|
5
|
-
class FeatureService extends
|
|
4
|
+
const system_1 = require("@camstack/system");
|
|
5
|
+
class FeatureService extends system_1.FeatureManager {
|
|
6
6
|
constructor(configService) {
|
|
7
7
|
super(configService);
|
|
8
8
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LifecycleStateMachine = void 0;
|
|
4
|
-
// Re-export from @camstack/
|
|
5
|
-
var
|
|
6
|
-
Object.defineProperty(exports, "LifecycleStateMachine", { enumerable: true, get: function () { return
|
|
4
|
+
// Re-export from @camstack/system — LifecycleStateMachine is already a plain class
|
|
5
|
+
var system_1 = require("@camstack/system");
|
|
6
|
+
Object.defineProperty(exports, "LifecycleStateMachine", { enumerable: true, get: function () { return system_1.LifecycleStateMachine; } });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LogRingBuffer = void 0;
|
|
4
|
-
// Re-export from @camstack/
|
|
5
|
-
var
|
|
6
|
-
Object.defineProperty(exports, "LogRingBuffer", { enumerable: true, get: function () { return
|
|
4
|
+
// Re-export from @camstack/system
|
|
5
|
+
var system_1 = require("@camstack/system");
|
|
6
|
+
Object.defineProperty(exports, "LogRingBuffer", { enumerable: true, get: function () { return system_1.LogRingBuffer; } });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LoggingService = void 0;
|
|
4
|
-
const
|
|
4
|
+
const system_1 = require("@camstack/system");
|
|
5
5
|
const types_1 = require("@camstack/types");
|
|
6
6
|
/** Baseline tags every hub-local logger gets, so console output never
|
|
7
7
|
* falls back to `?` for the agent slot. Hub-local addons already
|
|
@@ -13,7 +13,7 @@ const types_1 = require("@camstack/types");
|
|
|
13
13
|
* forked workers via `$hub.log` carry their own `tags.pid` which
|
|
14
14
|
* wins over this baseline (right-biased merge in `writeFromWorker`). */
|
|
15
15
|
const HUB_BASELINE_TAGS = { agentId: 'hub', nodeId: 'hub', pid: process.pid };
|
|
16
|
-
class LoggingService extends
|
|
16
|
+
class LoggingService extends system_1.LogManager {
|
|
17
17
|
/**
|
|
18
18
|
* Device-name cache consulted by the formatter when a log line
|
|
19
19
|
* carries `tags.deviceId` but no explicit `deviceName`. Populated
|
|
@@ -31,7 +31,7 @@ class LoggingService extends core_1.LogManager {
|
|
|
31
31
|
super(perAddonCapacity);
|
|
32
32
|
// Enriches every emitted LogEntry with `tags.deviceName` before
|
|
33
33
|
// destinations / subscribers see it — works across bundled copies
|
|
34
|
-
// of `@camstack/
|
|
34
|
+
// of `@camstack/system` (addon packages) because the mutation
|
|
35
35
|
// happens upstream of their formatters.
|
|
36
36
|
this.setDeviceNameLookup((id) => this.deviceNames.get(id) ?? null);
|
|
37
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ScopedLogger = void 0;
|
|
4
|
-
// Re-export from @camstack/
|
|
5
|
-
var
|
|
6
|
-
Object.defineProperty(exports, "ScopedLogger", { enumerable: true, get: function () { return
|
|
4
|
+
// Re-export from @camstack/system
|
|
5
|
+
var system_1 = require("@camstack/system");
|
|
6
|
+
Object.defineProperty(exports, "ScopedLogger", { enumerable: true, get: function () { return system_1.ScopedLogger; } });
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Adapter factories that bridge the server-side registry/service state into the
|
|
4
|
-
* narrow interfaces that CapRouteResolver (in @camstack/
|
|
4
|
+
* narrow interfaces that CapRouteResolver (in @camstack/system) requires.
|
|
5
5
|
*
|
|
6
6
|
* Layer note: this file is in server/backend and may import server-side types.
|
|
7
|
-
* The resolver itself (in @camstack/
|
|
7
|
+
* The resolver itself (in @camstack/system) must NOT import from here —
|
|
8
8
|
* it depends only on the narrow interfaces (NodeCapAuthority, InProcessProviderLookup)
|
|
9
9
|
* defined in the kernel. These factories are the wiring adapters.
|
|
10
10
|
*
|