@siddharatha/adapter-node-rolldown 1.0.9 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +61 -162
- package/package.json +15 -16
- package/files/middlewares.js +0 -162
- package/files/telemetry.js +0 -126
package/index.js
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
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
|
-
|
|
16
|
+
|
|
17
|
+
const files = fileURLToPath(new URL('./files', import.meta.url).href);
|
|
18
|
+
|
|
19
|
+
/** @type {import('./index.js').default} */
|
|
20
|
+
export default function (opts = {}) {
|
|
22
21
|
const {
|
|
23
22
|
out = 'build',
|
|
24
|
-
precompress =
|
|
23
|
+
precompress = false,
|
|
25
24
|
envPrefix = '',
|
|
26
25
|
polyfill = true,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
copyDevNodeModules = false,
|
|
27
|
+
cleanPackageJson = true,
|
|
28
|
+
keepPackageDependencies = false,
|
|
29
|
+
copyNpmrc = true
|
|
30
|
+
} = opts;
|
|
30
31
|
|
|
31
32
|
return {
|
|
32
|
-
name: '@sveltejs/adapter-node
|
|
33
|
-
|
|
33
|
+
name: '@sveltejs/adapter-node',
|
|
34
|
+
/** @param {Builder2_4_0} builder */
|
|
34
35
|
async adapt(builder) {
|
|
35
|
-
const tmp = builder.getBuildDirectory('adapter-node
|
|
36
|
+
const tmp = builder.getBuildDirectory('adapter-node');
|
|
36
37
|
|
|
37
38
|
builder.rimraf(out);
|
|
38
39
|
builder.rimraf(tmp);
|
|
@@ -65,141 +66,58 @@ export default function (options = {}) {
|
|
|
65
66
|
|
|
66
67
|
const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
|
|
67
68
|
|
|
69
|
+
// determine external patterns for bundling
|
|
70
|
+
let externalPatterns;
|
|
71
|
+
if (bundleAll) {
|
|
72
|
+
externalPatterns = [];
|
|
73
|
+
} else if (external) {
|
|
74
|
+
externalPatterns = typeof external === 'function' ? external(pkg) : external;
|
|
75
|
+
} else {
|
|
76
|
+
externalPatterns = Object.keys(pkg.dependencies || {});
|
|
77
|
+
}
|
|
78
|
+
|
|
68
79
|
/** @type {Record<string, string>} */
|
|
69
80
|
const input = {
|
|
70
81
|
index: `${tmp}/index.js`,
|
|
71
82
|
manifest: `${tmp}/manifest.js`
|
|
72
83
|
};
|
|
73
84
|
|
|
74
|
-
// Support for instrumentation files
|
|
75
85
|
if (builder.hasServerInstrumentationFile?.()) {
|
|
76
86
|
input['instrumentation.server'] = `${tmp}/instrumentation.server.js`;
|
|
77
87
|
}
|
|
78
88
|
|
|
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
|
|
89
|
+
// we bundle the Vite output so that deployments only need
|
|
90
|
+
// their production dependencies. Anything in devDependencies
|
|
91
|
+
// will get included in the bundled code
|
|
134
92
|
const bundle = await rolldown({
|
|
135
93
|
input,
|
|
136
|
-
external: externalPatterns,
|
|
137
94
|
platform: 'node',
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
...rolldownOptions
|
|
95
|
+
treeshake: true,
|
|
96
|
+
shimMissingExports: true,
|
|
97
|
+
external: keepPackageDependencies
|
|
98
|
+
? [...Object.keys(pkg.dependencies || {}).map((d) => new RegExp(`^${d}(\\/.*)?$`))]
|
|
99
|
+
: undefined,
|
|
144
100
|
});
|
|
145
101
|
|
|
146
102
|
await bundle.write({
|
|
147
103
|
dir: `${out}/server`,
|
|
148
104
|
format: 'esm',
|
|
149
105
|
sourcemap: true,
|
|
150
|
-
chunkFileNames: 'chunks/[name]-[hash].js'
|
|
151
|
-
minify: false,
|
|
152
|
-
keepNames: true
|
|
106
|
+
chunkFileNames: 'chunks/[name]-[hash].js'
|
|
153
107
|
});
|
|
154
108
|
|
|
155
|
-
|
|
156
|
-
builder.copy(files, `${tmp}/runtime`, {
|
|
109
|
+
builder.copy(files, out, {
|
|
157
110
|
replace: {
|
|
111
|
+
ENV: './env.js',
|
|
158
112
|
HANDLER: './handler.js',
|
|
159
113
|
MANIFEST: './server/manifest.js',
|
|
160
114
|
SERVER: './server/index.js',
|
|
161
115
|
SHIMS: './shims.js',
|
|
162
|
-
MIDDLEWARES: './middlewares.js',
|
|
163
116
|
ENV_PREFIX: JSON.stringify(envPrefix),
|
|
164
|
-
|
|
117
|
+
PRECOMPRESS: JSON.stringify(precompress)
|
|
165
118
|
}
|
|
166
119
|
});
|
|
167
120
|
|
|
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
121
|
if (builder.hasServerInstrumentationFile?.()) {
|
|
204
122
|
builder.instrument?.({
|
|
205
123
|
entrypoint: `${out}/index.js`,
|
|
@@ -210,48 +128,29 @@ export default function (options = {}) {
|
|
|
210
128
|
});
|
|
211
129
|
}
|
|
212
130
|
|
|
213
|
-
|
|
131
|
+
if (!polyfill) {
|
|
132
|
+
writeFileSync(`${out}/shims.js`, '', 'utf-8');
|
|
133
|
+
}
|
|
214
134
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
135
|
+
if (copyDevNodeModules) {
|
|
136
|
+
builder.copy('node_modules', `${out}/node_modules`, {});
|
|
137
|
+
}
|
|
138
|
+
if (copyNpmrc) {
|
|
139
|
+
builder.copy('.npmrc', `${out}/.npmrc`, {});
|
|
140
|
+
}
|
|
220
141
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
'polka': '^0.5.2',
|
|
225
|
-
'sirv': '^3.0.2',
|
|
226
|
-
...(pkg.dependencies || {})
|
|
227
|
-
};
|
|
142
|
+
if (cleanPackageJson) {
|
|
143
|
+
const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));
|
|
144
|
+
delete packageJson.devDependencies;
|
|
228
145
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (allUserDeps[otelPkg] && !finalDeps[otelPkg]) {
|
|
232
|
-
finalDeps[otelPkg] = allUserDeps[otelPkg];
|
|
146
|
+
if (!keepPackageDependencies) {
|
|
147
|
+
delete packageJson.dependencies;
|
|
233
148
|
}
|
|
149
|
+
delete packageJson.scripts;
|
|
150
|
+
writeFileSync(`${out}/package.json`, JSON.stringify(packageJson, null, 2), 'utf-8');
|
|
151
|
+
} else {
|
|
152
|
+
builder.copy('package.json', `${out}/package.json`, {});
|
|
234
153
|
}
|
|
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
154
|
},
|
|
256
155
|
|
|
257
156
|
supports: {
|
|
@@ -259,4 +158,4 @@ export default function (options = {}) {
|
|
|
259
158
|
instrumentation: () => true
|
|
260
159
|
}
|
|
261
160
|
};
|
|
262
|
-
}
|
|
161
|
+
}
|
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.4",
|
|
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
|
-
}
|