@siddharatha/adapter-node-rolldown 1.0.3 → 1.0.7

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/handler.js CHANGED
@@ -1,16 +1,27 @@
1
1
  import 'SHIMS';
2
2
  import { Server } from 'SERVER';
3
3
  import { manifest } from 'MANIFEST';
4
+ import { getRequest, setResponse } from '@sveltejs/kit/node';
4
5
 
5
6
  export const server = new Server(manifest);
6
7
 
7
8
  await server.init({ env: process.env });
8
9
 
9
10
  export const handler = async (req, res) => {
11
+ // Convert Node.js request to Web API Request
12
+ const request = await getRequest({
13
+ request: req,
14
+ base: `${req.socket.encrypted ? 'https' : 'http'}://${req.headers.host}`
15
+ });
16
+
10
17
  // Let SvelteKit handle the request
11
- return server.respond(req, res, {
18
+ const response = await server.respond(request, {
12
19
  getClientAddress() {
13
20
  return req.headers['x-forwarded-for']?.split(',')[0] || req.socket.remoteAddress;
14
- }
21
+ },
22
+ platform: { req }
15
23
  });
24
+
25
+ // Write response back to Node.js response
26
+ await setResponse(res, response);
16
27
  };
package/files/index.js CHANGED
@@ -1,217 +1,46 @@
1
- import { createServer } from 'node:http';
2
1
  import polka from 'polka';
3
- import { config } from 'ENV';
4
- import { initTelemetry, shutdownTelemetry } from 'TELEMETRY';
5
- import { createCompressionMiddleware, createStaticMiddleware, createBodyParser } from 'MIDDLEWARES';
2
+ import sirv from 'sirv';
6
3
  import { handler } from 'HANDLER';
7
4
 
8
- // WebSocket support
9
- let wss = null;
10
- if (config.websocket.enabled) {
11
- const { WebSocketServer } = await import('ws');
12
- wss = WebSocketServer;
13
- }
14
-
15
- // Track server state
16
- let isShuttingDown = false;
17
- let server = null;
18
- let wsServer = null;
19
-
20
- // Export for instrumentation support
21
- export const path = '/';
22
- export let port = config.port;
23
- export let host = config.host;
24
- export { server };
25
-
26
- /**
27
- * Initialize and start the server
28
- */
29
- async function start() {
30
- console.log('Starting SvelteKit high-performance server...');
31
-
32
- // Initialize OpenTelemetry first (for request tracing)
33
- await initTelemetry();
34
-
35
- // Create HTTP server
36
- server = createServer();
37
-
38
- // Configure server performance settings
39
- server.keepAliveTimeout = config.keepAliveTimeout;
40
- server.headersTimeout = config.headersTimeout;
41
- if (config.maxRequestsPerSocket) {
42
- server.maxRequestsPerSocket = config.maxRequestsPerSocket;
43
- }
44
-
45
- // Create Polka app
46
- const app = polka({ server });
47
-
48
- // Health check endpoints (before other middleware)
49
- if (config.healthCheck.enabled) {
50
- app.get('/health', (req, res) => {
51
- if (isShuttingDown) {
52
- res.writeHead(503, { 'Content-Type': 'text/plain' });
53
- res.end('Shutting down');
54
- return;
55
- }
56
- res.writeHead(200, { 'Content-Type': 'text/plain' });
57
- res.end('OK');
58
- });
59
-
60
- app.get('/readiness', async (req, res) => {
61
- if (isShuttingDown) {
62
- res.writeHead(503, { 'Content-Type': 'application/json' });
63
- res.end(JSON.stringify({ status: 'not ready', reason: 'shutting down' }));
64
- return;
65
- }
66
-
67
- // Add custom readiness checks here (database, cache, etc.)
68
- res.writeHead(200, { 'Content-Type': 'application/json' });
69
- res.end(JSON.stringify({ status: 'ready' }));
70
- });
71
- }
72
-
73
- // Apply compression middleware
74
- app.use(createCompressionMiddleware());
75
-
76
- // Apply body parser
77
- app.use(createBodyParser());
78
-
79
- // Serve prerendered pages and static assets
80
- app.use(createStaticMiddleware('client', true));
81
- app.use(createStaticMiddleware('prerendered', false));
82
-
83
- // Handle all other requests with SvelteKit
84
- app.use((req, res) => {
85
- // Convert Polka request to format expected by SvelteKit
86
- handler(req, res);
87
- });
88
-
89
- // Initialize WebSocket server if enabled
90
- if (config.websocket.enabled && wss) {
91
- wsServer = new wss({
92
- server,
93
- path: config.websocket.path
94
- });
95
-
96
- wsServer.on('connection', (ws, req) => {
97
- console.log(`WebSocket connection established: ${req.url}`);
98
-
99
- ws.on('message', (data) => {
100
- // Handle WebSocket messages
101
- // You can add custom logic here or expose via hooks
102
- try {
103
- const message = JSON.parse(data.toString());
104
- console.log('WebSocket message:', message);
105
-
106
- // Echo back for now (customize as needed)
107
- ws.send(JSON.stringify({ type: 'echo', data: message }));
108
- } catch (error) {
109
- console.error('WebSocket message error:', error);
110
- ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
111
- }
112
- });
113
-
114
- ws.on('close', () => {
115
- console.log('WebSocket connection closed');
116
- });
117
-
118
- ws.on('error', (error) => {
119
- console.error('WebSocket error:', error);
120
- });
121
-
122
- // Send welcome message
123
- ws.send(JSON.stringify({ type: 'connected', message: 'WebSocket connected' }));
124
- });
125
-
126
- console.log(`WebSocket server enabled on path: ${config.websocket.path}`);
127
- }
128
-
129
- // Start listening
130
- server.listen(config.port, config.host, () => {
131
- console.log(`\n✓ Server running on http://${config.host}:${config.port}`);
132
- console.log(` - Compression: ${config.compression ? 'enabled' : 'disabled'}`);
133
- console.log(` - WebSocket: ${config.websocket.enabled ? `enabled (${config.websocket.path})` : 'disabled'}`);
134
- console.log(` - OpenTelemetry: ${config.telemetry.enabled ? 'enabled' : 'disabled'}`);
135
- console.log(` - Health checks: ${config.healthCheck.enabled ? 'enabled (/health, /readiness)' : 'disabled'}`);
136
- console.log(` - Body limit: ${config.bodyLimit}`);
137
- console.log('');
138
- });
139
- }
140
-
141
- /**
142
- * Graceful shutdown handler
143
- */
144
- async function gracefulShutdown(signal) {
145
- if (isShuttingDown) {
146
- console.log('Shutdown already in progress...');
147
- return;
148
- }
149
-
150
- isShuttingDown = true;
151
- console.log(`\n${signal} received, starting graceful shutdown...`);
152
-
153
- // Set a timeout to force shutdown
154
- const forceShutdownTimer = setTimeout(() => {
155
- console.error('Forced shutdown after timeout');
156
- process.exit(1);
157
- }, config.gracefulShutdownTimeout);
158
-
159
- try {
160
- // Stop accepting new connections
161
- if (server) {
162
- await new Promise((resolve) => {
163
- server.close(() => {
164
- console.log('✓ HTTP server closed');
165
- resolve();
166
- });
167
- });
168
- }
169
-
170
- // Close WebSocket connections
171
- if (wsServer) {
172
- console.log('Closing WebSocket connections...');
173
- wsServer.clients.forEach((ws) => {
174
- ws.close(1001, 'Server shutting down');
175
- });
176
-
177
- await new Promise((resolve) => {
178
- wsServer.close(() => {
179
- console.log('✓ WebSocket server closed');
180
- resolve();
181
- });
182
- });
183
- }
184
-
185
- // Shutdown OpenTelemetry and flush traces
186
- await shutdownTelemetry();
187
-
188
- clearTimeout(forceShutdownTimer);
189
- console.log('✓ Graceful shutdown complete');
190
- process.exit(0);
191
- } catch (error) {
192
- console.error('Error during shutdown:', error);
193
- clearTimeout(forceShutdownTimer);
194
- process.exit(1);
5
+ const app = polka();
6
+
7
+ // Serve static assets
8
+ app.use(sirv('client', {
9
+ etag: true,
10
+ maxAge: 31536000,
11
+ immutable: true,
12
+ gzip: true,
13
+ brotli: true
14
+ }));
15
+
16
+ // Serve prerendered pages if they exist
17
+ try {
18
+ const { existsSync } = await import('node:fs');
19
+ if (existsSync('prerendered')) {
20
+ app.use(sirv('prerendered', {
21
+ etag: true,
22
+ maxAge: 0
23
+ }));
195
24
  }
25
+ } catch (e) {
26
+ // Skip if prerendered doesn't exist
196
27
  }
197
28
 
198
- // Register shutdown handlers
199
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
200
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
29
+ // Handle all SvelteKit requests
30
+ app.use(handler);
201
31
 
202
- // Handle uncaught errors
203
- process.on('uncaughtException', (error) => {
204
- console.error('Uncaught exception:', error);
205
- gracefulShutdown('UNCAUGHT_EXCEPTION');
206
- });
32
+ // Get port and host from environment
33
+ const PORT = parseInt(process.env.PORT || '3000', 10);
34
+ const HOST = process.env.HOST || '0.0.0.0';
207
35
 
208
- process.on('unhandledRejection', (reason, promise) => {
209
- console.error('Unhandled rejection at:', promise, 'reason:', reason);
210
- gracefulShutdown('UNHANDLED_REJECTION');
36
+ // Start server
37
+ app.listen(PORT, HOST, () => {
38
+ const displayHost = HOST === '0.0.0.0' ? 'localhost' : HOST;
39
+ console.log(`\n✓ Server running on http://${displayHost}:${PORT}\n`);
211
40
  });
212
41
 
213
- // Start the server
214
- start().catch((error) => {
215
- console.error('Failed to start server:', error);
216
- process.exit(1);
217
- });
42
+ // Export for instrumentation
43
+ export const path = '/';
44
+ export const host = HOST;
45
+ export const port = PORT;
46
+ export const server = app.server;
package/index.js CHANGED
@@ -9,19 +9,8 @@ const files = fileURLToPath(new URL('./files', import.meta.url).href);
9
9
  * @property {string} [out='build'] - Output directory
10
10
  * @property {boolean} [precompress=true] - Pre-compress static assets
11
11
  * @property {string} [envPrefix=''] - Prefix for environment variables
12
- * @property {boolean} [compression=true] - Enable runtime compression
13
- * @property {number} [compressionLevel=6] - Compression level (1-9)
14
- * @property {string} [bodyLimit='10mb'] - Body parser size limit
15
- * @property {boolean} [websocket=true] - Enable WebSocket support
16
- * @property {string} [websocketPath='/ws'] - WebSocket endpoint path
17
- * @property {boolean} [telemetry=true] - Enable OpenTelemetry
18
- * @property {object} [telemetryConfig={}] - Additional telemetry configuration
19
- * @property {number} [telemetrySampleRate=1.0] - Sampling rate (0.0-1.0)
20
- * @property {boolean} [healthCheck=true] - Enable health check endpoints
21
- * @property {number} [gracefulShutdownTimeout=30000] - Graceful shutdown timeout (ms)
22
12
  * @property {boolean} [polyfill=true] - Inject global polyfills
23
- * @property {string[]|((pkg: any) => string[])} [external] - External packages to exclude from bundle. Can be array of package names or function that receives package.json and returns array
24
- * @property {boolean} [bundleAll=false] - Bundle all dependencies (ignore package.json dependencies)
13
+ * @property {string[]|((pkg: any) => string[])} [external] - External packages to exclude from bundle
25
14
  * @property {object} [rolldownOptions={}] - Additional rolldown configuration options
26
15
  */
27
16
 
@@ -30,23 +19,13 @@ const files = fileURLToPath(new URL('./files', import.meta.url).href);
30
19
  * @param {AdapterOptions} options
31
20
  */
32
21
  export default function (options = {}) {
22
+ console.log('Using @siddharatha/adapter-node-rolldown v1.0.6 at 15 jan 11:58');
33
23
  const {
34
24
  out = 'build',
35
25
  precompress = true,
36
26
  envPrefix = '',
37
- compression = true,
38
- compressionLevel = 6,
39
- bodyLimit = '1000mb',
40
- websocket = true,
41
- websocketPath = '/ws',
42
- telemetry = true,
43
- telemetryConfig = {},
44
- telemetrySampleRate = 1.0,
45
- healthCheck = true,
46
- gracefulShutdownTimeout = 30000,
47
27
  polyfill = true,
48
28
  external,
49
- bundleAll = false,
50
29
  rolldownOptions = {}
51
30
  } = options;
52
31
 
@@ -109,16 +88,36 @@ export default function (options = {}) {
109
88
  ];
110
89
 
111
90
  // Determine external packages
112
- let externalPackages = [];
113
- if (!bundleAll) {
114
- if (typeof external === 'function') {
115
- externalPackages = external(pkg);
116
- } else if (Array.isArray(external)) {
117
- externalPackages = external;
118
- } else {
119
- // Default: use package.json dependencies
120
- externalPackages = Object.keys(pkg.dependencies || {});
121
- }
91
+ // Always include runtime dependencies and user dependencies
92
+ const runtimeDeps = ['polka', 'sirv', '@polka/url'];
93
+
94
+ // OpenTelemetry packages have CommonJS/require issues when bundled as ESM
95
+ // Always mark them as external
96
+ const otelPackages = [
97
+ '@opentelemetry/api',
98
+ '@opentelemetry/sdk-node',
99
+ '@opentelemetry/auto-instrumentations-node',
100
+ '@opentelemetry/exporter-trace-otlp-http',
101
+ '@opentelemetry/exporter-trace-otlp-grpc',
102
+ '@opentelemetry/exporter-metrics-otlp-http',
103
+ '@opentelemetry/exporter-metrics-otlp-grpc',
104
+ '@opentelemetry/otlp-exporter-base',
105
+ '@opentelemetry/resources',
106
+ '@opentelemetry/semantic-conventions',
107
+ '@opentelemetry/core',
108
+ '@opentelemetry/instrumentation',
109
+ 'import-in-the-middle'
110
+ ];
111
+
112
+ let externalPackages = [...runtimeDeps, ...otelPackages];
113
+
114
+ if (typeof external === 'function') {
115
+ externalPackages = [...externalPackages, ...external(pkg)];
116
+ } else if (Array.isArray(external)) {
117
+ externalPackages = [...externalPackages, ...external];
118
+ } else {
119
+ // Default: use package.json dependencies
120
+ externalPackages = [...externalPackages, ...Object.keys(pkg.dependencies || {})];
122
121
  }
123
122
 
124
123
  // Combine builtins with external packages
@@ -136,6 +135,7 @@ export default function (options = {}) {
136
135
  const bundle = await rolldown({
137
136
  input,
138
137
  external: externalPatterns,
138
+ platform: 'node',
139
139
  resolve: {
140
140
  conditionNames: ['node', 'import'],
141
141
  ...rolldownOptions.resolve
@@ -148,33 +148,57 @@ export default function (options = {}) {
148
148
  dir: `${out}/server`,
149
149
  format: 'esm',
150
150
  sourcemap: true,
151
- chunkFileNames: 'chunks/[name]-[hash].js'
151
+ chunkFileNames: 'chunks/[name]-[hash].js',
152
+ minify: false,
153
+ keepNames: true
152
154
  });
153
155
 
154
- builder.copy(files, out, {
156
+ // Now copy and bundle the runtime files
157
+ builder.copy(files, `${tmp}/runtime`, {
155
158
  replace: {
156
- ENV: './env.js',
157
159
  HANDLER: './handler.js',
158
160
  MANIFEST: './server/manifest.js',
159
161
  SERVER: './server/index.js',
160
162
  SHIMS: './shims.js',
161
- MIDDLEWARES: './middlewares.js',
162
- TELEMETRY: './telemetry.js',
163
163
  ENV_PREFIX: JSON.stringify(envPrefix),
164
- COMPRESSION_ENABLED: JSON.stringify(compression),
165
- COMPRESSION_LEVEL: JSON.stringify(compressionLevel),
166
- BODY_LIMIT: JSON.stringify(bodyLimit),
167
- WEBSOCKET_ENABLED: JSON.stringify(websocket),
168
- WEBSOCKET_PATH: JSON.stringify(websocketPath),
169
- TELEMETRY_ENABLED: JSON.stringify(telemetry),
170
- TELEMETRY_CONFIG: JSON.stringify(telemetryConfig),
171
- TELEMETRY_SAMPLE_RATE: JSON.stringify(telemetrySampleRate),
172
- HEALTH_CHECK_ENABLED: JSON.stringify(healthCheck),
173
- GRACEFUL_SHUTDOWN_TIMEOUT: JSON.stringify(gracefulShutdownTimeout),
174
164
  POLYFILL: JSON.stringify(polyfill)
175
165
  }
176
166
  });
177
167
 
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
+
178
202
  // Support for instrumentation
179
203
  if (builder.hasServerInstrumentationFile?.()) {
180
204
  builder.instrument?.({
@@ -188,36 +212,28 @@ export default function (options = {}) {
188
212
 
189
213
  builder.log.minor('Generating package.json');
190
214
 
191
- // Required runtime dependencies for the adapter
192
- const adapterDeps = {
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 = {
193
223
  '@polka/url': '^1.0.0-next.28',
194
224
  'polka': '^0.5.2',
195
225
  'sirv': '^3.0.2',
196
- 'compression': '^1.7.4'
226
+ ...(pkg.dependencies || {})
197
227
  };
198
228
 
199
- // Optional dependencies based on configuration
200
- if (websocket) {
201
- adapterDeps['ws'] = '^8.16.0';
202
- }
203
-
204
- if (telemetry) {
205
- Object.assign(adapterDeps, {
206
- '@opentelemetry/sdk-node': '0.48.0',
207
- '@opentelemetry/auto-instrumentations-node': '0.41.0',
208
- '@opentelemetry/exporter-trace-otlp-http': '0.48.0',
209
- '@opentelemetry/exporter-trace-otlp-grpc': '0.48.0',
210
- '@opentelemetry/resources': '1.21.0',
211
- '@opentelemetry/semantic-conventions': '1.21.0',
212
- '@opentelemetry/api': '1.7.0',
213
- 'import-in-the-middle': '^2.0.3'
214
- });
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
+ }
215
234
  }
216
235
 
217
- // Merge user's production dependencies with adapter dependencies
218
- // This ensures packages like aws-sdk, dynamodb, etc. are installed at runtime
219
- const userDeps = pkg.dependencies || {};
220
- const finalDeps = { ...userDeps, ...adapterDeps };
236
+ builder.log.info(`Including ${Object.keys(finalDeps).length} dependencies in output package.json`);
221
237
 
222
238
  writeFileSync(
223
239
  `${out}/package.json`,
@@ -227,9 +243,6 @@ export default function (options = {}) {
227
243
  version: pkg.version || '1.0.0',
228
244
  type: 'module',
229
245
  main: './index.js',
230
- engines: {
231
- node: pkg.engines?.node || '>=24.12.0'
232
- },
233
246
  dependencies: finalDeps
234
247
  },
235
248
  null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siddharatha/adapter-node-rolldown",
3
- "version": "1.0.3",
3
+ "version": "1.0.7",
4
4
  "description": "High-performance SvelteKit adapter for Node.js with Polka, WebSockets, and OpenTelemetry",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,9 +11,6 @@
11
11
  "index.js",
12
12
  "index.d.ts"
13
13
  ],
14
- "engines": {
15
- "node": ">=21.0.0"
16
- },
17
14
  "scripts": {
18
15
  "test": "echo \"Error: no test specified\" && exit 1"
19
16
  },
@@ -38,6 +35,19 @@
38
35
  "@sveltejs/kit": "^2.4.0"
39
36
  },
40
37
  "devDependencies": {
41
- "@sveltejs/kit": "^2.4.0"
38
+ "@sveltejs/kit": "^2.4.0",
39
+ "@polka/url": "^1.0.0-next.28",
40
+ "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"
42
52
  }
43
53
  }