@siddharatha/adapter-node-rolldown 1.0.2 → 1.0.5

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.4 at 14 jan 16:06');
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,17 @@ 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
+ let externalPackages = [...runtimeDeps];
94
+
95
+ if (typeof external === 'function') {
96
+ externalPackages = [...externalPackages, ...external(pkg)];
97
+ } else if (Array.isArray(external)) {
98
+ externalPackages = [...externalPackages, ...external];
99
+ } else {
100
+ // Default: use package.json dependencies
101
+ externalPackages = [...externalPackages, ...Object.keys(pkg.dependencies || {})];
122
102
  }
123
103
 
124
104
  // Combine builtins with external packages
@@ -151,30 +131,49 @@ export default function (options = {}) {
151
131
  chunkFileNames: 'chunks/[name]-[hash].js'
152
132
  });
153
133
 
154
- builder.copy(files, out, {
134
+ // Now copy and bundle the runtime files
135
+ builder.copy(files, `${tmp}/runtime`, {
155
136
  replace: {
156
- ENV: './env.js',
157
137
  HANDLER: './handler.js',
158
138
  MANIFEST: './server/manifest.js',
159
139
  SERVER: './server/index.js',
160
140
  SHIMS: './shims.js',
161
- MIDDLEWARES: './middlewares.js',
162
- TELEMETRY: './telemetry.js',
163
141
  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
142
  POLYFILL: JSON.stringify(polyfill)
175
143
  }
176
144
  });
177
145
 
146
+ // Bundle the runtime files (second pass)
147
+ // Mark the server files as external since they're already bundled
148
+ const runtimeExternalPatterns = [
149
+ ...externalPatterns,
150
+ /^\.\/server\// // Server files are already bundled, keep them external
151
+ ];
152
+
153
+ const runtimeBundle = await rolldown({
154
+ input: {
155
+ index: `${tmp}/runtime/index.js`
156
+ },
157
+ external: runtimeExternalPatterns,
158
+ resolve: {
159
+ conditionNames: ['node', 'import'],
160
+ modulePaths: [
161
+ fileURLToPath(new URL('./node_modules', import.meta.url)),
162
+ ...(rolldownOptions.resolve?.modulePaths || [])
163
+ ],
164
+ ...rolldownOptions.resolve
165
+ },
166
+ cwd: process.cwd(),
167
+ ...rolldownOptions
168
+ });
169
+
170
+ await runtimeBundle.write({
171
+ dir: `${out}`,
172
+ format: 'esm',
173
+ sourcemap: true,
174
+ chunkFileNames: 'chunks/[name]-[hash].js'
175
+ });
176
+
178
177
  // Support for instrumentation
179
178
  if (builder.hasServerInstrumentationFile?.()) {
180
179
  builder.instrument?.({
@@ -188,36 +187,15 @@ export default function (options = {}) {
188
187
 
189
188
  builder.log.minor('Generating package.json');
190
189
 
191
- // Required runtime dependencies for the adapter
192
- const adapterDeps = {
190
+ // Include adapter runtime dependencies + all user dependencies
191
+ const finalDeps = {
193
192
  '@polka/url': '^1.0.0-next.28',
194
193
  'polka': '^0.5.2',
195
194
  'sirv': '^3.0.2',
196
- 'compression': '^1.7.4'
195
+ ...(pkg.dependencies || {})
197
196
  };
198
197
 
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': '^1.17.1'
214
- });
215
- }
216
-
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 };
198
+ builder.log.info(`Including ${Object.keys(finalDeps).length} dependencies in output package.json`);
221
199
 
222
200
  writeFileSync(
223
201
  `${out}/package.json`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siddharatha/adapter-node-rolldown",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "High-performance SvelteKit adapter for Node.js with Polka, WebSockets, and OpenTelemetry",
5
5
  "type": "module",
6
6
  "exports": {
@@ -38,6 +38,19 @@
38
38
  "@sveltejs/kit": "^2.4.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@sveltejs/kit": "^2.4.0"
41
+ "@sveltejs/kit": "^2.4.0",
42
+ "@polka/url": "^1.0.0-next.28",
43
+ "polka": "^0.5.2",
44
+ "sirv": "^3.0.2",
45
+ "compression": "^1.7.4",
46
+ "ws": "^8.16.0",
47
+ "@opentelemetry/sdk-node": "0.48.0",
48
+ "@opentelemetry/auto-instrumentations-node": "0.41.0",
49
+ "@opentelemetry/exporter-trace-otlp-http": "0.48.0",
50
+ "@opentelemetry/exporter-trace-otlp-grpc": "0.48.0",
51
+ "@opentelemetry/resources": "1.21.0",
52
+ "@opentelemetry/semantic-conventions": "1.21.0",
53
+ "@opentelemetry/api": "1.7.0",
54
+ "import-in-the-middle": "^2.0.3"
42
55
  }
43
56
  }