@camstack/server 1.2.592 → 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 +219 -221
- package/dist/api/trpc/generated-cap-routers.js +4878 -4726
- 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 +254 -197
- 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,39 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
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.registerServerUploadPropagateRoute = registerServerUploadPropagateRoute;
|
|
37
1
|
/**
|
|
38
2
|
* POST /api/server-upload/propagate — deliver an already-uploaded
|
|
39
3
|
* `dev-uploads/<version>/` set from the hub onto one agent, then leave
|
|
@@ -42,13 +6,13 @@ exports.registerServerUploadPropagateRoute = registerServerUploadPropagateRoute;
|
|
|
42
6
|
* Mirrors addon fan-out: pack the version dir → stage one-shot hub-http
|
|
43
7
|
* ticket → `$agent.stageDevUploads`. Does NOT promote the closure.
|
|
44
8
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import { AGENT_DEPLOY_CONTROL_TIMEOUT_MS, } from './agent-addon-delivery.js';
|
|
12
|
+
import { buildHubHttpSource } from './addon-upload.js';
|
|
13
|
+
import { isSafeDevUploadVersion, packDevUploadVersionDir } from './dev-uploads-bundle.js';
|
|
14
|
+
import { authorizeUploadRequest, } from './upload-auth.js';
|
|
15
|
+
import { devUploadVersionDir, readDevUploadManifest, serverRootDir } from '../server-root/index.js';
|
|
52
16
|
function isStageResponse(value) {
|
|
53
17
|
if (value === null || typeof value !== 'object')
|
|
54
18
|
return false;
|
|
@@ -70,7 +34,7 @@ function readBody(value) {
|
|
|
70
34
|
error: 'nodeId must be a top-level agent id (not "hub" and not a child runner id)',
|
|
71
35
|
};
|
|
72
36
|
}
|
|
73
|
-
if (!
|
|
37
|
+
if (!isSafeDevUploadVersion(body.version)) {
|
|
74
38
|
return {
|
|
75
39
|
error: `Refused: version "${body.version}" is not a safe dev-channel version ` +
|
|
76
40
|
'(expected `<base>-dev.<epochSeconds>`)',
|
|
@@ -78,10 +42,10 @@ function readBody(value) {
|
|
|
78
42
|
}
|
|
79
43
|
return { version: body.version, nodeId: body.nodeId };
|
|
80
44
|
}
|
|
81
|
-
function registerServerUploadPropagateRoute(fastify, options) {
|
|
45
|
+
export function registerServerUploadPropagateRoute(fastify, options) {
|
|
82
46
|
const { authService, addonRegistry, logger, broker, resolveClusterBaseUrl } = options;
|
|
83
47
|
fastify.post('/api/server-upload/propagate', async (request, reply) => {
|
|
84
|
-
const auth = await
|
|
48
|
+
const auth = await authorizeUploadRequest({
|
|
85
49
|
authHeader: request.headers.authorization,
|
|
86
50
|
authService,
|
|
87
51
|
addonRegistry,
|
|
@@ -95,14 +59,14 @@ function registerServerUploadPropagateRoute(fastify, options) {
|
|
|
95
59
|
}
|
|
96
60
|
const { version, nodeId } = parsed;
|
|
97
61
|
const dataDir = path.resolve(options.dataDir ?? process.env['CAMSTACK_DATA'] ?? 'camstack-data');
|
|
98
|
-
const versionDir =
|
|
62
|
+
const versionDir = devUploadVersionDir(serverRootDir(dataDir), version);
|
|
99
63
|
if (!fs.existsSync(versionDir)) {
|
|
100
64
|
return reply.status(404).send({
|
|
101
65
|
error: `No hub-side upload for ${version} at ${versionDir}. ` +
|
|
102
66
|
'Upload first with `camstack deploy-server` (POST /api/server-upload).',
|
|
103
67
|
});
|
|
104
68
|
}
|
|
105
|
-
const manifest =
|
|
69
|
+
const manifest = readDevUploadManifest(versionDir);
|
|
106
70
|
if (manifest === null) {
|
|
107
71
|
return reply.status(400).send({
|
|
108
72
|
error: `Hub upload for ${version} has a missing or invalid manifest.json`,
|
|
@@ -122,8 +86,8 @@ function registerServerUploadPropagateRoute(fastify, options) {
|
|
|
122
86
|
let bundle;
|
|
123
87
|
let source;
|
|
124
88
|
try {
|
|
125
|
-
bundle = await
|
|
126
|
-
source =
|
|
89
|
+
bundle = await packDevUploadVersionDir(versionDir);
|
|
90
|
+
source = buildHubHttpSource(bundle, hubBaseUrl);
|
|
127
91
|
}
|
|
128
92
|
catch (err) {
|
|
129
93
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -133,7 +97,7 @@ function registerServerUploadPropagateRoute(fastify, options) {
|
|
|
133
97
|
return reply.status(500).send({ error: `Failed to stage upload pack: ${message}` });
|
|
134
98
|
}
|
|
135
99
|
try {
|
|
136
|
-
const raw = await broker.call('$agent.stageDevUploads', { version, source }, { nodeID: nodeId, timeout:
|
|
100
|
+
const raw = await broker.call('$agent.stageDevUploads', { version, source }, { nodeID: nodeId, timeout: AGENT_DEPLOY_CONTROL_TIMEOUT_MS });
|
|
137
101
|
if (!isStageResponse(raw) || raw.success !== true) {
|
|
138
102
|
logger.warn('server-upload propagate: malformed agent response', {
|
|
139
103
|
meta: { version, nodeId },
|
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
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.validateTarballSet = validateTarballSet;
|
|
37
|
-
exports.registerServerUploadRoute = registerServerUploadRoute;
|
|
38
1
|
/**
|
|
39
2
|
* POST /api/server-upload — the dev server-deploy channel's upload gateway.
|
|
40
3
|
*
|
|
@@ -60,11 +23,11 @@ exports.registerServerUploadRoute = registerServerUploadRoute;
|
|
|
60
23
|
* the instance (done by `registerAddonUploadRoute`) — this route only adds
|
|
61
24
|
* the handler.
|
|
62
25
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
26
|
+
import * as fs from 'node:fs';
|
|
27
|
+
import * as path from 'node:path';
|
|
28
|
+
import { devUploadVersionDir, isDevChannelVersion, serverRootDir, writeDevUploadManifest, } from '../server-root/index.js';
|
|
29
|
+
import { isTarballFilename, readTarballManifest } from './tarball-manifest.js';
|
|
30
|
+
import { authorizeUploadRequest, } from './upload-auth.js';
|
|
68
31
|
/**
|
|
69
32
|
* Version chars beyond the dev-channel shape check: strictly semver-ish
|
|
70
33
|
* (alnum, dots, dashes) so the version can never traverse out of
|
|
@@ -91,17 +54,17 @@ function flattenedTgzName(packageName) {
|
|
|
91
54
|
* is derived server-side from the validated PACKAGE name — a client
|
|
92
55
|
* filename never becomes a filesystem path.
|
|
93
56
|
*/
|
|
94
|
-
function validateTarballSet(files, version) {
|
|
57
|
+
export function validateTarballSet(files, version) {
|
|
95
58
|
const seen = new Set();
|
|
96
59
|
const validated = [];
|
|
97
60
|
for (const file of files) {
|
|
98
61
|
if (hasPathTraversal(file.filename)) {
|
|
99
62
|
return { error: `Refused: filename contains path separators (${file.filename})` };
|
|
100
63
|
}
|
|
101
|
-
if (!
|
|
64
|
+
if (!isTarballFilename(file.filename)) {
|
|
102
65
|
return { error: `Refused: ${file.filename} is not a .tgz/.tar.gz archive` };
|
|
103
66
|
}
|
|
104
|
-
const manifest =
|
|
67
|
+
const manifest = readTarballManifest(file.buffer, file.filename);
|
|
105
68
|
if (manifest === null) {
|
|
106
69
|
return {
|
|
107
70
|
error: `Refused: ${file.filename} is missing or has a malformed package/package.json`,
|
|
@@ -126,10 +89,10 @@ function validateTarballSet(files, version) {
|
|
|
126
89
|
}
|
|
127
90
|
return validated;
|
|
128
91
|
}
|
|
129
|
-
function registerServerUploadRoute(fastify, options) {
|
|
92
|
+
export function registerServerUploadRoute(fastify, options) {
|
|
130
93
|
const { authService, addonRegistry, logger } = options;
|
|
131
94
|
fastify.post('/api/server-upload', async (request, reply) => {
|
|
132
|
-
const auth = await
|
|
95
|
+
const auth = await authorizeUploadRequest({
|
|
133
96
|
authHeader: request.headers.authorization,
|
|
134
97
|
authService,
|
|
135
98
|
addonRegistry,
|
|
@@ -152,7 +115,7 @@ function registerServerUploadRoute(fastify, options) {
|
|
|
152
115
|
if (version === null || version.length === 0) {
|
|
153
116
|
return reply.status(400).send({ error: 'Missing "version" field' });
|
|
154
117
|
}
|
|
155
|
-
if (!SAFE_VERSION_RE.test(version) || !
|
|
118
|
+
if (!SAFE_VERSION_RE.test(version) || !isDevChannelVersion(version)) {
|
|
156
119
|
return reply.status(400).send({
|
|
157
120
|
error: `Refused: version "${version}" is not dev-channel shaped — this route only ` +
|
|
158
121
|
'accepts `<base>-dev.<epochSeconds>` versions produced by `camstack deploy-server`.',
|
|
@@ -167,7 +130,7 @@ function registerServerUploadRoute(fastify, options) {
|
|
|
167
130
|
return reply.status(400).send({ error: validated.error });
|
|
168
131
|
}
|
|
169
132
|
const dataDir = path.resolve(options.dataDir ?? process.env['CAMSTACK_DATA'] ?? 'camstack-data');
|
|
170
|
-
const versionDir =
|
|
133
|
+
const versionDir = devUploadVersionDir(serverRootDir(dataDir), version);
|
|
171
134
|
fs.mkdirSync(versionDir, { recursive: true });
|
|
172
135
|
const packages = {};
|
|
173
136
|
for (const pkg of validated) {
|
|
@@ -175,7 +138,7 @@ function registerServerUploadRoute(fastify, options) {
|
|
|
175
138
|
fs.writeFileSync(path.join(versionDir, tgzName), pkg.buffer);
|
|
176
139
|
packages[pkg.name] = tgzName;
|
|
177
140
|
}
|
|
178
|
-
|
|
141
|
+
writeDevUploadManifest(versionDir, { version, packages });
|
|
179
142
|
logger.info('server-upload stored dev closure', {
|
|
180
143
|
meta: { version, packages: Object.keys(packages), dir: versionDir },
|
|
181
144
|
});
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.markSseRequestNoCompression = markSseRequestNoCompression;
|
|
4
1
|
/** Mutates the request headers in place; returns whether it marked the request. */
|
|
5
|
-
function markSseRequestNoCompression(request) {
|
|
2
|
+
export function markSseRequestNoCompression(request) {
|
|
6
3
|
const accept = request.headers.accept;
|
|
7
4
|
if (typeof accept === 'string' && accept.includes('text/event-stream')) {
|
|
8
5
|
request.headers['x-no-compression'] = '1';
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FRAME_ANCESTORS_POLICY = void 0;
|
|
4
|
-
exports.isFramePolicyTarget = isFramePolicyTarget;
|
|
5
|
-
exports.registerFramePolicy = registerFramePolicy;
|
|
6
1
|
/** The one directive: frame me from my origin only. */
|
|
7
|
-
|
|
2
|
+
export const FRAME_ANCESTORS_POLICY = "frame-ancestors 'self'";
|
|
8
3
|
const CSP_HEADER = 'content-security-policy';
|
|
9
4
|
/** Only a document can be framed; assets, JSON and streams are never one. */
|
|
10
|
-
function isFramePolicyTarget(contentType) {
|
|
5
|
+
export function isFramePolicyTarget(contentType) {
|
|
11
6
|
return typeof contentType === 'string' && contentType.trim().toLowerCase().startsWith('text/html');
|
|
12
7
|
}
|
|
13
8
|
/**
|
|
@@ -16,13 +11,13 @@ function isFramePolicyTarget(contentType) {
|
|
|
16
11
|
* reverse proxy's streaming path) are not seen here; they carry no HTML
|
|
17
12
|
* shell of ours.
|
|
18
13
|
*/
|
|
19
|
-
function registerFramePolicy(fastify) {
|
|
14
|
+
export function registerFramePolicy(fastify) {
|
|
20
15
|
fastify.addHook('onSend', async (_request, reply, payload) => {
|
|
21
16
|
if (!isFramePolicyTarget(reply.getHeader('content-type')))
|
|
22
17
|
return payload;
|
|
23
18
|
if (reply.getHeader(CSP_HEADER) !== undefined)
|
|
24
19
|
return payload;
|
|
25
|
-
reply.header(CSP_HEADER,
|
|
20
|
+
reply.header(CSP_HEADER, FRAME_ANCESTORS_POLICY);
|
|
26
21
|
return payload;
|
|
27
22
|
});
|
|
28
23
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Brotli-compressed copies of static SPA assets, cached on disk.
|
|
4
3
|
*
|
|
@@ -17,53 +16,12 @@
|
|
|
17
16
|
* The first request for a given file still pays the compression, exactly as
|
|
18
17
|
* every request does today. Every request after it pays nothing.
|
|
19
18
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Object.defineProperty(o, k2, desc);
|
|
27
|
-
}) : (function(o, m, k, k2) {
|
|
28
|
-
if (k2 === undefined) k2 = k;
|
|
29
|
-
o[k2] = m[k];
|
|
30
|
-
}));
|
|
31
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
-
}) : function(o, v) {
|
|
34
|
-
o["default"] = v;
|
|
35
|
-
});
|
|
36
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
-
var ownKeys = function(o) {
|
|
38
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
-
var ar = [];
|
|
40
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
-
return ar;
|
|
42
|
-
};
|
|
43
|
-
return ownKeys(o);
|
|
44
|
-
};
|
|
45
|
-
return function (mod) {
|
|
46
|
-
if (mod && mod.__esModule) return mod;
|
|
47
|
-
var result = {};
|
|
48
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
-
__setModuleDefault(result, mod);
|
|
50
|
-
return result;
|
|
51
|
-
};
|
|
52
|
-
})();
|
|
53
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
-
exports.acceptsBrotli = acceptsBrotli;
|
|
55
|
-
exports.isCompressibleAsset = isCompressibleAsset;
|
|
56
|
-
exports.resolvePrecompressedAsset = resolvePrecompressedAsset;
|
|
57
|
-
exports.warmPrecompressedAssets = warmPrecompressedAssets;
|
|
58
|
-
exports.resetPrecompressedWarning = resetPrecompressedWarning;
|
|
59
|
-
exports.precompressedTempPath = precompressedTempPath;
|
|
60
|
-
exports.precompressedSiblingExists = precompressedSiblingExists;
|
|
61
|
-
const fs = __importStar(require("node:fs"));
|
|
62
|
-
const fsp = __importStar(require("node:fs/promises"));
|
|
63
|
-
const path = __importStar(require("node:path"));
|
|
64
|
-
const node_zlib_1 = require("node:zlib");
|
|
65
|
-
const node_util_1 = require("node:util");
|
|
66
|
-
const brotli = (0, node_util_1.promisify)(node_zlib_1.brotliCompress);
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import * as fsp from 'node:fs/promises';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import { brotliCompress, constants as zlibConstants } from 'node:zlib';
|
|
23
|
+
import { promisify } from 'node:util';
|
|
24
|
+
const brotli = promisify(brotliCompress);
|
|
67
25
|
/** Below this, the framing costs more than the compression saves — the same
|
|
68
26
|
* threshold `@fastify/compress` is registered with. */
|
|
69
27
|
const MIN_BYTES = 1024;
|
|
@@ -77,12 +35,12 @@ const inFlight = new Map();
|
|
|
77
35
|
* error to repeat on every asset. */
|
|
78
36
|
let warnedUnwritable = false;
|
|
79
37
|
/** Does the client accept brotli? */
|
|
80
|
-
function acceptsBrotli(acceptEncoding) {
|
|
38
|
+
export function acceptsBrotli(acceptEncoding) {
|
|
81
39
|
if (acceptEncoding === undefined)
|
|
82
40
|
return false;
|
|
83
41
|
return /\bbr\b/.test(acceptEncoding);
|
|
84
42
|
}
|
|
85
|
-
function isCompressibleAsset(relOrAbs) {
|
|
43
|
+
export function isCompressibleAsset(relOrAbs) {
|
|
86
44
|
return COMPRESSIBLE.test(relOrAbs);
|
|
87
45
|
}
|
|
88
46
|
/**
|
|
@@ -108,8 +66,8 @@ async function compressToDisk(filePath, brPath, log) {
|
|
|
108
66
|
params: {
|
|
109
67
|
// Quality 11 is worth it BECAUSE this runs once. The per-request path
|
|
110
68
|
// could never afford it, which is why it was set to 4.
|
|
111
|
-
[
|
|
112
|
-
[
|
|
69
|
+
[zlibConstants.BROTLI_PARAM_QUALITY]: 11,
|
|
70
|
+
[zlibConstants.BROTLI_PARAM_SIZE_HINT]: raw.byteLength,
|
|
113
71
|
},
|
|
114
72
|
});
|
|
115
73
|
// Write via a temp file + rename so a concurrent reader never sees a
|
|
@@ -142,7 +100,7 @@ async function compressToDisk(filePath, brPath, log) {
|
|
|
142
100
|
* cache could not be written. The caller then serves exactly what it served
|
|
143
101
|
* before, so this can only ever be an optimisation.
|
|
144
102
|
*/
|
|
145
|
-
async function resolvePrecompressedAsset(filePath, acceptEncoding, log) {
|
|
103
|
+
export async function resolvePrecompressedAsset(filePath, acceptEncoding, log) {
|
|
146
104
|
const plain = { filePath, encoding: null };
|
|
147
105
|
if (!acceptsBrotli(acceptEncoding) || !isCompressibleAsset(filePath))
|
|
148
106
|
return plain;
|
|
@@ -183,7 +141,7 @@ async function resolvePrecompressedAsset(filePath, acceptEncoding, log) {
|
|
|
183
141
|
* a page load faster would be a bad trade. Failures are silent here — the
|
|
184
142
|
* request path logs them if it ever hits one.
|
|
185
143
|
*/
|
|
186
|
-
function warmPrecompressedAssets(root, log) {
|
|
144
|
+
export function warmPrecompressedAssets(root, log) {
|
|
187
145
|
void (async () => {
|
|
188
146
|
let warmed = 0;
|
|
189
147
|
for (const file of await listCompressible(root)) {
|
|
@@ -213,7 +171,7 @@ async function listCompressible(dir, out = []) {
|
|
|
213
171
|
return out;
|
|
214
172
|
}
|
|
215
173
|
/** Test seam — the "read-only dist" warning is once per process. */
|
|
216
|
-
function resetPrecompressedWarning() {
|
|
174
|
+
export function resetPrecompressedWarning() {
|
|
217
175
|
warnedUnwritable = false;
|
|
218
176
|
}
|
|
219
177
|
/**
|
|
@@ -222,10 +180,10 @@ function resetPrecompressedWarning() {
|
|
|
222
180
|
* root, which is what CI runs as, and the test that relied on it produced a
|
|
223
181
|
* `.br` in a "read-only" directory (2026-09-23).
|
|
224
182
|
*/
|
|
225
|
-
function precompressedTempPath(brPath) {
|
|
183
|
+
export function precompressedTempPath(brPath) {
|
|
226
184
|
return `${brPath}.${String(process.pid)}.tmp`;
|
|
227
185
|
}
|
|
228
186
|
/** Synchronous existence probe used by the callers' own guards. */
|
|
229
|
-
function precompressedSiblingExists(filePath) {
|
|
187
|
+
export function precompressedSiblingExists(filePath) {
|
|
230
188
|
return fs.existsSync(`${filePath}.br`);
|
|
231
189
|
}
|
|
@@ -1,42 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
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.FORWARDED_PREFIX_HEADER = void 0;
|
|
37
|
-
exports.parseForwardedPrefix = parseForwardedPrefix;
|
|
38
|
-
exports.injectSpaMount = injectSpaMount;
|
|
39
|
-
exports.sendSpaShell = sendSpaShell;
|
|
40
1
|
/**
|
|
41
2
|
* spa-mount — serving the admin-UI shell under a reverse-proxy path prefix.
|
|
42
3
|
*
|
|
@@ -54,10 +15,10 @@ exports.sendSpaShell = sendSpaShell;
|
|
|
54
15
|
*
|
|
55
16
|
* Without the header nothing changes — the shell is served exactly as before.
|
|
56
17
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
18
|
+
import * as fs from 'node:fs/promises';
|
|
19
|
+
import { spaShellCacheControl } from './spa-static';
|
|
59
20
|
/** Node lower-cases incoming header names. */
|
|
60
|
-
|
|
21
|
+
export const FORWARDED_PREFIX_HEADER = 'x-forwarded-prefix';
|
|
61
22
|
/** The canonical spelling, for `Vary`. */
|
|
62
23
|
const FORWARDED_PREFIX_VARY = 'X-Forwarded-Prefix';
|
|
63
24
|
const MOUNT_META_NAME = 'camstack-mount';
|
|
@@ -73,7 +34,7 @@ const MAX_PREFIX_LENGTH = 512;
|
|
|
73
34
|
* an attribute. Invalid is treated as absent — a relay that gets this wrong
|
|
74
35
|
* gets the root shell, never a 4xx and never a partial injection.
|
|
75
36
|
*/
|
|
76
|
-
function parseForwardedPrefix(value) {
|
|
37
|
+
export function parseForwardedPrefix(value) {
|
|
77
38
|
if (typeof value !== 'string')
|
|
78
39
|
return null;
|
|
79
40
|
if (value.length === 0 || value.length > MAX_PREFIX_LENGTH)
|
|
@@ -100,7 +61,7 @@ function parseForwardedPrefix(value) {
|
|
|
100
61
|
* relative build shipped, and only the root worked (operator, 2026-09-07).
|
|
101
62
|
* A root mount is therefore `<base href="/">`, not "no base at all".
|
|
102
63
|
*/
|
|
103
|
-
function injectSpaMount(html, prefix) {
|
|
64
|
+
export function injectSpaMount(html, prefix) {
|
|
104
65
|
const match = /<head(?:\s[^>]*)?>/i.exec(html);
|
|
105
66
|
if (match === null)
|
|
106
67
|
return html;
|
|
@@ -114,8 +75,8 @@ function injectSpaMount(html, prefix) {
|
|
|
114
75
|
* `Vary: X-Forwarded-Prefix` — a cache that ignores `no-store` must still
|
|
115
76
|
* never hand a root shell to a relayed request or vice versa.
|
|
116
77
|
*/
|
|
117
|
-
async function sendSpaShell(reply, indexPath, headers) {
|
|
118
|
-
reply.header('cache-control',
|
|
78
|
+
export async function sendSpaShell(reply, indexPath, headers) {
|
|
79
|
+
reply.header('cache-control', spaShellCacheControl());
|
|
119
80
|
reply.header('vary', FORWARDED_PREFIX_VARY);
|
|
120
81
|
let html;
|
|
121
82
|
try {
|
|
@@ -127,6 +88,6 @@ async function sendSpaShell(reply, indexPath, headers) {
|
|
|
127
88
|
}
|
|
128
89
|
// `''` is the root mount: `injectSpaMount` writes `<base href="/">`, which a
|
|
129
90
|
// relative-asset shell needs at every depth. Never "no base".
|
|
130
|
-
const prefix = parseForwardedPrefix(headers[
|
|
91
|
+
const prefix = parseForwardedPrefix(headers[FORWARDED_PREFIX_HEADER]) ?? '';
|
|
131
92
|
return reply.type('text/html').send(injectSpaMount(html, prefix));
|
|
132
93
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* spa-static — shared static-serving helpers for the SPAs the hub mounts
|
|
4
3
|
* (admin-ui at `/`, viewer-ui at `/viewer/camstack`). Extracted so both
|
|
@@ -6,12 +5,6 @@
|
|
|
6
5
|
* immutable; the service worker / registration / web manifest + the SPA shell
|
|
7
6
|
* (`index.html`) always revalidate so a redeploy actually reaches clients.
|
|
8
7
|
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.spaShellCacheControl = spaShellCacheControl;
|
|
11
|
-
exports.spaAssetCacheControl = spaAssetCacheControl;
|
|
12
|
-
exports.addonBundleCacheControl = addonBundleCacheControl;
|
|
13
|
-
exports.contentTypeForPath = contentTypeForPath;
|
|
14
|
-
exports.isRetiredPublicPath = isRetiredPublicPath;
|
|
15
8
|
/**
|
|
16
9
|
* Cache-Control for the SPA SHELL (`index.html`) — the HTML entry only, never a
|
|
17
10
|
* hashed asset.
|
|
@@ -29,7 +22,7 @@ exports.isRetiredPublicPath = isRetiredPublicPath;
|
|
|
29
22
|
* send the shell with NO header at all, which is where the stale copies came
|
|
30
23
|
* from.
|
|
31
24
|
*/
|
|
32
|
-
function spaShellCacheControl() {
|
|
25
|
+
export function spaShellCacheControl() {
|
|
33
26
|
return 'no-store';
|
|
34
27
|
}
|
|
35
28
|
/**
|
|
@@ -44,7 +37,7 @@ function spaShellCacheControl() {
|
|
|
44
37
|
* so the same bytes never carry two different policies.
|
|
45
38
|
* - Everything else (favicon, non-hashed files) → `no-cache`.
|
|
46
39
|
*/
|
|
47
|
-
function spaAssetCacheControl(rel) {
|
|
40
|
+
export function spaAssetCacheControl(rel) {
|
|
48
41
|
const base = rel.split('/').pop() ?? rel;
|
|
49
42
|
if (/^(sw\.js|registerSW\.js|workbox-.*\.js|manifest\.webmanifest)$/.test(base)) {
|
|
50
43
|
return 'no-cache, must-revalidate';
|
|
@@ -73,7 +66,7 @@ function spaAssetCacheControl(rel) {
|
|
|
73
66
|
* until a manual hard-reload. Unknown fixed names now revalidate — the
|
|
74
67
|
* cost is a cheap 304.
|
|
75
68
|
*/
|
|
76
|
-
function addonBundleCacheControl(filePath) {
|
|
69
|
+
export function addonBundleCacheControl(filePath) {
|
|
77
70
|
const base = filePath.split('/').pop() ?? filePath;
|
|
78
71
|
// Vite/rolldown content hash: exactly 8 base64url chars between a
|
|
79
72
|
// hyphen and the extension (`dist-CYZr2fwk.mjs`, `….js-CQ-aEQ9b.mjs`).
|
|
@@ -114,14 +107,14 @@ const CONTENT_TYPES = {
|
|
|
114
107
|
* assets directly (the admin-ui path goes through @fastify/static). Defaults
|
|
115
108
|
* to `application/octet-stream` for unknown extensions.
|
|
116
109
|
*/
|
|
117
|
-
function contentTypeForPath(pathname) {
|
|
110
|
+
export function contentTypeForPath(pathname) {
|
|
118
111
|
const base = pathname.split('/').pop() ?? pathname;
|
|
119
112
|
const dot = base.lastIndexOf('.');
|
|
120
113
|
const ext = dot >= 0 ? base.slice(dot + 1).toLowerCase() : '';
|
|
121
114
|
return CONTENT_TYPES[ext] ?? 'application/octet-stream';
|
|
122
115
|
}
|
|
123
116
|
/** Paths intentionally retired instead of falling through to the admin SPA. */
|
|
124
|
-
function isRetiredPublicPath(url) {
|
|
117
|
+
export function isRetiredPublicPath(url) {
|
|
125
118
|
const pathname = url.split('?')[0] ?? url;
|
|
126
119
|
return (pathname === '/addon/stream-broker/embed' || pathname.startsWith('/addon/stream-broker/embed/'));
|
|
127
120
|
}
|
|
@@ -1,51 +1,14 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
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.isTarballFilename = isTarballFilename;
|
|
37
|
-
exports.readTarballManifest = readTarballManifest;
|
|
38
1
|
/**
|
|
39
2
|
* npm-pack tarball manifest inspection — shared by the addon upload route
|
|
40
3
|
* (`/api/addons/upload`) and the dev server-deploy upload route
|
|
41
4
|
* (`/api/server-upload`).
|
|
42
5
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
6
|
+
import { execFileSync } from 'node:child_process';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as os from 'node:os';
|
|
9
|
+
import * as path from 'node:path';
|
|
47
10
|
const TARBALL_EXTENSIONS = ['.tgz', '.tar.gz'];
|
|
48
|
-
function isTarballFilename(filename) {
|
|
11
|
+
export function isTarballFilename(filename) {
|
|
49
12
|
return TARBALL_EXTENSIONS.some((ext) => filename.endsWith(ext));
|
|
50
13
|
}
|
|
51
14
|
/**
|
|
@@ -60,12 +23,12 @@ function isTarballFilename(filename) {
|
|
|
60
23
|
* fixed inner path. Returns null (not throw) on malformed archives so
|
|
61
24
|
* the caller can surface a precise 400 response.
|
|
62
25
|
*/
|
|
63
|
-
function readTarballManifest(buffer, filename) {
|
|
26
|
+
export function readTarballManifest(buffer, filename) {
|
|
64
27
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-tarball-check-'));
|
|
65
28
|
const tgzPath = path.join(tmpDir, path.basename(filename));
|
|
66
29
|
try {
|
|
67
30
|
fs.writeFileSync(tgzPath, buffer);
|
|
68
|
-
const output =
|
|
31
|
+
const output = execFileSync('tar', ['-xzO', '-f', tgzPath, 'package/package.json'], {
|
|
69
32
|
timeout: 5_000,
|
|
70
33
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
71
34
|
});
|