@openworkers/adapter-sveltekit 0.2.3 → 0.3.1

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/README.md CHANGED
@@ -17,19 +17,77 @@ import adapter from '@openworkers/adapter-sveltekit';
17
17
  export default {
18
18
  kit: {
19
19
  adapter: adapter({
20
- out: 'dist' // default
20
+ out: 'dist', // Output directory (default: 'dist')
21
+ functions: false // Generate mini-workers for API routes (default: false)
21
22
  })
22
23
  }
23
24
  };
24
25
  ```
25
26
 
27
+ ## Options
28
+
29
+ | Option | Type | Default | Description |
30
+ |--------|------|---------|-------------|
31
+ | `out` | `string` | `'dist'` | Output directory for the build |
32
+ | `functions` | `boolean` | `false` | Generate separate mini-workers for each API route |
33
+
26
34
  ## Output
27
35
 
28
36
  ```
29
37
  dist/
30
- worker.js # Worker entry point
31
- routes.js # Route manifest for edge routing
32
- assets/ # Static assets and prerendered pages
38
+ ├── worker.js # Main SSR worker
39
+ ├── routes.js # Route manifest for edge routing
40
+ ├── assets/ # Static assets and prerendered pages
41
+ └── functions/ # Mini-workers for API routes (if functions: true)
42
+ ├── api-hello.js
43
+ └── api-users.js
44
+ ```
45
+
46
+ ## Functions Mode
47
+
48
+ When `functions: true`, the adapter generates a separate mini-worker for each `+server.ts` endpoint:
49
+
50
+ - `/api/hello/+server.ts` → `functions/api-hello.js`
51
+ - `/api/users/+server.ts` → `functions/api-users.js`
52
+
53
+ The route mappings are included in `routes.js`:
54
+
55
+ ```js
56
+ {
57
+ "functions": [
58
+ { "pattern": "/api/hello", "worker": "functions/api-hello.js" },
59
+ { "pattern": "/api/users", "worker": "functions/api-users.js" }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ This prepares for native project routing in the OpenWorkers runner, where each function can be deployed as a separate worker for better isolation and scaling.
65
+
66
+ ## TypeScript
67
+
68
+ For proper types on `platform.env`, add `@openworkers/workers-types`:
69
+
70
+ ```bash
71
+ bun add -d @openworkers/workers-types
72
+ ```
73
+
74
+ Then in `src/app.d.ts`:
75
+
76
+ ```ts
77
+ /// <reference types="@openworkers/workers-types" />
78
+
79
+ declare global {
80
+ namespace App {
81
+ interface Platform {
82
+ env: {
83
+ KV: BindingKV;
84
+ ASSETS: BindingAssets;
85
+ };
86
+ }
87
+ }
88
+ }
89
+
90
+ export {};
33
91
  ```
34
92
 
35
93
  ## License
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Mini-worker template for OpenWorkers Functions.
3
+ * Wraps a SvelteKit API endpoint as a standalone worker.
4
+ */
5
+
6
+ import * as handlers from 'ENDPOINT';
7
+
8
+ export default {
9
+ async fetch(req, env, ctx) {
10
+ globalThis.env = env;
11
+
12
+ const method = req.method;
13
+ const handler = handlers[method];
14
+
15
+ if (!handler) {
16
+ return new Response('Method Not Allowed', {
17
+ status: 405,
18
+ headers: { Allow: Object.keys(handlers).join(', ') }
19
+ });
20
+ }
21
+
22
+ const url = new URL(req.url);
23
+
24
+ // Build a minimal RequestEvent-like object
25
+ const event = {
26
+ request: req,
27
+ url,
28
+ params: ctx.params ?? {},
29
+ platform: { env, ctx },
30
+ getClientAddress() {
31
+ return req.headers.get('x-real-ip') ?? req.headers.get('x-forwarded-for') ?? '';
32
+ }
33
+ };
34
+
35
+ try {
36
+ return await handler(event);
37
+ } catch (error) {
38
+ console.error(`[Function] Error in ${method} handler:`, error);
39
+
40
+ return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
41
+ status: 500,
42
+ headers: { 'Content-Type': 'application/json' }
43
+ });
44
+ }
45
+ }
46
+ };
package/index.d.ts CHANGED
@@ -6,6 +6,13 @@ export interface AdapterOptions {
6
6
  * @default 'dist'
7
7
  */
8
8
  out?: string;
9
+
10
+ /**
11
+ * Generate separate mini-workers for each API route.
12
+ * Outputs to `dist/functions/` with routing info in `routes.js`.
13
+ * @default false
14
+ */
15
+ functions?: boolean;
9
16
  }
10
17
 
