@camstack/server 1.2.593 → 1.2.594
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-root-inventory.js +11 -50
- package/dist/agent/addon-scan.js +6 -44
- package/dist/agent/agent-addon-runtime.js +3 -8
- package/dist/agent/agent-addon-updates.js +12 -52
- package/dist/agent/agent-cap-dispatch-service.js +3 -5
- package/dist/agent/agent-config.js +7 -42
- package/dist/agent/agent-deploy-swap.js +5 -41
- package/dist/agent/agent-group-runner.js +8 -47
- package/dist/agent/agent-http-auth.js +10 -22
- package/dist/agent/agent-http.js +69 -115
- package/dist/agent/agent-hub-addon-update.js +10 -16
- package/dist/agent/agent-hub-registration.js +4 -7
- package/dist/agent/agent-infra-capabilities.js +5 -9
- package/dist/agent/agent-json-file.js +5 -42
- package/dist/agent/agent-mesh-gate.js +5 -8
- package/dist/agent/agent-node-certificates.js +25 -28
- package/dist/agent/agent-pairing-local.js +10 -47
- package/dist/agent/agent-pairing-routes.js +16 -20
- package/dist/agent/agent-pairing-store.js +18 -58
- package/dist/agent/agent-reconnect.js +1 -4
- package/dist/agent/agent-service.js +42 -78
- package/dist/agent/agent-sniffing-listener.js +11 -48
- package/dist/agent/agent-undeploy.js +5 -41
- package/dist/agent/agent-update-routes.js +14 -19
- package/dist/agent/agent-update-service.js +38 -80
- package/dist/agent/apply-model-distribution.js +1 -4
- package/dist/agent/apply-stage-dev-uploads.js +6 -9
- package/dist/agent/derive-hub-url.js +3 -8
- package/dist/agent/fetch-bundle-from-hub.js +6 -9
- package/dist/agent/hubs-found.js +6 -43
- package/dist/agent/infra-boot-guard.js +1 -4
- package/dist/agent/infra-boot-plan.js +2 -6
- package/dist/agent/main.js +158 -186
- package/dist/agent/register-agent-cap-dispatch.js +3 -6
- package/dist/agent/serial-queue.js +2 -7
- package/dist/agent-status-page.js +1 -4
- package/dist/api/addon-upload.js +22 -61
- package/dist/api/agent-addon-delivery.js +6 -11
- package/dist/api/auth-whoami.js +1 -4
- package/dist/api/backup-download-pump.js +5 -9
- package/dist/api/backup-download.js +7 -10
- package/dist/api/core/addon-settings.router.js +16 -19
- package/dist/api/core/agent-pairing.router.js +76 -79
- package/dist/api/core/agents.router.js +21 -24
- package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
- package/dist/api/core/auth-device-cert.procedures.js +62 -67
- package/dist/api/core/auth-limits.js +16 -25
- package/dist/api/core/auth-reauth.procedures.js +32 -37
- package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
- package/dist/api/core/auth-sessions.procedures.js +52 -56
- package/dist/api/core/auth.router.js +300 -304
- package/dist/api/core/cap-providers.js +74 -121
- package/dist/api/core/capabilities.router.js +34 -37
- package/dist/api/core/capability-preference-writes.js +10 -17
- package/dist/api/core/certificates.router.js +106 -109
- package/dist/api/core/cluster-nodes.router.js +15 -18
- package/dist/api/core/collection-preference.js +2 -6
- package/dist/api/core/event-bus-proxy.router.js +34 -37
- package/dist/api/core/failure-contributions.js +4 -8
- package/dist/api/core/hwaccel.router.js +17 -20
- package/dist/api/core/integration-secrets.js +8 -12
- package/dist/api/core/lifecycle-job-runner.js +13 -49
- package/dist/api/core/live-events.router.js +29 -32
- package/dist/api/core/load-contributions.js +4 -8
- package/dist/api/core/logging-settings.js +30 -43
- package/dist/api/core/logs.router.js +40 -43
- package/dist/api/core/notifications.router.js +15 -18
- package/dist/api/core/public-event-filter.js +4 -8
- package/dist/api/core/repl.router.js +18 -21
- package/dist/api/core/request-census-settings.js +11 -16
- package/dist/api/core/server-management.provider.js +1 -4
- package/dist/api/core/server-name.js +9 -17
- package/dist/api/core/site-location.js +16 -24
- package/dist/api/core/stream-probe.router.js +21 -24
- package/dist/api/core/system-events.router.js +23 -26
- package/dist/api/cors/cors-policy.js +20 -29
- package/dist/api/cors/register-cors-policy.js +9 -14
- package/dist/api/deploy-stage-registry.js +6 -10
- package/dist/api/dev-uploads-bundle.js +12 -50
- package/dist/api/health/adaptive-probe.routes.js +9 -13
- package/dist/api/health/health.routes.js +8 -13
- package/dist/api/hub-cluster-url.js +3 -9
- package/dist/api/model-distributor.js +12 -50
- package/dist/api/oauth2/consent-page.js +10 -13
- package/dist/api/oauth2/oauth2-routes.js +17 -25
- package/dist/api/oauth2/private-host.js +1 -4
- package/dist/api/server-upload-propagate.js +15 -51
- package/dist/api/server-upload.js +13 -50
- package/dist/api/sse-no-compression.js +1 -4
- package/dist/api/static/frame-policy.js +4 -9
- package/dist/api/static/precompressed-asset.js +15 -57
- package/dist/api/static/spa-mount.js +8 -47
- package/dist/api/static/spa-static.js +5 -12
- package/dist/api/tarball-manifest.js +7 -44
- package/dist/api/trpc/cap-mount-helpers.js +7 -12
- package/dist/api/trpc/cap-route-error-formatter.js +10 -13
- package/dist/api/trpc/cap-router-runtime.js +40 -51
- package/dist/api/trpc/client-ip.js +9 -20
- package/dist/api/trpc/core-cap-bridge.js +32 -42
- package/dist/api/trpc/device-collection-dispatch.js +23 -27
- package/dist/api/trpc/device-config-secret-redaction.js +24 -40
- package/dist/api/trpc/generated-cap-mounts.js +218 -222
- package/dist/api/trpc/generated-cap-routers.js +4688 -4850
- package/dist/api/trpc/http-request-census-hook.js +8 -11
- package/dist/api/trpc/http-request-census.js +34 -41
- package/dist/api/trpc/http-request-census.singleton.js +4 -8
- package/dist/api/trpc/localized-schema-paths.js +1 -4
- package/dist/api/trpc/principal-visibility.js +14 -22
- package/dist/api/trpc/remote-addon-update-grant.js +1 -4
- package/dist/api/trpc/scope-access.js +10 -15
- package/dist/api/trpc/server-provided-caps.js +3 -7
- package/dist/api/trpc/share-view-access.js +6 -14
- package/dist/api/trpc/trpc-error-device-tags.js +3 -6
- package/dist/api/trpc/trpc-error-principal.js +2 -6
- package/dist/api/trpc/trpc.context.js +20 -25
- package/dist/api/trpc/trpc.middleware.js +38 -46
- package/dist/api/trpc/trpc.router.js +58 -99
- package/dist/api/trpc/user-error.js +5 -8
- package/dist/api/trpc/ws-request-census.js +17 -24
- package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
- package/dist/api/upload-auth.js +5 -9
- package/dist/auth/addon-route-jwt-gate.js +4 -7
- package/dist/auth/addon-route-share-gate.js +7 -12
- package/dist/auth/app-confirm-page.js +17 -22
- package/dist/auth/app-confirm-routes.js +26 -31
- package/dist/auth/app-confirmations.js +7 -44
- package/dist/auth/app-page-shell.js +17 -30
- package/dist/auth/app-page-strings.js +11 -17
- package/dist/auth/app-passkey-page.js +16 -21
- package/dist/auth/app-passkey-routes.js +37 -41
- package/dist/auth/app-refused-route.js +13 -18
- package/dist/auth/auth-network-policy.js +11 -15
- package/dist/auth/auth-provider-gate.js +4 -9
- package/dist/auth/auth-rate-limit.js +3 -7
- package/dist/auth/client-address.js +6 -9
- package/dist/auth/device-enroll-proofs.js +6 -43
- package/dist/auth/external-link-intents.js +3 -7
- package/dist/auth/hub-sessions.js +6 -12
- package/dist/auth/native-link-completions.js +7 -11
- package/dist/auth/native-return.js +9 -13
- package/dist/auth/passkey-provider.js +26 -32
- package/dist/auth/second-factors.js +6 -10
- package/dist/auth/session-connections.js +6 -12
- package/dist/auth/session-cookie.js +12 -23
- package/dist/auth/session-lifetimes.js +8 -12
- package/dist/auth/session-mint.js +4 -11
- package/dist/auth/sso-finish-app.js +13 -16
- package/dist/auth/sso-finish-deps.js +21 -27
- package/dist/auth/sso-finish.js +28 -38
- package/dist/auth/sso-routes.js +22 -25
- package/dist/auth/used-bridge-ids.js +1 -5
- package/dist/boot/boot-config.js +16 -55
- package/dist/boot/init-sequence.js +1 -4
- package/dist/boot/integration-id-backfill.js +3 -8
- package/dist/boot/platform-keychain-key.js +5 -42
- package/dist/boot/post-boot.service.js +14 -18
- package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
- package/dist/boot/retired-public-url-env.js +4 -8
- package/dist/bootstrap-packages.js +1 -4
- package/dist/closure-node-modules.js +2 -38
- package/dist/closure-patches/patch-reach.json +6 -2
- package/dist/core/addon/addon-call-gateway.js +1 -5
- package/dist/core/addon/addon-package.service.js +83 -123
- package/dist/core/addon/addon-process-view.js +2 -6
- package/dist/core/addon/addon-realign-plan.js +1 -4
- package/dist/core/addon/addon-registry.service.js +199 -185
- package/dist/core/addon/addon-row-manifest.js +1 -4
- package/dist/core/addon/addon-search.service.js +3 -7
- package/dist/core/addon/addon-settings-provider.js +1 -3
- package/dist/core/addon/addon-uninstall.js +4 -11
- package/dist/core/addon/addon.tokens.js +2 -5
- package/dist/core/addon/device-meta-mirror.js +8 -13
- package/dist/core/addon/forked-custom-actions.js +6 -11
- package/dist/core/addon/integration-visibility.js +3 -6
- package/dist/core/addon/materialize-route-path.js +1 -4
- package/dist/core/addon/package-dir-utils.js +8 -45
- package/dist/core/addon/prune-misplaced-addons.js +5 -43
- package/dist/core/addon/runner-convergence.js +1 -4
- package/dist/core/addon/runner-serialization.js +1 -4
- package/dist/core/addon/runner-spawn-fanout.js +3 -8
- package/dist/core/addon/settings-door-wiring.js +5 -8
- package/dist/core/addon/single-flight-refresh.js +1 -4
- package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
- package/dist/core/addon-pages/addon-pages.service.js +3 -40
- package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
- package/dist/core/agent/agent-addon-backfill.js +9 -17
- package/dist/core/agent/agent-delivery-ledger.js +3 -7
- package/dist/core/agent/agent-liveness-event.js +2 -6
- package/dist/core/agent/agent-pairing-http.js +41 -45
- package/dist/core/agent/agent-registry.service.js +53 -92
- package/dist/core/agent/cluster-node-history-mirror.js +3 -7
- package/dist/core/agent/cluster-node-history-store.js +113 -58
- package/dist/core/agent/hub-agent-pairing.js +1 -5
- package/dist/core/agent/node-certificates-client.js +3 -6
- package/dist/core/agent/node-directory.js +1 -4
- package/dist/core/app-links/well-known-app-links.js +2 -6
- package/dist/core/auth/auth.service.js +3 -8
- package/dist/core/auth/handoff-code.service.js +11 -49
- package/dist/core/auth/record-kinds.js +35 -0
- package/dist/core/auth/share-token.service.js +174 -122
- package/dist/core/capability/capability.service.js +1 -5
- package/dist/core/config/config.schema.js +1 -6
- package/dist/core/config/config.service.js +2 -6
- package/dist/core/events/event-bus.service.js +3 -7
- package/dist/core/feature/feature.service.js +2 -6
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
- package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
- package/dist/core/logging/log-ring-buffer.js +1 -5
- package/dist/core/logging/logging.service.js +5 -9
- package/dist/core/logging/scoped-logger.js +1 -5
- package/dist/core/moleculer/agent-readiness-pull.js +1 -4
- package/dist/core/moleculer/agent-registration-request.js +3 -7
- package/dist/core/moleculer/cap-call-fn.js +39 -5
- package/dist/core/moleculer/cap-route-authority.js +3 -8
- package/dist/core/moleculer/hub-mesh-guard.js +5 -9
- package/dist/core/moleculer/moleculer.service.js +108 -119
- package/dist/core/network/network-quality.service.js +2 -6
- package/dist/core/notification/notification-wrapper.service.js +3 -7
- package/dist/core/notification/toast-wrapper.service.js +3 -7
- package/dist/core/provider/provider.tokens.js +1 -4
- package/dist/core/repl/repl-engine.service.js +4 -8
- package/dist/core/runner-health/runner-boot-check.js +7 -15
- package/dist/core/runner-health/update-preflight.js +9 -14
- package/dist/core/server-update/server-update.service.js +12 -49
- package/dist/core/server-update/system-apply-closure-patches.js +6 -42
- package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
- package/dist/core/server-update/system-exec-npm.js +2 -5
- package/dist/core/storage/fs-storage-backend.js +1 -5
- package/dist/core/storage/storage-location-manager.js +1 -5
- package/dist/core/storage/storage.service.js +2 -6
- package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
- package/dist/core/streaming/stream-probe.service.js +12 -16
- package/dist/core/streaming/ttl-cache.js +1 -5
- package/dist/core/topology/topology-emitter.service.js +19 -23
- package/dist/core/update-availability-emitter.js +3 -7
- package/dist/core/update-availability-store.js +8 -45
- package/dist/core/updates/agent-installed-packages.js +5 -9
- package/dist/core/updates/restart-marker.js +3 -8
- package/dist/core/updates/update-check-scheduler.js +13 -18
- package/dist/core/updates/wrapper-update-checker.js +3 -7
- package/dist/first-boot-addon-plan.js +2 -6
- package/dist/framework-nodepath.js +2 -38
- package/dist/i18n/request-lang.js +7 -11
- package/dist/launcher.js +30 -65
- package/dist/lifecycle-journal-path.js +2 -38
- package/dist/main.js +287 -324
- package/dist/manual-boot.js +120 -157
- package/dist/node-role.js +1 -4
- package/dist/package-inventory.js +7 -48
- package/dist/pending-restore.js +7 -43
- package/dist/single-copy-cleanup-runner.js +9 -45
- package/dist/single-copy-cleanup.js +7 -15
- package/dist/sqlite-restore.js +9 -48
- package/dist/starter.js +4 -39
- package/dist/ui-serving/lazy-ui-serving.js +3 -39
- package/package.json +13 -13
|
@@ -1,69 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.AddonPackageService = exports.FRAMEWORK_PACKAGES = exports.AUTO_UPDATE_EXCLUDED_PACKAGES = exports.SYSTEM_PACKAGE = void 0;
|
|
37
|
-
exports.isVersionNewer = isVersionNewer;
|
|
38
|
-
exports.isFrameworkPackage = isFrameworkPackage;
|
|
39
|
-
exports.extractTgzStripped = extractTgzStripped;
|
|
40
|
-
const types_1 = require("@camstack/types");
|
|
41
|
-
const node_child_process_1 = require("node:child_process");
|
|
42
|
-
const node_crypto_1 = require("node:crypto");
|
|
43
|
-
const fs = __importStar(require("node:fs"));
|
|
44
|
-
const os = __importStar(require("node:os"));
|
|
45
|
-
const path = __importStar(require("node:path"));
|
|
46
|
-
const node_util_1 = require("node:util");
|
|
47
|
-
const system_1 = require("@camstack/system");
|
|
48
|
-
const types_2 = require("@camstack/types");
|
|
49
|
-
const update_availability_emitter_js_1 = require("../update-availability-emitter.js");
|
|
50
|
-
const update_check_scheduler_js_1 = require("../updates/update-check-scheduler.js");
|
|
51
|
-
const restart_marker_js_1 = require("../updates/restart-marker.js");
|
|
52
|
-
const package_dir_utils_js_1 = require("./package-dir-utils.js");
|
|
53
|
-
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
1
|
+
import { userError } from '@camstack/types';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as os from 'node:os';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
import { AddonInstaller, detectWorkspacePackagesDir, ensureDir, scheduleSelfRestart, writePendingRestart, } from '@camstack/system';
|
|
9
|
+
import { EventCategory, errMsg } from '@camstack/types';
|
|
10
|
+
import { UpdateAvailabilityEmitter } from '../update-availability-emitter.js';
|
|
11
|
+
import { clampUpdateCheckInterval, DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS, } from '../updates/update-check-scheduler.js';
|
|
12
|
+
import { buildRestartMarker } from '../updates/restart-marker.js';
|
|
13
|
+
import { computeDistBuildId, resolveHubClosurePackageDir } from './package-dir-utils.js';
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
54
15
|
/**
|
|
55
16
|
* The primary host-provided framework package (kernel + core). Kept as a named
|
|
56
17
|
* export because `lifecycle-job-runner` + several tests reference it directly.
|
|
57
18
|
*/
|
|
58
|
-
|
|
19
|
+
export const SYSTEM_PACKAGE = '@camstack/system';
|
|
59
20
|
/**
|
|
60
21
|
* Packages the npm auto-updater must NEVER touch: the framework/system tier
|
|
61
22
|
* ships exclusively via `applyServerUpdate` (single-copy collapse). Listed
|
|
62
23
|
* explicitly (not via a manifest flag) because the updater runs against
|
|
63
24
|
* `listInstalled()` package names before any manifest is loaded.
|
|
64
25
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
26
|
+
export const AUTO_UPDATE_EXCLUDED_PACKAGES = new Set([
|
|
27
|
+
SYSTEM_PACKAGE,
|
|
67
28
|
'@camstack/types',
|
|
68
29
|
'@camstack/kernel',
|
|
69
30
|
'@camstack/core',
|
|
@@ -79,7 +40,7 @@ exports.AUTO_UPDATE_EXCLUDED_PACKAGES = new Set([
|
|
|
79
40
|
* 1.2.6); when both carry prereleases they compare lexicographically.
|
|
80
41
|
* Unparseable versions are never "newer" (fail safe: no update).
|
|
81
42
|
*/
|
|
82
|
-
function isVersionNewer(target, current) {
|
|
43
|
+
export function isVersionNewer(target, current) {
|
|
83
44
|
const parse = (v) => {
|
|
84
45
|
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(v.trim());
|
|
85
46
|
if (!m)
|
|
@@ -120,8 +81,8 @@ function isVersionNewer(target, current) {
|
|
|
120
81
|
* flag (`@camstack/types` declares `system: false` yet is a framework package
|
|
121
82
|
* here) — that flag drives Admin-UI grouping; this gate drives upload routing.
|
|
122
83
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
84
|
+
export const FRAMEWORK_PACKAGES = [
|
|
85
|
+
SYSTEM_PACKAGE,
|
|
125
86
|
'@camstack/types',
|
|
126
87
|
'@camstack/sdk',
|
|
127
88
|
];
|
|
@@ -129,8 +90,8 @@ exports.FRAMEWORK_PACKAGES = [
|
|
|
129
90
|
* Returns true for a host-provided framework package (special-cased by the
|
|
130
91
|
* addon-upload route — never installed as a normal addon).
|
|
131
92
|
*/
|
|
132
|
-
function isFrameworkPackage(packageName) {
|
|
133
|
-
return
|
|
93
|
+
export function isFrameworkPackage(packageName) {
|
|
94
|
+
return FRAMEWORK_PACKAGES.includes(packageName);
|
|
134
95
|
}
|
|
135
96
|
// ---------------------------------------------------------------------------
|
|
136
97
|
// Typed JSON helpers
|
|
@@ -177,7 +138,7 @@ function asRecord(value) {
|
|
|
177
138
|
// ---------------------------------------------------------------------------
|
|
178
139
|
/** Core packages that live in the server's own node_modules */
|
|
179
140
|
const CORE_MANAGED_PACKAGES = ['@camstack/system', '@camstack/types'];
|
|
180
|
-
class AddonPackageService {
|
|
141
|
+
export class AddonPackageService {
|
|
181
142
|
loggingService;
|
|
182
143
|
eventBusService;
|
|
183
144
|
configService;
|
|
@@ -200,7 +161,7 @@ class AddonPackageService {
|
|
|
200
161
|
global: {
|
|
201
162
|
channel: 'off',
|
|
202
163
|
intervalSeconds: 21600,
|
|
203
|
-
updateCheckIntervalSeconds:
|
|
164
|
+
updateCheckIntervalSeconds: DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS,
|
|
204
165
|
},
|
|
205
166
|
overrides: {},
|
|
206
167
|
};
|
|
@@ -236,12 +197,12 @@ class AddonPackageService {
|
|
|
236
197
|
this.notificationService = notificationService;
|
|
237
198
|
this.toastService = toastService;
|
|
238
199
|
this.logger = this.loggingService.createLogger('AddonPackageService');
|
|
239
|
-
this.updateAvailability = new
|
|
200
|
+
this.updateAvailability = new UpdateAvailabilityEmitter(this.eventBusService, { type: 'core', id: 'addon-package-service' }, updateAvailabilityStore);
|
|
240
201
|
// Initialize installer eagerly (no async needed).
|
|
241
202
|
// Ensures install/uninstall works before full module init completes.
|
|
242
203
|
try {
|
|
243
204
|
const addonsDir = this.resolveAddonsDir();
|
|
244
|
-
const workspacePackagesDir =
|
|
205
|
+
const workspacePackagesDir = detectWorkspacePackagesDir(__dirname);
|
|
245
206
|
// `CAMSTACK_NPM_REGISTRY` override exists primarily for the e2e
|
|
246
207
|
// harness — it points the installer at a sandboxed verdaccio so
|
|
247
208
|
// the CLI-vs-npm version-interaction tests don't hit the public
|
|
@@ -250,15 +211,15 @@ class AddonPackageService {
|
|
|
250
211
|
// AddonInstaller). Both the `npm install` shell-out AND the
|
|
251
212
|
// metadata HTTPS fetch honour this value.
|
|
252
213
|
const registry = process.env['CAMSTACK_NPM_REGISTRY'];
|
|
253
|
-
this.installer = new
|
|
214
|
+
this.installer = new AddonInstaller({
|
|
254
215
|
addonsDir,
|
|
255
216
|
workspacePackagesDir: workspacePackagesDir ?? undefined,
|
|
256
217
|
...(registry ? { registry } : {}),
|
|
257
218
|
});
|
|
258
|
-
|
|
219
|
+
ensureDir(addonsDir);
|
|
259
220
|
}
|
|
260
221
|
catch (error) {
|
|
261
|
-
const msg =
|
|
222
|
+
const msg = errMsg(error);
|
|
262
223
|
this.logger.warn('Installer init failed', { meta: { error: msg } });
|
|
263
224
|
}
|
|
264
225
|
// Load auto-update config from disk
|
|
@@ -302,7 +263,7 @@ class AddonPackageService {
|
|
|
302
263
|
}
|
|
303
264
|
catch (err) {
|
|
304
265
|
this.logger.debug('Non-fatal: failed to write .install-source marker', {
|
|
305
|
-
meta: { error:
|
|
266
|
+
meta: { error: errMsg(err) },
|
|
306
267
|
});
|
|
307
268
|
}
|
|
308
269
|
this.installer.manifest.upsert(result.name, {
|
|
@@ -327,9 +288,9 @@ class AddonPackageService {
|
|
|
327
288
|
async rollbackPackage(name) {
|
|
328
289
|
this.requireInstaller();
|
|
329
290
|
if (!this.isAllowedPackage(name)) {
|
|
330
|
-
throw
|
|
291
|
+
throw userError('server.package-not-allowed', { name: String(name) }, `Package "${name}" is not an allowed @camstack/* package`);
|
|
331
292
|
}
|
|
332
|
-
if (
|
|
293
|
+
if (AUTO_UPDATE_EXCLUDED_PACKAGES.has(name)) {
|
|
333
294
|
throw new Error(`"${name}" is a framework package — roll it back via serverManagement, not the addon-package path`);
|
|
334
295
|
}
|
|
335
296
|
const previousVersion = this.getInstalledPackageVersion(name);
|
|
@@ -358,7 +319,7 @@ class AddonPackageService {
|
|
|
358
319
|
}
|
|
359
320
|
catch (reloadError) {
|
|
360
321
|
this.logger.warn('Restart failed after rollback', {
|
|
361
|
-
meta: { name, error:
|
|
322
|
+
meta: { name, error: errMsg(reloadError) },
|
|
362
323
|
});
|
|
363
324
|
}
|
|
364
325
|
// Clear update cache so the UI reflects the new state.
|
|
@@ -369,7 +330,7 @@ class AddonPackageService {
|
|
|
369
330
|
async uninstall(name) {
|
|
370
331
|
this.requireInstaller();
|
|
371
332
|
if (this.isProtected(name)) {
|
|
372
|
-
throw
|
|
333
|
+
throw userError('server.package-protected', { name: String(name) }, `Cannot uninstall protected package "${name}"`);
|
|
373
334
|
}
|
|
374
335
|
await this.installer.uninstall(name);
|
|
375
336
|
this.logger.info('Uninstalled', { meta: { name } });
|
|
@@ -396,7 +357,7 @@ class AddonPackageService {
|
|
|
396
357
|
});
|
|
397
358
|
}
|
|
398
359
|
catch (err) {
|
|
399
|
-
const msg =
|
|
360
|
+
const msg = errMsg(err);
|
|
400
361
|
this.logger.error('npm install failed', { meta: { packageName, error: msg } });
|
|
401
362
|
this.toastService.broadcast({
|
|
402
363
|
title: 'Install Failed',
|
|
@@ -409,7 +370,7 @@ class AddonPackageService {
|
|
|
409
370
|
await this.reloadPackages();
|
|
410
371
|
}
|
|
411
372
|
catch (err) {
|
|
412
|
-
const msg =
|
|
373
|
+
const msg = errMsg(err);
|
|
413
374
|
this.logger.error('reloadPackages failed', { meta: { error: msg } });
|
|
414
375
|
}
|
|
415
376
|
let loaded = [];
|
|
@@ -420,7 +381,7 @@ class AddonPackageService {
|
|
|
420
381
|
failed = result.failed;
|
|
421
382
|
}
|
|
422
383
|
catch (err) {
|
|
423
|
-
const msg =
|
|
384
|
+
const msg = errMsg(err);
|
|
424
385
|
this.logger.error('loadNewAddons failed', { meta: { error: msg } });
|
|
425
386
|
failed.push(packageName);
|
|
426
387
|
}
|
|
@@ -447,7 +408,7 @@ class AddonPackageService {
|
|
|
447
408
|
});
|
|
448
409
|
}
|
|
449
410
|
catch (err) {
|
|
450
|
-
const msg =
|
|
411
|
+
const msg = errMsg(err);
|
|
451
412
|
this.logger.error('Workspace install failed', { meta: { error: msg } });
|
|
452
413
|
this.toastService.broadcast({ title: 'Install Failed', message: msg, severity: 'warning' });
|
|
453
414
|
throw new Error(`Workspace install failed: ${msg}`, { cause: err });
|
|
@@ -457,7 +418,7 @@ class AddonPackageService {
|
|
|
457
418
|
}
|
|
458
419
|
catch (err) {
|
|
459
420
|
this.logger.warn('Non-fatal: failed to reload packages after workspace install', {
|
|
460
|
-
meta: { error:
|
|
421
|
+
meta: { error: errMsg(err) },
|
|
461
422
|
});
|
|
462
423
|
}
|
|
463
424
|
let loaded = [];
|
|
@@ -468,7 +429,7 @@ class AddonPackageService {
|
|
|
468
429
|
failed = result.failed;
|
|
469
430
|
}
|
|
470
431
|
catch (err) {
|
|
471
|
-
this.logger.warn('Failed to load new addons after install', { meta: { error:
|
|
432
|
+
this.logger.warn('Failed to load new addons after install', { meta: { error: errMsg(err) } });
|
|
472
433
|
failed.push(packageName);
|
|
473
434
|
}
|
|
474
435
|
this.toastService.broadcast({
|
|
@@ -488,7 +449,7 @@ class AddonPackageService {
|
|
|
488
449
|
*/
|
|
489
450
|
async uninstallAndReload(packageName) {
|
|
490
451
|
if (this.isProtected(packageName)) {
|
|
491
|
-
throw
|
|
452
|
+
throw userError('server.package-required', { packageName: String(packageName) }, `Package ${packageName} is required and cannot be uninstalled`);
|
|
492
453
|
}
|
|
493
454
|
try {
|
|
494
455
|
this.addonRegistry.emitUninstallEvent(packageName);
|
|
@@ -497,19 +458,19 @@ class AddonPackageService {
|
|
|
497
458
|
this.logger.info('Uninstall complete', { meta: { packageName } });
|
|
498
459
|
}
|
|
499
460
|
catch (err) {
|
|
500
|
-
const msg =
|
|
461
|
+
const msg = errMsg(err);
|
|
501
462
|
this.logger.error('Uninstall failed', { meta: { packageName, error: msg } });
|
|
502
463
|
this.toastService.broadcast({ title: 'Uninstall Failed', message: msg, severity: 'warning' });
|
|
503
464
|
throw new Error(`Uninstall failed: ${msg}`, { cause: err });
|
|
504
465
|
}
|
|
505
466
|
await this.reloadPackages().catch((err) => {
|
|
506
467
|
this.logger.warn('Non-fatal: failed to reload packages after uninstall', {
|
|
507
|
-
meta: { error:
|
|
468
|
+
meta: { error: errMsg(err) },
|
|
508
469
|
});
|
|
509
470
|
});
|
|
510
471
|
await this.addonRegistry.loadNewAddons().catch((err) => {
|
|
511
472
|
this.logger.warn('Non-fatal: failed to load new addons after uninstall', {
|
|
512
|
-
meta: { error:
|
|
473
|
+
meta: { error: errMsg(err) },
|
|
513
474
|
});
|
|
514
475
|
});
|
|
515
476
|
this.toastService.broadcast({
|
|
@@ -559,7 +520,7 @@ class AddonPackageService {
|
|
|
559
520
|
}
|
|
560
521
|
}
|
|
561
522
|
catch (err) {
|
|
562
|
-
this.logger.warn('Failed to read workspace directory', { meta: { error:
|
|
523
|
+
this.logger.warn('Failed to read workspace directory', { meta: { error: errMsg(err) } });
|
|
563
524
|
}
|
|
564
525
|
return results;
|
|
565
526
|
}
|
|
@@ -590,7 +551,7 @@ class AddonPackageService {
|
|
|
590
551
|
const fromRegistry = this.addonRegistry?.isPackageProtected?.(name);
|
|
591
552
|
if (typeof fromRegistry === 'boolean')
|
|
592
553
|
return fromRegistry;
|
|
593
|
-
return
|
|
554
|
+
return AddonInstaller.REQUIRED_PACKAGES.includes(name);
|
|
594
555
|
}
|
|
595
556
|
/**
|
|
596
557
|
* Set of package names with a pending pre-update backup on disk —
|
|
@@ -679,7 +640,7 @@ class AddonPackageService {
|
|
|
679
640
|
// Never OFFER a framework package as an addon update: clicking it would
|
|
680
641
|
// route to `updatePackage`, which now refuses it anyway. Filtering here
|
|
681
642
|
// keeps the UI honest (no dead "Update" button for @camstack/server).
|
|
682
|
-
if (
|
|
643
|
+
if (AUTO_UPDATE_EXCLUDED_PACKAGES.has(name))
|
|
683
644
|
return;
|
|
684
645
|
const lookup = await this.lookupLatestVersion(name);
|
|
685
646
|
if (!lookup.ok) {
|
|
@@ -946,7 +907,7 @@ class AddonPackageService {
|
|
|
946
907
|
return result;
|
|
947
908
|
}
|
|
948
909
|
catch (error) {
|
|
949
|
-
const msg =
|
|
910
|
+
const msg = errMsg(error);
|
|
950
911
|
this.logger.warn('Failed to fetch versions', { meta: { name, error: msg } });
|
|
951
912
|
return cached?.versions ?? [];
|
|
952
913
|
}
|
|
@@ -985,7 +946,7 @@ class AddonPackageService {
|
|
|
985
946
|
}
|
|
986
947
|
catch (err) {
|
|
987
948
|
this.logger.warn('Post-update confirmation failed — backup retained for rollback', {
|
|
988
|
-
meta: { name, backupDir, error:
|
|
949
|
+
meta: { name, backupDir, error: errMsg(err) },
|
|
989
950
|
});
|
|
990
951
|
}
|
|
991
952
|
}
|
|
@@ -1062,7 +1023,7 @@ class AddonPackageService {
|
|
|
1062
1023
|
// hub/node_modules/@camstack/ — addons resolve everything from
|
|
1063
1024
|
// their own inlined deps.
|
|
1064
1025
|
const addonsDir = this.resolveAddonsDir();
|
|
1065
|
-
const { installPackageFromNpm } = await
|
|
1026
|
+
const { installPackageFromNpm } = await import('@camstack/system');
|
|
1066
1027
|
const dirName = name.replace(/^@camstack\//, '');
|
|
1067
1028
|
const targetDir = path.join(addonsDir, dirName);
|
|
1068
1029
|
const packageSpec = version ? `${name}@${version}` : name;
|
|
@@ -1080,7 +1041,7 @@ class AddonPackageService {
|
|
|
1080
1041
|
return { success: true, version: updatedVersion, requiresRestart: true };
|
|
1081
1042
|
}
|
|
1082
1043
|
catch (error) {
|
|
1083
|
-
const msg =
|
|
1044
|
+
const msg = errMsg(error);
|
|
1084
1045
|
this.logger.error('Failed to update package', { meta: { name, error: msg } });
|
|
1085
1046
|
return { success: false, version: '', requiresRestart: false, error: msg };
|
|
1086
1047
|
}
|
|
@@ -1138,7 +1099,7 @@ class AddonPackageService {
|
|
|
1138
1099
|
return { success: true, version: updatedVersion, requiresRestart: false };
|
|
1139
1100
|
}
|
|
1140
1101
|
catch (error) {
|
|
1141
|
-
const msg =
|
|
1102
|
+
const msg = errMsg(error);
|
|
1142
1103
|
this.logger.error('Failed to apply staged addon update', { meta: { name, error: msg } });
|
|
1143
1104
|
return { success: false, version: '', requiresRestart: false, error: msg };
|
|
1144
1105
|
}
|
|
@@ -1211,25 +1172,25 @@ class AddonPackageService {
|
|
|
1211
1172
|
restartServer(requestedBy, update) {
|
|
1212
1173
|
this.logger.info('Server restart requested -- initiating graceful shutdown');
|
|
1213
1174
|
// Both versions, one builder, shared with the agent — see `restart-marker.ts`.
|
|
1214
|
-
const payload =
|
|
1175
|
+
const payload = buildRestartMarker({
|
|
1215
1176
|
requestedAt: Date.now(),
|
|
1216
1177
|
...(requestedBy !== undefined ? { requestedBy } : {}),
|
|
1217
1178
|
...(update !== undefined ? { update } : {}),
|
|
1218
1179
|
});
|
|
1219
1180
|
try {
|
|
1220
|
-
|
|
1181
|
+
writePendingRestart(this.resolveDataDir(), payload);
|
|
1221
1182
|
}
|
|
1222
1183
|
catch (err) {
|
|
1223
1184
|
// Marker write failure shouldn't block the restart — log + continue.
|
|
1224
1185
|
this.logger.warn('Failed to write restart marker; restart will proceed without completion toast', {
|
|
1225
|
-
meta: { error:
|
|
1186
|
+
meta: { error: errMsg(err) },
|
|
1226
1187
|
});
|
|
1227
1188
|
}
|
|
1228
1189
|
this.eventBusService.emit({
|
|
1229
|
-
id:
|
|
1190
|
+
id: randomUUID(),
|
|
1230
1191
|
timestamp: new Date(),
|
|
1231
1192
|
source: { type: 'core', id: 'addon-package-service' },
|
|
1232
|
-
category:
|
|
1193
|
+
category: EventCategory.SystemRestarting,
|
|
1233
1194
|
// The node, as `system.restart-completed` names it after the boot
|
|
1234
1195
|
// (`post-boot.service.ts`): the announcement and the landing of one
|
|
1235
1196
|
// restart must name the same node, or a stale `node-updating` could not
|
|
@@ -1237,7 +1198,7 @@ class AddonPackageService {
|
|
|
1237
1198
|
data: { ...payload, nodeId: process.env['CAMSTACK_NODE_ID'] ?? 'hub' },
|
|
1238
1199
|
});
|
|
1239
1200
|
// 10s grace gives in-flight requests time to drain.
|
|
1240
|
-
|
|
1201
|
+
scheduleSelfRestart({ delayMs: 10_000 });
|
|
1241
1202
|
}
|
|
1242
1203
|
// =========================================================================
|
|
1243
1204
|
// Framework live-update
|
|
@@ -1256,7 +1217,7 @@ class AddonPackageService {
|
|
|
1256
1217
|
*/
|
|
1257
1218
|
async listFrameworkPackages() {
|
|
1258
1219
|
const registry = process.env['CAMSTACK_NPM_REGISTRY'];
|
|
1259
|
-
const rows = await Promise.all([
|
|
1220
|
+
const rows = await Promise.all([SYSTEM_PACKAGE].map(async (packageName) => {
|
|
1260
1221
|
const manifest = readResolvedPackageManifest(packageName);
|
|
1261
1222
|
const currentVersion = manifest !== null && typeof manifest['version'] === 'string'
|
|
1262
1223
|
? manifest['version']
|
|
@@ -1267,8 +1228,8 @@ class AddonPackageService {
|
|
|
1267
1228
|
// Content build-id of the code the hub ACTUALLY loaded — resolved from
|
|
1268
1229
|
// the same closure the running process uses. Surfaces "same semver,
|
|
1269
1230
|
// new code" (framework packages ship changes without always bumping).
|
|
1270
|
-
const hubPkgDir =
|
|
1271
|
-
const buildId = hubPkgDir !== null ?
|
|
1231
|
+
const hubPkgDir = resolveHubClosurePackageDir(packageName);
|
|
1232
|
+
const buildId = hubPkgDir !== null ? computeDistBuildId(path.join(hubPkgDir, 'dist')) : null;
|
|
1272
1233
|
let latestVersion = null;
|
|
1273
1234
|
let lookupFailed = false;
|
|
1274
1235
|
try {
|
|
@@ -1285,7 +1246,7 @@ class AddonPackageService {
|
|
|
1285
1246
|
catch (err) {
|
|
1286
1247
|
lookupFailed = true;
|
|
1287
1248
|
this.logger.debug('listFrameworkPackages: npm view failed', {
|
|
1288
|
-
meta: { packageName, error:
|
|
1249
|
+
meta: { packageName, error: errMsg(err) },
|
|
1289
1250
|
});
|
|
1290
1251
|
}
|
|
1291
1252
|
// STRICTLY newer, never merely different. The hub runs
|
|
@@ -1357,14 +1318,14 @@ class AddonPackageService {
|
|
|
1357
1318
|
/** Re-discover addons from the addons directory (call after install/uninstall) */
|
|
1358
1319
|
async reloadPackages() {
|
|
1359
1320
|
try {
|
|
1360
|
-
const kernel = await
|
|
1321
|
+
const kernel = await import('@camstack/system');
|
|
1361
1322
|
this.loader = new kernel.AddonLoader(this.logger.child('AddonLoader'));
|
|
1362
1323
|
const addonsDir = this.resolveAddonsDir();
|
|
1363
1324
|
await this.loader.loadFromDirectory(addonsDir);
|
|
1364
1325
|
this.logger.info('Reloaded', { meta: { count: this.loader.listAddons().length } });
|
|
1365
1326
|
}
|
|
1366
1327
|
catch (error) {
|
|
1367
|
-
const msg =
|
|
1328
|
+
const msg = errMsg(error);
|
|
1368
1329
|
this.logger.warn('reloadPackages failed', { meta: { error: msg } });
|
|
1369
1330
|
}
|
|
1370
1331
|
}
|
|
@@ -1398,7 +1359,7 @@ class AddonPackageService {
|
|
|
1398
1359
|
const previousCheckInterval = this.autoUpdateConfig.global.updateCheckIntervalSeconds;
|
|
1399
1360
|
const nextCheckInterval = updateCheckIntervalSeconds === undefined
|
|
1400
1361
|
? previousCheckInterval
|
|
1401
|
-
:
|
|
1362
|
+
: clampUpdateCheckInterval(updateCheckIntervalSeconds);
|
|
1402
1363
|
this.autoUpdateConfig = {
|
|
1403
1364
|
...this.autoUpdateConfig,
|
|
1404
1365
|
global: {
|
|
@@ -1452,7 +1413,7 @@ class AddonPackageService {
|
|
|
1452
1413
|
});
|
|
1453
1414
|
this.autoUpdateTimer = setInterval(() => {
|
|
1454
1415
|
this.runAutoUpdate().catch((err) => {
|
|
1455
|
-
this.logger.error('Auto-update check failed', { meta: { error:
|
|
1416
|
+
this.logger.error('Auto-update check failed', { meta: { error: errMsg(err) } });
|
|
1456
1417
|
});
|
|
1457
1418
|
}, intervalMs);
|
|
1458
1419
|
}
|
|
@@ -1482,7 +1443,7 @@ class AddonPackageService {
|
|
|
1482
1443
|
// skipped a swept framework target; excluding it here also kills the
|
|
1483
1444
|
// useless candidate churn that participated in the 2026-07-22 hub
|
|
1484
1445
|
// wedge (mass staged swap right after a publish train).
|
|
1485
|
-
if (
|
|
1446
|
+
if (AUTO_UPDATE_EXCLUDED_PACKAGES.has(pkg.name))
|
|
1486
1447
|
continue;
|
|
1487
1448
|
// Determine effective channel for this addon
|
|
1488
1449
|
const addonId = pkg.name.replace('@camstack/addon-', '').replace('@camstack/', '');
|
|
@@ -1530,7 +1491,7 @@ class AddonPackageService {
|
|
|
1530
1491
|
}
|
|
1531
1492
|
catch (err) {
|
|
1532
1493
|
this.logger.warn('Auto-update check failed', {
|
|
1533
|
-
meta: { name: pkg.name, error:
|
|
1494
|
+
meta: { name: pkg.name, error: errMsg(err) },
|
|
1534
1495
|
});
|
|
1535
1496
|
}
|
|
1536
1497
|
}
|
|
@@ -1547,7 +1508,7 @@ class AddonPackageService {
|
|
|
1547
1508
|
// ship via applyServerUpdate). Wrap so a failure is logged, not thrown out
|
|
1548
1509
|
// of the timer callback.
|
|
1549
1510
|
try {
|
|
1550
|
-
const { getLifecycleRunner } = await
|
|
1511
|
+
const { getLifecycleRunner } = await import('../lifecycle/lifecycle-runner.singleton.js');
|
|
1551
1512
|
const runner = getLifecycleRunner();
|
|
1552
1513
|
const { jobId } = await runner.startJob({ kind: 'update', targets, createdBy: 'system' });
|
|
1553
1514
|
this.logger.info('Auto-update job started', {
|
|
@@ -1555,7 +1516,7 @@ class AddonPackageService {
|
|
|
1555
1516
|
});
|
|
1556
1517
|
}
|
|
1557
1518
|
catch (err) {
|
|
1558
|
-
this.logger.error('Auto-update job failed to start', { meta: { error:
|
|
1519
|
+
this.logger.error('Auto-update job failed to start', { meta: { error: errMsg(err) } });
|
|
1559
1520
|
}
|
|
1560
1521
|
}
|
|
1561
1522
|
// =========================================================================
|
|
@@ -1577,8 +1538,8 @@ class AddonPackageService {
|
|
|
1577
1538
|
channel: validChannel,
|
|
1578
1539
|
intervalSeconds: typeof global['intervalSeconds'] === 'number' ? global['intervalSeconds'] : 3600,
|
|
1579
1540
|
updateCheckIntervalSeconds: typeof rawCheckInterval === 'number'
|
|
1580
|
-
?
|
|
1581
|
-
:
|
|
1541
|
+
? clampUpdateCheckInterval(rawCheckInterval)
|
|
1542
|
+
: DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS,
|
|
1582
1543
|
},
|
|
1583
1544
|
overrides: Object.fromEntries(Object.entries(asRecord(raw['overrides'])).map(([k, v]) => {
|
|
1584
1545
|
const s = asString(v);
|
|
@@ -1591,14 +1552,14 @@ class AddonPackageService {
|
|
|
1591
1552
|
}
|
|
1592
1553
|
catch (err) {
|
|
1593
1554
|
this.logger.debug('Corrupt auto-update config, falling back to defaults', {
|
|
1594
|
-
meta: { error:
|
|
1555
|
+
meta: { error: errMsg(err) },
|
|
1595
1556
|
});
|
|
1596
1557
|
}
|
|
1597
1558
|
return {
|
|
1598
1559
|
global: {
|
|
1599
1560
|
channel: 'off',
|
|
1600
1561
|
intervalSeconds: 21600,
|
|
1601
|
-
updateCheckIntervalSeconds:
|
|
1562
|
+
updateCheckIntervalSeconds: DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS,
|
|
1602
1563
|
},
|
|
1603
1564
|
overrides: {},
|
|
1604
1565
|
};
|
|
@@ -1614,7 +1575,7 @@ class AddonPackageService {
|
|
|
1614
1575
|
fs.writeFileSync(configPath, JSON.stringify(this.autoUpdateConfig, null, 2));
|
|
1615
1576
|
}
|
|
1616
1577
|
catch (err) {
|
|
1617
|
-
this.logger.warn('Failed to save auto-update config', { meta: { error:
|
|
1578
|
+
this.logger.warn('Failed to save auto-update config', { meta: { error: errMsg(err) } });
|
|
1618
1579
|
}
|
|
1619
1580
|
}
|
|
1620
1581
|
/** Resolve the top-level data directory */
|
|
@@ -1709,7 +1670,7 @@ class AddonPackageService {
|
|
|
1709
1670
|
// The package could not be evaluated at all (unreadable manifest, …).
|
|
1710
1671
|
// Counted as a failure for the same reason a registry miss is.
|
|
1711
1672
|
failures += 1;
|
|
1712
|
-
const msg =
|
|
1673
|
+
const msg = errMsg(error);
|
|
1713
1674
|
this.logger.warn('Failed to check updates for addon', {
|
|
1714
1675
|
meta: { pkgJsonPath, error: msg },
|
|
1715
1676
|
});
|
|
@@ -1762,7 +1723,7 @@ class AddonPackageService {
|
|
|
1762
1723
|
return { ok: true, latestVersion: version || null };
|
|
1763
1724
|
}
|
|
1764
1725
|
catch (error) {
|
|
1765
|
-
return { ok: false, error:
|
|
1726
|
+
return { ok: false, error: errMsg(error) };
|
|
1766
1727
|
}
|
|
1767
1728
|
}
|
|
1768
1729
|
/**
|
|
@@ -1835,7 +1796,7 @@ class AddonPackageService {
|
|
|
1835
1796
|
return results;
|
|
1836
1797
|
}
|
|
1837
1798
|
catch (err) {
|
|
1838
|
-
this.logger.warn('npm search failed', { meta: { error:
|
|
1799
|
+
this.logger.warn('npm search failed', { meta: { error: errMsg(err) } });
|
|
1839
1800
|
// Stale cache is better than nothing on transient network failure
|
|
1840
1801
|
return this.searchCache?.results ?? [];
|
|
1841
1802
|
}
|
|
@@ -1871,7 +1832,7 @@ class AddonPackageService {
|
|
|
1871
1832
|
}
|
|
1872
1833
|
catch (err) {
|
|
1873
1834
|
this.logger.debug('Installed-version lookup failed', {
|
|
1874
|
-
meta: { packageName, error:
|
|
1835
|
+
meta: { packageName, error: errMsg(err) },
|
|
1875
1836
|
});
|
|
1876
1837
|
}
|
|
1877
1838
|
this.logger.debug('No readable installed copy — previous version is unknown', {
|
|
@@ -1894,7 +1855,7 @@ class AddonPackageService {
|
|
|
1894
1855
|
* host mid-`applyServerUpdate` publish. A refusal, not a silent no-op.
|
|
1895
1856
|
*/
|
|
1896
1857
|
refuseExcludedFramework(name) {
|
|
1897
|
-
if (!
|
|
1858
|
+
if (!AUTO_UPDATE_EXCLUDED_PACKAGES.has(name))
|
|
1898
1859
|
return null;
|
|
1899
1860
|
return {
|
|
1900
1861
|
success: false,
|
|
@@ -1954,7 +1915,7 @@ class AddonPackageService {
|
|
|
1954
1915
|
timestamp: Date.now(),
|
|
1955
1916
|
})
|
|
1956
1917
|
.catch((err) => {
|
|
1957
|
-
const msg =
|
|
1918
|
+
const msg = errMsg(err);
|
|
1958
1919
|
this.logger.debug('Update notification failed', { meta: { error: msg } });
|
|
1959
1920
|
});
|
|
1960
1921
|
this.toastService.broadcast({
|
|
@@ -1965,7 +1926,6 @@ class AddonPackageService {
|
|
|
1965
1926
|
});
|
|
1966
1927
|
}
|
|
1967
1928
|
}
|
|
1968
|
-
exports.AddonPackageService = AddonPackageService;
|
|
1969
1929
|
// ---------------------------------------------------------------------------
|
|
1970
1930
|
// Tarball extraction helper (exported for regression tests)
|
|
1971
1931
|
// ---------------------------------------------------------------------------
|
|
@@ -1982,9 +1942,9 @@ exports.AddonPackageService = AddonPackageService;
|
|
|
1982
1942
|
* `src/core/addon/__tests__/extract-tarball-strip.spec.ts` can test the real
|
|
1983
1943
|
* implementation without instantiating `AddonPackageService`.
|
|
1984
1944
|
*/
|
|
1985
|
-
async function extractTgzStripped(tgz, destDir) {
|
|
1945
|
+
export async function extractTgzStripped(tgz, destDir) {
|
|
1986
1946
|
fs.mkdirSync(destDir, { recursive: true });
|
|
1987
|
-
const tmpFile = path.join(os.tmpdir(), `camstack-tgz-${
|
|
1947
|
+
const tmpFile = path.join(os.tmpdir(), `camstack-tgz-${randomUUID()}.tgz`);
|
|
1988
1948
|
try {
|
|
1989
1949
|
fs.writeFileSync(tmpFile, tgz);
|
|
1990
1950
|
await execFileAsync('tar', ['--strip-components=1', '-xzf', tmpFile, '-C', destDir], {
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NEVER_LOADED_PROCESS = void 0;
|
|
4
|
-
exports.describeAddonProcess = describeAddonProcess;
|
|
5
|
-
function describeAddonProcess(input) {
|
|
1
|
+
export function describeAddonProcess(input) {
|
|
6
2
|
if (!input.forked) {
|
|
7
3
|
// Hosted by hub-main itself: its state is hub-main's, which is running if this code is.
|
|
8
4
|
return input.initialized
|
|
@@ -25,4 +21,4 @@ function describeAddonProcess(input) {
|
|
|
25
21
|
* A package on disk that never loaded: there is no process, and the card must
|
|
26
22
|
* show the diagnostic state distinctly (`scanFailedToLoadPackages`).
|
|
27
23
|
*/
|
|
28
|
-
|
|
24
|
+
export const NEVER_LOADED_PROCESS = { mode: 'in-process', state: 'failed' };
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.planAddonRealignment = planAddonRealignment;
|
|
4
1
|
/** `a` strictly newer than `b`, by numeric segments, missing segments as 0. */
|
|
5
2
|
function isStrictlyNewer(a, b) {
|
|
6
3
|
const pa = a.split('.').map((p) => Number.parseInt(p, 10));
|
|
@@ -16,7 +13,7 @@ function isStrictlyNewer(a, b) {
|
|
|
16
13
|
}
|
|
17
14
|
return false;
|
|
18
15
|
}
|
|
19
|
-
function planAddonRealignment(candidates) {
|
|
16
|
+
export function planAddonRealignment(candidates) {
|
|
20
17
|
return candidates.map((c) => {
|
|
21
18
|
if (c.closureVersion === null) {
|
|
22
19
|
return { pkg: c.pkg, action: 'keep', reason: 'not carried by this closure' };
|