@camstack/server 1.1.56 → 1.1.58
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.
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.AddonWidgetsService = void 0;
|
|
37
|
+
exports.stripBundleVersionSegment = stripBundleVersionSegment;
|
|
37
38
|
const path = __importStar(require("node:path"));
|
|
38
39
|
const fs = __importStar(require("node:fs"));
|
|
39
40
|
/**
|
|
@@ -45,6 +46,23 @@ function stripNodeSuffix(registryKey) {
|
|
|
45
46
|
const at = registryKey.indexOf('@');
|
|
46
47
|
return at === -1 ? registryKey : registryKey.slice(0, at);
|
|
47
48
|
}
|
|
49
|
+
/** A content-version namespace segment: `v<hex>` (the aggregator's dir hash). */
|
|
50
|
+
const VERSION_SEGMENT_RE = /^v[0-9a-f]{6,}$/;
|
|
51
|
+
/**
|
|
52
|
+
* Strip the optional leading content-version segment (`v<hash>/`) from a
|
|
53
|
+
* requested bundle path. The version is a cache-busting NAMESPACE only — the
|
|
54
|
+
* real file lives at `distDir/<rest>`; MF relative imports resolve against the
|
|
55
|
+
* versioned URL, so `v<hash>/_stub.js` must resolve to `_stub.js`. Returns
|
|
56
|
+
* `{ filePath, versioned }` — `versioned` lets the route serve content-
|
|
57
|
+
* addressed files as `immutable`. Pure + exported for the spec.
|
|
58
|
+
*/
|
|
59
|
+
function stripBundleVersionSegment(rawPath) {
|
|
60
|
+
const slash = rawPath.indexOf('/');
|
|
61
|
+
if (slash > 0 && VERSION_SEGMENT_RE.test(rawPath.slice(0, slash))) {
|
|
62
|
+
return { filePath: rawPath.slice(slash + 1), versioned: true };
|
|
63
|
+
}
|
|
64
|
+
return { filePath: rawPath, versioned: false };
|
|
65
|
+
}
|
|
48
66
|
/**
|
|
49
67
|
* AddonWidgetsService — server-side helper that backs the static file
|
|
50
68
|
* route `/api/addon-widgets/:addonId/*` (registered in `main.ts`).
|
|
@@ -103,8 +121,11 @@ class AddonWidgetsService {
|
|
|
103
121
|
this.logger.warn('Bundle resolve failed: addon install path not found', { tags: { addonId } });
|
|
104
122
|
return null;
|
|
105
123
|
}
|
|
124
|
+
// Drop the content-version namespace (`v<hash>/`) the aggregator stamps —
|
|
125
|
+
// it exists only to atomically cache-bust the bundle on update.
|
|
126
|
+
const { filePath: bareFilePath } = stripBundleVersionSegment(filePath);
|
|
106
127
|
const resolvedBase = path.resolve(installPath.distDir);
|
|
107
|
-
const resolvedFile = path.resolve(installPath.distDir,
|
|
128
|
+
const resolvedFile = path.resolve(installPath.distDir, bareFilePath);
|
|
108
129
|
// Path traversal protection
|
|
109
130
|
if (!resolvedFile.startsWith(resolvedBase + path.sep) && resolvedFile !== resolvedBase) {
|
|
110
131
|
this.logger.warn('Path traversal denied for addon', { tags: { addonId }, meta: { filePath } });
|
package/dist/main.js
CHANGED
|
@@ -475,11 +475,17 @@ async function bootstrap() {
|
|
|
475
475
|
: ext === '.html'
|
|
476
476
|
? 'text/html'
|
|
477
477
|
: 'application/octet-stream';
|
|
478
|
+
// A content-versioned request (`v<hash>/…`) is content-addressed: the
|
|
479
|
+
// URL changes iff the bundle changed, so EVERYTHING under it — even the
|
|
480
|
+
// fixed-name `_stub.js`/`remoteEntry.js` — is safely immutable (this
|
|
481
|
+
// defeats a CDN edge serving a stale stub). Legacy unversioned requests
|
|
482
|
+
// keep the per-file revalidation policy.
|
|
483
|
+
const { versioned } = (0, addon_widgets_service_1.stripBundleVersionSegment)(filePath);
|
|
484
|
+
const cacheControl = versioned
|
|
485
|
+
? 'public, max-age=31536000, immutable'
|
|
486
|
+
: (0, spa_static_1.addonBundleCacheControl)(resolved);
|
|
478
487
|
const stream = fs.createReadStream(resolved);
|
|
479
|
-
return reply
|
|
480
|
-
.header('cache-control', (0, spa_static_1.addonBundleCacheControl)(resolved))
|
|
481
|
-
.type(contentType)
|
|
482
|
-
.send(stream);
|
|
488
|
+
return reply.header('cache-control', cacheControl).type(contentType).send(stream);
|
|
483
489
|
});
|
|
484
490
|
// Serve static assets (e.g. SVG icons) from an addon's package directory
|
|
485
491
|
fastify.get('/api/addon-assets/:addonId/*', async (request, reply) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.58",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"@camstack/addon-auth": "1.1.6",
|
|
29
29
|
"@camstack/addon-decoder-nodeav": "1.1.9",
|
|
30
30
|
"@camstack/addon-notifiers": "1.1.21",
|
|
31
|
-
"@camstack/addon-pipeline": "1.1.
|
|
32
|
-
"@camstack/addon-pipeline-orchestrator": "1.1.
|
|
31
|
+
"@camstack/addon-pipeline": "1.1.52",
|
|
32
|
+
"@camstack/addon-pipeline-orchestrator": "1.1.42",
|
|
33
33
|
"@camstack/addon-post-analysis": "1.1.24",
|
|
34
34
|
"@camstack/sdk": "1.1.22",
|
|
35
35
|
"@camstack/shm-ring": "1.0.21",
|
|
36
|
-
"@camstack/system": "1.1.
|
|
36
|
+
"@camstack/system": "1.1.45",
|
|
37
37
|
"@camstack/types": "1.1.40",
|
|
38
38
|
"@camstack/ui-library": "1.1.32",
|
|
39
39
|
"@fastify/compress": "^9.0.0",
|