11
18
  export default function plugin(options?: AdapterOptions): Adapter;
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, writeFileSync, readdirSync, statSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { build } from 'esbuild';
@@ -13,6 +13,7 @@ export default function (options = {}) {
13
13
  async adapt(builder) {
14
14
  const dest = options.out ?? 'dist';
15
15
  const assetsDir = `${dest}/assets`;
16
+ const functionsEnabled = options.functions ?? false;
16
17
 
17
18
  const files = fileURLToPath(new URL('./files', import.meta.url).href);
18
19
  const tmp = builder.getBuildDirectory('openworkers-tmp');
@@ -34,6 +35,7 @@ export default function (options = {}) {
34
35
 
35
36
  // Generate 404.html fallback
36
37
  const fallback = path.join(assetsDir, '404.html');
38
+
37
39
  if (!existsSync(fallback)) {
38
40
  writeFileSync(fallback, 'Not Found');
39
41
  }
@@ -58,7 +60,7 @@ export default function (options = {}) {
58
60
  `export { Server, manifest, prerendered, base_path };\n`
59
61
  );
60
62
 
61
- // Bundle worker with esbuild
63
+ // Bundle main worker with esbuild
62
64
  const workerDest = `${dest}/worker.js`;
63
65
  const shimAsyncHooks = posixify(path.resolve(files, 'shims/async_hooks.js'));
64
66
 
@@ -80,6 +82,52 @@ export default function (options = {}) {
80
82
  }
81
83
  });
82
84
 
85
+ // Generate mini-workers for API routes if enabled
86
+ /** @type {Array<{pattern: string, worker: string}>} */
87
+ const functions = [];
88
+
89
+ if (functionsEnabled) {
90
+ builder.mkdirp(`${dest}/functions`);
91
+
92
+ const endpointsDir = path.join(builder.getServerDirectory(), 'entries/endpoints');
93
+ const functionTemplate = posixify(path.resolve(files, 'function-worker.js'));
94
+
95
+ if (existsSync(endpointsDir)) {
96
+ const endpoints = findEndpoints(endpointsDir);
97
+
98
+ for (const endpoint of endpoints) {
99
+ const routePattern = endpoint.route;
100
+ const workerName = routePattern.replace(/\//g, '-').replace(/^-/, '') || 'index';
101
+ const workerFile = `functions/${workerName}.js`;
102
+
103
+ // Bundle using the template with ENDPOINT alias
104
+ await build({
105
+ entryPoints: [functionTemplate],
106
+ bundle: true,
107
+ format: 'esm',
108
+ platform: 'browser',
109
+ outfile: `${dest}/${workerFile}`,
110
+ alias: {
111
+ ENDPOINT: posixify(endpoint.file),
112
+ 'node:async_hooks': shimAsyncHooks
113
+ },
114
+ external: ['node:*'],
115
+ minify: false,
116
+ banner: {
117
+ js: `// Generated by ${name} - Function: ${routePattern}\n`
118
+ }
119
+ });
120
+
121
+ functions.push({
122
+ pattern: routePattern,
123
+ worker: workerFile
124
+ });
125
+
126
+ builder.log.minor(` Generated function: ${routePattern} → ${workerFile}`);
127
+ }
128
+ }
129
+ }
130
+
83
131
  // Generate routes.js for edge routing
84
132
  const routes = {
85
133
  // Immutable assets (hashed filenames, cache forever)
@@ -88,6 +136,8 @@ export default function (options = {}) {
88
136
  static: staticFiles.map((f) => `/${f}`),
89
137
  // Prerendered pages (serve from assets, no worker needed)
90
138
  prerendered: builder.prerendered.paths,
139
+ // Functions (API routes as separate workers)
140
+ functions: functions,
91
141
  // Everything else -> SSR
92
142
  ssr: ['/*']
93
143
  };
@@ -101,11 +151,43 @@ export default function (options = {}) {
101
151
 
102
152
  builder.log.minor(`Wrote ${workerDest}`);
103
153
  builder.log.minor(`Wrote ${dest}/routes.js`);
154
+
155
+ if (functions.length > 0) {
156
+ builder.log.minor(`Wrote ${functions.length} function workers to ${dest}/functions/`);
157
+ }
158
+
104
159
  builder.log.minor(`Wrote ${assetsDir} (${builder.prerendered.paths.length} prerendered pages)`);
105
160
  }
106
161
  };
107
162
  }
108
163
 
164
+ /**
165
+ * Find all endpoint files in the server output
166
+ * @param {string} dir
167
+ * @param {string} [base='']
168
+ * @returns {Array<{route: string, file: string}>}
169
+ */
170
+ function findEndpoints(dir, base = '') {
171
+ const results = [];
172
+ const entries = readdirSync(dir);
173
+
174
+ for (const entry of entries) {
175
+ const fullPath = path.join(dir, entry);
176
+ const stat = statSync(fullPath);
177
+
178
+ if (stat.isDirectory()) {
179
+ results.push(...findEndpoints(fullPath, `${base}/${entry}`));
180
+ } else if (entry === '_server.ts.js' || entry === '_server.js.js') {
181
+ results.push({
182
+ route: base || '/',
183
+ file: fullPath
184
+ });
185
+ }
186
+ }
187
+
188
+ return results;
189
+ }
190
+
109
191
  /** @param {string} str */
110
192
  function posixify(str) {
111
193
  return str.replace(/\\/g, '/');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openworkers/adapter-sveltekit",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "description": "SvelteKit adapter for OpenWorkers",
5
5
  "keywords": [
6
6
  "adapter",