@openworkers/adapter-sveltekit 0.3.4 → 0.3.6
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 +5 -5
- package/files/function-worker.js +81 -37
- package/files/shims/async_hooks.js +32 -32
- package/index.js +74 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,10 +35,10 @@ export default {
|
|
|
35
35
|
|
|
36
36
|
```
|
|
37
37
|
dist/
|
|
38
|
-
├──
|
|
39
|
-
├──
|
|
40
|
-
├── assets/
|
|
41
|
-
└── functions/
|
|
38
|
+
├── _worker.js # Main SSR worker
|
|
39
|
+
├── _routes.json # Route manifest for edge routing
|
|
40
|
+
├── assets/ # Static assets and prerendered pages
|
|
41
|
+
└── functions/ # Mini-workers for API routes (if functions: true)
|
|
42
42
|
├── api-hello.js
|
|
43
43
|
└── api-users.js
|
|
44
44
|
```
|
|
@@ -50,7 +50,7 @@ When `functions: true`, the adapter generates a separate mini-worker for each `+
|
|
|
50
50
|
- `/api/hello/+server.ts` → `functions/api-hello.js`
|
|
51
51
|
- `/api/users/+server.ts` → `functions/api-users.js`
|
|
52
52
|
|
|
53
|
-
The route mappings are included in `
|
|
53
|
+
The route mappings are included in `_routes.json`:
|
|
54
54
|
|
|
55
55
|
```js
|
|
56
56
|
{
|
package/files/function-worker.js
CHANGED
|
@@ -5,42 +5,86 @@
|
|
|
5
5
|
|
|
6
6
|
import * as handlers from 'ENDPOINT';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Extract route params from URL pathname based on SvelteKit route pattern
|
|
10
|
+
* @param {string} pathname - URL pathname (e.g., "/stream/42")
|
|
11
|
+
* @param {string} pattern - SvelteKit route pattern (e.g., "/stream/[n]")
|
|
12
|
+
* @returns {Record<string, string>} - Extracted params (e.g., {n: "42"})
|
|
13
|
+
*/
|
|
14
|
+
function extractParams(pathname, pattern) {
|
|
15
|
+
const params = {};
|
|
16
|
+
const patternSegments = pattern.split('/').filter(Boolean);
|
|
17
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < patternSegments.length; i++) {
|
|
20
|
+
const patternSegment = patternSegments[i];
|
|
21
|
+
|
|
22
|
+
// Rest parameter: [...rest]
|
|
23
|
+
if (patternSegment.startsWith('[...') && patternSegment.endsWith(']')) {
|
|
24
|
+
const paramName = patternSegment.slice(4, -1);
|
|
25
|
+
params[paramName] = pathSegments.slice(i).join('/');
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Optional parameter: [[optional]]
|
|
30
|
+
if (patternSegment.startsWith('[[') && patternSegment.endsWith(']]')) {
|
|
31
|
+
const paramName = patternSegment.slice(2, -2);
|
|
32
|
+
if (i < pathSegments.length) {
|
|
33
|
+
params[paramName] = pathSegments[i];
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Regular parameter: [param]
|
|
39
|
+
if (patternSegment.startsWith('[') && patternSegment.endsWith(']')) {
|
|
40
|
+
const paramName = patternSegment.slice(1, -1);
|
|
41
|
+
params[paramName] = pathSegments[i];
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return params;
|
|
47
|
+
}
|
|
48
|
+
|
|
8
49
|
export default {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
async fetch(req, env, ctx) {
|
|
51
|
+
globalThis.env = env;
|
|
52
|
+
|
|
53
|
+
const method = req.method;
|
|
54
|
+
const handler = handlers[method];
|
|
55
|
+
|
|
56
|
+
if (!handler) {
|
|
57
|
+
return new Response('Method Not Allowed', {
|
|
58
|
+
status: 405,
|
|
59
|
+
headers: { Allow: Object.keys(handlers).join(', ') }
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const url = new URL(req.url);
|
|
64
|
+
|
|
65
|
+
// Extract params from URL based on route pattern
|
|
66
|
+
const params = extractParams(url.pathname, ROUTE_PATTERN);
|
|
67
|
+
|
|
68
|
+
// Build a minimal RequestEvent-like object
|
|
69
|
+
const event = {
|
|
70
|
+
request: req,
|
|
71
|
+
url,
|
|
72
|
+
params,
|
|
73
|
+
platform: { env, ctx },
|
|
74
|
+
getClientAddress() {
|
|
75
|
+
return req.headers.get('x-real-ip') ?? req.headers.get('x-forwarded-for') ?? '';
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
return await handler(event);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(`[Function] Error in ${method} handler:`, error);
|
|
83
|
+
|
|
84
|
+
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
|
|
85
|
+
status: 500,
|
|
86
|
+
headers: { 'Content-Type': 'application/json' }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
46
90
|
};
|
|
@@ -6,36 +6,36 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
export class AsyncLocalStorage {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
9
|
+
#store;
|
|
10
|
+
|
|
11
|
+
run(store, fn, ...args) {
|
|
12
|
+
this.#store = store;
|
|
13
|
+
return fn(...args);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getStore() {
|
|
17
|
+
return this.#store;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Stubs for API completeness
|
|
21
|
+
enterWith(store) {
|
|
22
|
+
this.#store = store;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exit(fn, ...args) {
|
|
26
|
+
this.#store = undefined;
|
|
27
|
+
return fn(...args);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
disable() {
|
|
31
|
+
this.#store = undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static bind(fn) {
|
|
35
|
+
return fn;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static snapshot() {
|
|
39
|
+
return (fn, ...args) => fn(...args);
|
|
40
|
+
}
|
|
41
41
|
}
|
package/index.js
CHANGED
|
@@ -91,15 +91,18 @@ export default function (options = {}) {
|
|
|
91
91
|
if (functionsEnabled) {
|
|
92
92
|
builder.mkdirp(`${dest}/functions`);
|
|
93
93
|
|
|
94
|
-
const
|
|
94
|
+
const serverDir = builder.getServerDirectory();
|
|
95
|
+
const viteManifestPath = path.join(serverDir, '.vite/manifest.json');
|
|
95
96
|
const functionTemplate = posixify(path.resolve(files, 'function-worker.js'));
|
|
96
97
|
|
|
97
|
-
if (existsSync(
|
|
98
|
-
const
|
|
98
|
+
if (existsSync(viteManifestPath)) {
|
|
99
|
+
const viteManifest = JSON.parse(readFileSync(viteManifestPath, 'utf-8'));
|
|
100
|
+
const endpoints = extractEndpointsFromManifest(viteManifest, serverDir);
|
|
99
101
|
|
|
100
102
|
for (const endpoint of endpoints) {
|
|
101
|
-
const routePattern = endpoint.
|
|
102
|
-
|
|
103
|
+
const routePattern = endpoint.pattern;
|
|
104
|
+
// Use SvelteKit route syntax for worker filename
|
|
105
|
+
const workerName = endpoint.route.replace(/\//g, '-').replace(/^-/, '') || 'index';
|
|
103
106
|
const workerFile = `functions/${workerName}.js`;
|
|
104
107
|
|
|
105
108
|
// Bundle using the template with ENDPOINT alias
|
|
@@ -115,6 +118,9 @@ export default function (options = {}) {
|
|
|
115
118
|
},
|
|
116
119
|
external: ['node:*'],
|
|
117
120
|
minify: false,
|
|
121
|
+
define: {
|
|
122
|
+
ROUTE_PATTERN: JSON.stringify(endpoint.route)
|
|
123
|
+
},
|
|
118
124
|
banner: {
|
|
119
125
|
js: `// Generated by ${name} v${version} - Function: ${routePattern}\n`
|
|
120
126
|
}
|
|
@@ -162,30 +168,72 @@ export default function (options = {}) {
|
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
/**
|
|
165
|
-
*
|
|
166
|
-
* @param {
|
|
167
|
-
* @param {string}
|
|
168
|
-
* @returns {Array<{route: string, file: string}>}
|
|
171
|
+
* Extract endpoints from Vite manifest and convert SvelteKit routes to simple patterns
|
|
172
|
+
* @param {object} manifest - Vite manifest object
|
|
173
|
+
* @param {string} serverDir - Server build directory
|
|
174
|
+
* @returns {Array<{pattern: string, route: string, file: string}>}
|
|
169
175
|
*/
|
|
170
|
-
function
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
176
|
+
function extractEndpointsFromManifest(manifest, serverDir) {
|
|
177
|
+
const endpoints = [];
|
|
178
|
+
|
|
179
|
+
for (const [key, entry] of Object.entries(manifest)) {
|
|
180
|
+
// Only process endpoint files (+server.ts)
|
|
181
|
+
if (!key.includes('+server.ts')) continue;
|
|
182
|
+
|
|
183
|
+
const sourcePath = entry.src;
|
|
184
|
+
if (!sourcePath || !sourcePath.startsWith('src/routes/')) continue;
|
|
185
|
+
|
|
186
|
+
// Extract route from source path: src/routes/status/[code]/[[reason]]/+server.ts
|
|
187
|
+
const routePart = sourcePath
|
|
188
|
+
.replace(/^src\/routes/, '')
|
|
189
|
+
.replace(/\/\+server\.(ts|js)$/, '');
|
|
190
|
+
|
|
191
|
+
// Convert SvelteKit route syntax to simple wildcard patterns
|
|
192
|
+
const pattern = convertRouteToPattern(routePart);
|
|
193
|
+
|
|
194
|
+
// Get the built file path
|
|
195
|
+
const file = path.join(serverDir, entry.file);
|
|
196
|
+
|
|
197
|
+
endpoints.push({
|
|
198
|
+
pattern, // For routing: /status/*/*
|
|
199
|
+
route: routePart, // For filename: /status/[code]/[[reason]]
|
|
200
|
+
file
|
|
201
|
+
});
|
|
186
202
|
}
|
|
187
203
|
|
|
188
|
-
return
|
|
204
|
+
return endpoints;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Convert SvelteKit route syntax to simple wildcard patterns
|
|
209
|
+
* Examples:
|
|
210
|
+
* /status/[code]/[[reason]] becomes /status/star/star
|
|
211
|
+
* /range/[n] becomes /range/star
|
|
212
|
+
* /drip/[...params] becomes /drip/doublestar
|
|
213
|
+
* @param {string} route - SvelteKit route (e.g. "/status/[code]/[[reason]]")
|
|
214
|
+
* @returns {string} - Simple pattern with wildcards
|
|
215
|
+
*/
|
|
216
|
+
function convertRouteToPattern(route) {
|
|
217
|
+
if (!route || route === '/') return '/';
|
|
218
|
+
|
|
219
|
+
const segments = route.split('/').filter(Boolean);
|
|
220
|
+
const patternSegments = segments.map(segment => {
|
|
221
|
+
// Rest parameter: [...params] -> **
|
|
222
|
+
if (segment.startsWith('[...') && segment.endsWith(']')) {
|
|
223
|
+
return '**';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Required or optional parameter: [param] or [[param]] -> *
|
|
227
|
+
if ((segment.startsWith('[') && segment.endsWith(']')) ||
|
|
228
|
+
(segment.startsWith('[[') && segment.endsWith(']]'))) {
|
|
229
|
+
return '*';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Static segment: keep as-is
|
|
233
|
+
return segment;
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return '/' + patternSegments.join('/');
|
|
189
237
|
}
|
|
190
238
|
|
|
191
239
|
/** @param {string} str */
|