@siddharatha/adapter-node-rolldown 1.0.9 → 1.1.3
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/files/env.js +92 -48
- package/files/handler.js +1457 -24
- package/files/index.js +477 -29
- package/files/shims.js +30 -4
- package/index.js +33 -165
- package/package.json +15 -16
- package/files/middlewares.js +0 -162
- package/files/telemetry.js +0 -126
package/index.js
CHANGED
|
@@ -1,38 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { rolldown } from 'rolldown';
|
|
4
4
|
|
|
5
|
-
const files = fileURLToPath(new URL('./files', import.meta.url).href);
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
10
|
-
* @
|
|
11
|
-
* @property {string} [envPrefix=''] - Prefix for environment variables
|
|
12
|
-
* @property {boolean} [polyfill=true] - Inject global polyfills
|
|
13
|
-
* @property {string[]|((pkg: any) => string[])} [external] - External packages to exclude from bundle
|
|
14
|
-
* @property {object} [rolldownOptions={}] - Additional rolldown configuration options
|
|
7
|
+
* @template T
|
|
8
|
+
* @template {keyof T} K
|
|
9
|
+
* @typedef {Partial<Omit<T, K>> & Required<Pick<T, K>>} PartialExcept
|
|
15
10
|
*/
|
|
16
11
|
|
|
17
12
|
/**
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
13
|
+
* We use a custom `Builder` type here to support the minimum version of SvelteKit.
|
|
14
|
+
* @typedef {PartialExcept<import('@sveltejs/kit').Builder, 'log' | 'rimraf' | 'mkdirp' | 'config' | 'prerendered' | 'routes' | 'createEntries' | 'findServerAssets' | 'generateFallback' | 'generateEnvModule' | 'generateManifest' | 'getBuildDirectory' | 'getClientDirectory' | 'getServerDirectory' | 'getAppPath' | 'writeClient' | 'writePrerendered' | 'writePrerendered' | 'writeServer' | 'copy' | 'compress'>} Builder2_4_0
|
|
20
15
|
*/
|
|
21
|
-
export default function (options = {}) {
|
|
22
|
-
const {
|
|
23
|
-
out = 'build',
|
|
24
|
-
precompress = true,
|
|
25
|
-
envPrefix = '',
|
|
26
|
-
polyfill = true,
|
|
27
|
-
external,
|
|
28
|
-
rolldownOptions = {}
|
|
29
|
-
} = options;
|
|
30
16
|
|
|
31
|
-
|
|
32
|
-
name: '@sveltejs/adapter-node-rolldown',
|
|
17
|
+
const files = fileURLToPath(new URL('./files', import.meta.url).href);
|
|
33
18
|
|
|
19
|
+
/** @type {import('./index.js').default} */
|
|
20
|
+
export default function (opts = {}) {
|
|
21
|
+
const { out = 'build', precompress = true, envPrefix = '', external, bundleAll = false, rolldownOptions = {} } = opts;
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
name: '@sveltejs/adapter-node',
|
|
25
|
+
/** @param {Builder2_4_0} builder */
|
|
34
26
|
async adapt(builder) {
|
|
35
|
-
const tmp = builder.getBuildDirectory('adapter-node
|
|
27
|
+
const tmp = builder.getBuildDirectory('adapter-node');
|
|
36
28
|
|
|
37
29
|
builder.rimraf(out);
|
|
38
30
|
builder.rimraf(tmp);
|
|
@@ -65,72 +57,29 @@ export default function (options = {}) {
|
|
|
65
57
|
|
|
66
58
|
const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
|
|
67
59
|
|
|
60
|
+
// determine external patterns for bundling
|
|
61
|
+
let externalPatterns;
|
|
62
|
+
if (bundleAll) {
|
|
63
|
+
externalPatterns = [];
|
|
64
|
+
} else if (external) {
|
|
65
|
+
externalPatterns = typeof external === 'function' ? external(pkg) : external;
|
|
66
|
+
} else {
|
|
67
|
+
externalPatterns = Object.keys(pkg.dependencies || {});
|
|
68
|
+
}
|
|
69
|
+
|
|
68
70
|
/** @type {Record<string, string>} */
|
|
69
71
|
const input = {
|
|
70
72
|
index: `${tmp}/index.js`,
|
|
71
73
|
manifest: `${tmp}/manifest.js`
|
|
72
74
|
};
|
|
73
75
|
|
|
74
|
-
// Support for instrumentation files
|
|
75
76
|
if (builder.hasServerInstrumentationFile?.()) {
|
|
76
77
|
input['instrumentation.server'] = `${tmp}/instrumentation.server.js`;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
'constants', 'crypto', 'dgram', 'diagnostics_channel', 'dns', 'domain',
|
|
83
|
-
'events', 'fs', 'http', 'http2', 'https', 'inspector', 'module', 'net',
|
|
84
|
-
'os', 'path', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline',
|
|
85
|
-
'repl', 'stream', 'string_decoder', 'sys', 'timers', 'tls', 'trace_events',
|
|
86
|
-
'tty', 'url', 'util', 'v8', 'vm', 'wasi', 'worker_threads', 'zlib'
|
|
87
|
-
];
|
|
88
|
-
|
|
89
|
-
// Determine external packages
|
|
90
|
-
// Always include runtime dependencies and user dependencies
|
|
91
|
-
const runtimeDeps = ['polka', 'sirv', '@polka/url'];
|
|
92
|
-
|
|
93
|
-
// OpenTelemetry packages have CommonJS/require issues when bundled as ESM
|
|
94
|
-
// Always mark them as external
|
|
95
|
-
const otelPackages = [
|
|
96
|
-
'@opentelemetry/api',
|
|
97
|
-
'@opentelemetry/sdk-node',
|
|
98
|
-
'@opentelemetry/auto-instrumentations-node',
|
|
99
|
-
'@opentelemetry/exporter-trace-otlp-http',
|
|
100
|
-
'@opentelemetry/exporter-trace-otlp-grpc',
|
|
101
|
-
'@opentelemetry/exporter-metrics-otlp-http',
|
|
102
|
-
'@opentelemetry/exporter-metrics-otlp-grpc',
|
|
103
|
-
'@opentelemetry/otlp-exporter-base',
|
|
104
|
-
'@opentelemetry/resources',
|
|
105
|
-
'@opentelemetry/semantic-conventions',
|
|
106
|
-
'@opentelemetry/core',
|
|
107
|
-
'@opentelemetry/instrumentation',
|
|
108
|
-
'import-in-the-middle'
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
let externalPackages = [...runtimeDeps, ...otelPackages];
|
|
112
|
-
|
|
113
|
-
if (typeof external === 'function') {
|
|
114
|
-
externalPackages = [...externalPackages, ...external(pkg)];
|
|
115
|
-
} else if (Array.isArray(external)) {
|
|
116
|
-
externalPackages = [...externalPackages, ...external];
|
|
117
|
-
} else {
|
|
118
|
-
// Default: use package.json dependencies
|
|
119
|
-
externalPackages = [...externalPackages, ...Object.keys(pkg.dependencies || {})];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Combine builtins with external packages
|
|
123
|
-
const allExternal = [...new Set([...builtins, ...externalPackages])];
|
|
124
|
-
|
|
125
|
-
// Convert to regex patterns for deep exports support
|
|
126
|
-
// Also handle node: prefix for built-ins
|
|
127
|
-
const externalPatterns = allExternal.map((d) =>
|
|
128
|
-
new RegExp(`^(node:)?${d.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\/.*)?$`)
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
// Bundle the Vite output so deployments only need production dependencies
|
|
132
|
-
// Anything in devDependencies will get included in the bundled code
|
|
133
|
-
// Rolldown has native support for node resolution, CommonJS, and JSON
|
|
80
|
+
// we bundle the Vite output so that deployments only need
|
|
81
|
+
// their production dependencies. Anything in devDependencies
|
|
82
|
+
// will get included in the bundled code
|
|
134
83
|
const bundle = await rolldown({
|
|
135
84
|
input,
|
|
136
85
|
external: externalPatterns,
|
|
@@ -147,59 +96,21 @@ export default function (options = {}) {
|
|
|
147
96
|
dir: `${out}/server`,
|
|
148
97
|
format: 'esm',
|
|
149
98
|
sourcemap: true,
|
|
150
|
-
chunkFileNames: 'chunks/[name]-[hash].js'
|
|
151
|
-
minify: false,
|
|
152
|
-
keepNames: true
|
|
99
|
+
chunkFileNames: 'chunks/[name]-[hash].js'
|
|
153
100
|
});
|
|
154
101
|
|
|
155
|
-
|
|
156
|
-
builder.copy(files, `${tmp}/runtime`, {
|
|
102
|
+
builder.copy(files, out, {
|
|
157
103
|
replace: {
|
|
104
|
+
ENV: './env.js',
|
|
158
105
|
HANDLER: './handler.js',
|
|
159
106
|
MANIFEST: './server/manifest.js',
|
|
160
107
|
SERVER: './server/index.js',
|
|
161
108
|
SHIMS: './shims.js',
|
|
162
|
-
MIDDLEWARES: './middlewares.js',
|
|
163
109
|
ENV_PREFIX: JSON.stringify(envPrefix),
|
|
164
|
-
|
|
110
|
+
PRECOMPRESS: JSON.stringify(precompress)
|
|
165
111
|
}
|
|
166
112
|
});
|
|
167
113
|
|
|
168
|
-
// Bundle the runtime files (second pass)
|
|
169
|
-
// Mark the server files as external since they're already bundled
|
|
170
|
-
const runtimeExternalPatterns = [
|
|
171
|
-
...externalPatterns,
|
|
172
|
-
/^\.\/server\// // Server files are already bundled, keep them external
|
|
173
|
-
];
|
|
174
|
-
|
|
175
|
-
const runtimeBundle = await rolldown({
|
|
176
|
-
input: {
|
|
177
|
-
index: `${tmp}/runtime/index.js`
|
|
178
|
-
},
|
|
179
|
-
external: runtimeExternalPatterns,
|
|
180
|
-
platform: 'node',
|
|
181
|
-
resolve: {
|
|
182
|
-
conditionNames: ['node', 'import'],
|
|
183
|
-
modulePaths: [
|
|
184
|
-
fileURLToPath(new URL('./node_modules', import.meta.url)),
|
|
185
|
-
...(rolldownOptions.resolve?.modulePaths || [])
|
|
186
|
-
],
|
|
187
|
-
...rolldownOptions.resolve
|
|
188
|
-
},
|
|
189
|
-
cwd: process.cwd(),
|
|
190
|
-
...rolldownOptions
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
await runtimeBundle.write({
|
|
194
|
-
dir: `${out}`,
|
|
195
|
-
format: 'esm',
|
|
196
|
-
sourcemap: true,
|
|
197
|
-
chunkFileNames: 'chunks/[name]-[hash].js',
|
|
198
|
-
minify: false,
|
|
199
|
-
keepNames: true
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Support for instrumentation
|
|
203
114
|
if (builder.hasServerInstrumentationFile?.()) {
|
|
204
115
|
builder.instrument?.({
|
|
205
116
|
entrypoint: `${out}/index.js`,
|
|
@@ -209,49 +120,6 @@ export default function (options = {}) {
|
|
|
209
120
|
}
|
|
210
121
|
});
|
|
211
122
|
}
|
|
212
|
-
|
|
213
|
-
builder.log.minor('Generating package.json');
|
|
214
|
-
|
|
215
|
-
// Collect all user dependencies (both dependencies and devDependencies)
|
|
216
|
-
const allUserDeps = {
|
|
217
|
-
...(pkg.dependencies || {}),
|
|
218
|
-
...(pkg.devDependencies || {})
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// Include adapter runtime dependencies + all user dependencies
|
|
222
|
-
const finalDeps = {
|
|
223
|
-
'@polka/url': '^1.0.0-next.28',
|
|
224
|
-
'polka': '^0.5.2',
|
|
225
|
-
'sirv': '^3.0.2',
|
|
226
|
-
...(pkg.dependencies || {})
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
// Add OpenTelemetry packages if they're used (from devDependencies or dependencies)
|
|
230
|
-
for (const otelPkg of otelPackages) {
|
|
231
|
-
if (allUserDeps[otelPkg] && !finalDeps[otelPkg]) {
|
|
232
|
-
finalDeps[otelPkg] = allUserDeps[otelPkg];
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
builder.log.info(`Including ${Object.keys(finalDeps).length} dependencies in output package.json`);
|
|
237
|
-
|
|
238
|
-
writeFileSync(
|
|
239
|
-
`${out}/package.json`,
|
|
240
|
-
JSON.stringify(
|
|
241
|
-
{
|
|
242
|
-
name: pkg.name || 'sveltekit-app',
|
|
243
|
-
version: pkg.version || '1.0.0',
|
|
244
|
-
type: 'module',
|
|
245
|
-
main: './index.js',
|
|
246
|
-
dependencies: finalDeps
|
|
247
|
-
},
|
|
248
|
-
null,
|
|
249
|
-
2
|
|
250
|
-
)
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
builder.log.success(`Adapter complete! Output: ${out}`);
|
|
254
|
-
builder.log.info(`\nTo run the server:\n cd ${out}\n npm install\n node index.js\n`);
|
|
255
123
|
},
|
|
256
124
|
|
|
257
125
|
supports: {
|
|
@@ -259,4 +127,4 @@ export default function (options = {}) {
|
|
|
259
127
|
instrumentation: () => true
|
|
260
128
|
}
|
|
261
129
|
};
|
|
262
|
-
}
|
|
130
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siddharatha/adapter-node-rolldown",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"description": "Just replacing @sveltejs/adapter-node with rolldown",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./index.js"
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"index.d.ts"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"
|
|
15
|
+
"dev": "rollup -cw",
|
|
16
|
+
"build": "rollup -c",
|
|
17
|
+
"check": "tsc",
|
|
18
|
+
"lint": "prettier --check .",
|
|
19
|
+
"format": "pnpm lint --write",
|
|
20
|
+
"prepublishOnly": "pnpm build"
|
|
16
21
|
},
|
|
17
22
|
"keywords": [
|
|
18
23
|
"svelte",
|
|
@@ -29,25 +34,19 @@
|
|
|
29
34
|
"author": "",
|
|
30
35
|
"license": "MIT",
|
|
31
36
|
"dependencies": {
|
|
32
|
-
"rolldown": "
|
|
37
|
+
"rolldown": "1.0.0-beta.60",
|
|
38
|
+
"@rollup/plugin-commonjs": "^28.0.1",
|
|
39
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
40
|
+
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
41
|
+
"rollup": "^4.9.5"
|
|
33
42
|
},
|
|
34
43
|
"peerDependencies": {
|
|
35
44
|
"@sveltejs/kit": "^2.4.0"
|
|
36
45
|
},
|
|
37
46
|
"devDependencies": {
|
|
38
|
-
"@sveltejs/kit": "^2.4.0",
|
|
39
47
|
"@polka/url": "^1.0.0-next.28",
|
|
48
|
+
"@sveltejs/kit": "^2.4.0",
|
|
40
49
|
"polka": "^0.5.2",
|
|
41
|
-
"sirv": "^3.0.2"
|
|
42
|
-
"compression": "^1.7.4",
|
|
43
|
-
"ws": "^8.16.0",
|
|
44
|
-
"@opentelemetry/sdk-node": "0.48.0",
|
|
45
|
-
"@opentelemetry/auto-instrumentations-node": "0.41.0",
|
|
46
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.48.0",
|
|
47
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "0.48.0",
|
|
48
|
-
"@opentelemetry/resources": "1.21.0",
|
|
49
|
-
"@opentelemetry/semantic-conventions": "1.21.0",
|
|
50
|
-
"@opentelemetry/api": "1.7.0",
|
|
51
|
-
"import-in-the-middle": "^2.0.3"
|
|
50
|
+
"sirv": "^3.0.2"
|
|
52
51
|
}
|
|
53
52
|
}
|
package/files/middlewares.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import compression from 'compression';
|
|
2
|
-
import sirv from 'sirv';
|
|
3
|
-
import { config } from 'ENV';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Create compression middleware with optimized settings
|
|
7
|
-
*/
|
|
8
|
-
export function createCompressionMiddleware() {
|
|
9
|
-
if (!config.compression) {
|
|
10
|
-
return (req, res, next) => next();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return compression({
|
|
14
|
-
level: config.compressionLevel,
|
|
15
|
-
threshold: 1024, // Only compress responses > 1KB
|
|
16
|
-
memLevel: 8,
|
|
17
|
-
filter: (req, res) => {
|
|
18
|
-
const contentType = res.getHeader('Content-Type');
|
|
19
|
-
|
|
20
|
-
// Don't compress images, videos, or already compressed content
|
|
21
|
-
if (contentType && (
|
|
22
|
-
contentType.includes('image/') ||
|
|
23
|
-
contentType.includes('video/') ||
|
|
24
|
-
contentType.includes('audio/') ||
|
|
25
|
-
contentType.includes('font/')
|
|
26
|
-
)) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Use default compression filter for everything else
|
|
31
|
-
return compression.filter(req, res);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Create static file serving middleware with optimized settings
|
|
38
|
-
*/
|
|
39
|
-
export function createStaticMiddleware(dir, precompressed = true) {
|
|
40
|
-
return sirv(dir, {
|
|
41
|
-
dev: false,
|
|
42
|
-
etag: true,
|
|
43
|
-
maxAge: 31536000, // 1 year for immutable assets
|
|
44
|
-
immutable: true,
|
|
45
|
-
gzip: precompressed, // Serve .gz files if available
|
|
46
|
-
brotli: precompressed, // Serve .br files if available
|
|
47
|
-
setHeaders: (res, pathname) => {
|
|
48
|
-
// Cache control based on file type
|
|
49
|
-
if (pathname.includes('immutable')) {
|
|
50
|
-
res.setHeader('Cache-Control', 'public, immutable, max-age=31536000');
|
|
51
|
-
} else if (pathname.endsWith('.html')) {
|
|
52
|
-
res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
|
|
53
|
-
} else {
|
|
54
|
-
res.setHeader('Cache-Control', 'public, max-age=3600');
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Simple body parser for JSON and URL-encoded data with configurable limits
|
|
62
|
-
*/
|
|
63
|
-
export function createBodyParser() {
|
|
64
|
-
const limitBytes = parseLimit(config.bodyLimit);
|
|
65
|
-
|
|
66
|
-
return (req, res, next) => {
|
|
67
|
-
// Skip if not a body method
|
|
68
|
-
if (req.method !== 'POST' && req.method !== 'PUT' && req.method !== 'PATCH') {
|
|
69
|
-
return next();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Skip if body already parsed
|
|
73
|
-
if (req.body) {
|
|
74
|
-
return next();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const contentType = req.headers['content-type'] || '';
|
|
78
|
-
|
|
79
|
-
// Skip if not JSON or form data (SvelteKit will handle FormData/multipart)
|
|
80
|
-
if (!contentType.includes('application/json') &&
|
|
81
|
-
!contentType.includes('application/x-www-form-urlencoded')) {
|
|
82
|
-
return next();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let data = '';
|
|
86
|
-
let size = 0;
|
|
87
|
-
|
|
88
|
-
req.on('data', chunk => {
|
|
89
|
-
size += chunk.length;
|
|
90
|
-
if (size > limitBytes) {
|
|
91
|
-
req.removeAllListeners('data');
|
|
92
|
-
req.removeAllListeners('end');
|
|
93
|
-
res.writeHead(413, { 'Content-Type': 'application/json' });
|
|
94
|
-
res.end(JSON.stringify({ error: 'Request body too large' }));
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
data += chunk.toString();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
req.on('end', () => {
|
|
101
|
-
try {
|
|
102
|
-
if (contentType.includes('application/json')) {
|
|
103
|
-
req.body = data ? JSON.parse(data) : {};
|
|
104
|
-
} else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
105
|
-
req.body = parseUrlEncoded(data);
|
|
106
|
-
}
|
|
107
|
-
} catch (error) {
|
|
108
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
109
|
-
res.end(JSON.stringify({ error: 'Invalid request body' }));
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
next();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
req.on('error', (error) => {
|
|
116
|
-
console.error('Body parse error:', error);
|
|
117
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
118
|
-
res.end(JSON.stringify({ error: 'Request error' }));
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Parse size limit string to bytes
|
|
125
|
-
*/
|
|
126
|
-
function parseLimit(limit) {
|
|
127
|
-
if (typeof limit === 'number') return limit;
|
|
128
|
-
|
|
129
|
-
const match = limit.match(/^(\d+(?:\.\d+)?)\s*(kb|mb|gb)?$/i);
|
|
130
|
-
if (!match) return 10 * 1024 * 1024; // Default 10MB
|
|
131
|
-
|
|
132
|
-
const value = parseFloat(match[1]);
|
|
133
|
-
const unit = (match[2] || 'b').toLowerCase();
|
|
134
|
-
|
|
135
|
-
const multipliers = {
|
|
136
|
-
b: 1,
|
|
137
|
-
kb: 1024,
|
|
138
|
-
mb: 1024 * 1024,
|
|
139
|
-
gb: 1024 * 1024 * 1024
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
return value * (multipliers[unit] || 1);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Parse URL-encoded form data
|
|
147
|
-
*/
|
|
148
|
-
function parseUrlEncoded(str) {
|
|
149
|
-
const obj = {};
|
|
150
|
-
const pairs = str.split('&');
|
|
151
|
-
|
|
152
|
-
for (const pair of pairs) {
|
|
153
|
-
const [key, value] = pair.split('=');
|
|
154
|
-
if (key) {
|
|
155
|
-
const decodedKey = decodeURIComponent(key);
|
|
156
|
-
const decodedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
|
|
157
|
-
obj[decodedKey] = decodedValue;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return obj;
|
|
162
|
-
}
|
package/files/telemetry.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { config } from 'ENV';
|
|
2
|
-
|
|
3
|
-
let sdk = null;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Initialize OpenTelemetry SDK for distributed tracing
|
|
7
|
-
*/
|
|
8
|
-
export async function initTelemetry() {
|
|
9
|
-
if (!config.telemetry.enabled) {
|
|
10
|
-
console.log('OpenTelemetry is disabled');
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
// Dynamic imports to avoid loading if telemetry is disabled
|
|
16
|
-
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
|
17
|
-
const { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node');
|
|
18
|
-
const { Resource } = await import('@opentelemetry/resources');
|
|
19
|
-
const { SemanticResourceAttributes } = await import('@opentelemetry/semantic-conventions');
|
|
20
|
-
|
|
21
|
-
// Choose exporter based on protocol
|
|
22
|
-
let TraceExporter;
|
|
23
|
-
if (config.telemetry.protocol === 'grpc') {
|
|
24
|
-
const module = await import('@opentelemetry/exporter-trace-otlp-grpc');
|
|
25
|
-
TraceExporter = module.OTLPTraceExporter;
|
|
26
|
-
} else {
|
|
27
|
-
const module = await import('@opentelemetry/exporter-trace-otlp-http');
|
|
28
|
-
TraceExporter = module.OTLPTraceExporter;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const exporterConfig = {
|
|
32
|
-
url: config.telemetry.endpoint,
|
|
33
|
-
headers: {}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Add Dynatrace API token if provided
|
|
37
|
-
if (config.telemetry.dynatraceToken) {
|
|
38
|
-
exporterConfig.headers['Authorization'] = `Api-Token ${config.telemetry.dynatraceToken}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Merge custom headers from config
|
|
42
|
-
if (config.telemetry.customConfig.headers) {
|
|
43
|
-
Object.assign(exporterConfig.headers, config.telemetry.customConfig.headers);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
sdk = new NodeSDK({
|
|
47
|
-
resource: new Resource({
|
|
48
|
-
[SemanticResourceAttributes.SERVICE_NAME]: config.telemetry.serviceName,
|
|
49
|
-
[SemanticResourceAttributes.SERVICE_VERSION]: config.telemetry.serviceVersion,
|
|
50
|
-
...config.telemetry.customConfig.resourceAttributes
|
|
51
|
-
}),
|
|
52
|
-
traceExporter: new TraceExporter(exporterConfig),
|
|
53
|
-
instrumentations: [
|
|
54
|
-
getNodeAutoInstrumentations({
|
|
55
|
-
// Disable noisy instrumentations
|
|
56
|
-
'@opentelemetry/instrumentation-fs': {
|
|
57
|
-
enabled: false
|
|
58
|
-
},
|
|
59
|
-
'@opentelemetry/instrumentation-http': {
|
|
60
|
-
enabled: true,
|
|
61
|
-
ignoreIncomingPaths: ['/health', '/readiness'],
|
|
62
|
-
ignoreOutgoingUrls: [/\/health$/, /\/readiness$/]
|
|
63
|
-
},
|
|
64
|
-
'@opentelemetry/instrumentation-dns': {
|
|
65
|
-
enabled: false
|
|
66
|
-
},
|
|
67
|
-
// Enable all others by default
|
|
68
|
-
...config.telemetry.customConfig.instrumentations
|
|
69
|
-
})
|
|
70
|
-
],
|
|
71
|
-
// Sampling configuration
|
|
72
|
-
...(config.telemetry.sampleRate < 1.0 && {
|
|
73
|
-
sampler: {
|
|
74
|
-
shouldSample: () => {
|
|
75
|
-
return Math.random() < config.telemetry.sampleRate
|
|
76
|
-
? { decision: 1 } // RECORD_AND_SAMPLED
|
|
77
|
-
: { decision: 0 }; // NOT_RECORD
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
})
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
await sdk.start();
|
|
84
|
-
console.log('OpenTelemetry SDK initialized successfully');
|
|
85
|
-
console.log(` Service: ${config.telemetry.serviceName}`);
|
|
86
|
-
console.log(` Endpoint: ${config.telemetry.endpoint || 'default'}`);
|
|
87
|
-
console.log(` Protocol: ${config.telemetry.protocol}`);
|
|
88
|
-
console.log(` Sample Rate: ${(config.telemetry.sampleRate * 100).toFixed(1)}%`);
|
|
89
|
-
|
|
90
|
-
return sdk;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error('Failed to initialize OpenTelemetry:', error.message);
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Shutdown telemetry SDK and flush remaining spans
|
|
99
|
-
*/
|
|
100
|
-
export async function shutdownTelemetry() {
|
|
101
|
-
if (sdk) {
|
|
102
|
-
console.log('Shutting down OpenTelemetry SDK...');
|
|
103
|
-
try {
|
|
104
|
-
await sdk.shutdown();
|
|
105
|
-
console.log('OpenTelemetry SDK shutdown complete');
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error('Error shutting down OpenTelemetry:', error.message);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get tracer for custom instrumentation
|
|
114
|
-
*/
|
|
115
|
-
export function getTracer(name = 'sveltekit-adapter') {
|
|
116
|
-
if (!config.telemetry.enabled) {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
const { trace } = require('@opentelemetry/api');
|
|
122
|
-
return trace.getTracer(name);
|
|
123
|
-
} catch {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
}
|