@vesk/adapter 0.2.86 → 0.2.88

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.
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAA2B,MAAM,yBAAyB,CAAC;AAS5F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgDhG;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CA8C5E"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAA2B,MAAM,yBAAyB,CAAC;AAS5F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0EhG;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAwE5E"}
@@ -41,13 +41,39 @@ export function compileMiddleware(mwChain, _appDir) {
41
41
  ' nextResult = await run(index + 1);',
42
42
  ' return nextResult;',
43
43
  ' }',
44
- ' const result = await fn(ctx, next);',
45
- ' if (result instanceof Response) return result;',
46
- ' if (nextResult instanceof Response) return nextResult;',
47
- ' if (!nextCalled) return run(index + 1);',
48
- ' return null;',
44
+ ' try {',
45
+ ' const result = await fn(ctx, next);',
46
+ ' if (result instanceof Response) return result;',
47
+ ' if (nextResult instanceof Response) return nextResult;',
48
+ ' if (!nextCalled) return run(index + 1);',
49
+ ' return null;',
50
+ ' } catch (e) {',
51
+ ' if (e && typeof e === \'object\' && e.name === \'Redirect\') {',
52
+ ' return new Response(null, {',
53
+ ' status: Number(e.status) || 302,',
54
+ ' headers: { Location: String(e.url || \'\') },',
55
+ ' });',
56
+ ' }',
57
+ ' if (e instanceof TypeError && /Failed to parse URL from/.test(String(e.message))) {',
58
+ ' const msg = String(e.message);',
59
+ ' const prefix = \'Failed to parse URL from \';',
60
+ ' const start = msg.indexOf(prefix);',
61
+ ' const target = start === -1 ? \'\' : msg.slice(start + prefix.length).trim().split(\' \')[0];',
62
+ ' return new Response(null, { status: 302, headers: { Location: target } });',
63
+ ' }',
64
+ ' throw e;',
65
+ ' }',
66
+ ' }',
67
+ ' let response = null;',
68
+ ' try {',
69
+ ' response = await run(0);',
70
+ ' } catch (e) {',
71
+ ' // Unexpected middleware errors must not crash the server. On serverless',
72
+ ' // platforms (Vercel, Netlify, Cloudflare) an uncaught throw surfaces as',
73
+ ' // FUNCTION_INVOCATION_FAILED — Next.js avoids this by wrapping entry',
74
+ ' // points the same way. Convert it into a 500 response.',
75
+ ' response = new Response(null, { status: 500 });',
49
76
  ' }',
50
- ' const response = await run(0);',
51
77
  ' return { response, rewriteUrl };',
52
78
  '}',
53
79
  '',
@@ -87,13 +113,39 @@ export function compileMiddlewareCode(mwSourceTexts) {
87
113
  ' ncResult = await run(index + 1);',
88
114
  ' return ncResult;',
89
115
  ' }',
90
- ' const result = await fn(ctx, next);',
91
- ' if (result instanceof Response) return result;',
92
- ' if (ncResult instanceof Response) return ncResult;',
93
- ' if (!nc) return run(index + 1);',
94
- ' return null;',
116
+ ' try {',
117
+ ' const result = await fn(ctx, next);',
118
+ ' if (result instanceof Response) return result;',
119
+ ' if (ncResult instanceof Response) return ncResult;',
120
+ ' if (!nc) return run(index + 1);',
121
+ ' return null;',
122
+ ' } catch (e) {',
123
+ ' if (e && typeof e === \'object\' && e.name === \'Redirect\') {',
124
+ ' return new Response(null, {',
125
+ ' status: Number(e.status) || 302,',
126
+ ' headers: { Location: String(e.url || \'\') },',
127
+ ' });',
128
+ ' }',
129
+ ' if (e instanceof TypeError && /Failed to parse URL from/.test(String(e.message))) {',
130
+ ' const msg = String(e.message);',
131
+ ' const prefix = \'Failed to parse URL from \';',
132
+ ' const start = msg.indexOf(prefix);',
133
+ ' const target = start === -1 ? \'\' : msg.slice(start + prefix.length).trim().split(\' \')[0];',
134
+ ' return new Response(null, { status: 302, headers: { Location: target } });',
135
+ ' }',
136
+ ' throw e;',
137
+ ' }',
138
+ ' }',
139
+ ' let response = null;',
140
+ ' try {',
141
+ ' response = await run(0);',
142
+ ' } catch (e) {',
143
+ ' // Unexpected middleware errors must not crash the server. On serverless',
144
+ ' // platforms (Vercel, Netlify, Cloudflare) an uncaught throw surfaces as',
145
+ ' // FUNCTION_INVOCATION_FAILED — Next.js avoids this by wrapping entry',
146
+ ' // points the same way. Convert it into a 500 response.',
147
+ ' response = new Response(null, { status: 500 });',
95
148
  ' }',
96
- ' const response = await run(0);',
97
149
  ' return { response, rewriteUrl };',
98
150
  '}',
99
151
  '',
@@ -1 +1 @@
1
- {"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AASvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAgBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CA8MjF;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4GzF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB"}
1
+ {"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AASvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAgBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CA8OjF;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4GzF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB"}
@@ -47,6 +47,17 @@ export function generatePlatformHandlerSource(input) {
47
47
  const hasEvents = !!input.hasEvents;
48
48
  let imports = '';
49
49
  const routeEntries = [];
50
+ const routeSpecificity = (path) => {
51
+ if (/:path\b|:rest\b|\[\.\.\./.test(path))
52
+ return 3; // catch-all
53
+ if (/:/.test(path))
54
+ return 2; // dynamic param
55
+ return 1; // static
56
+ };
57
+ const pushEntry = (path, type, handler, extra) => {
58
+ const entry = `{ path: ${JSON.stringify(path)}, type: '${type}', handler: ${handler}${extra}}`;
59
+ routeEntries.push({ path, entry, specificity: routeSpecificity(path) });
60
+ };
50
61
  for (const r of ssrRoutes) {
51
62
  const name = routeName(r.fullPath.split('/').filter(Boolean));
52
63
  const id = `__ssr_${toId(name)}`;
@@ -54,15 +65,16 @@ export function generatePlatformHandlerSource(input) {
54
65
  imports += `import { handle as ${id} } from ${JSON.stringify(funcPath)};\n`;
55
66
  const revalidate = r._revalidate != null ? `revalidate: ${r._revalidate}, ` : '';
56
67
  const tags = r._isrTags ? `tags: ${JSON.stringify(r._isrTags)}, ` : '';
57
- routeEntries.push(`{ path: ${JSON.stringify(r.fullPath)}, type: 'ssr', handler: ${id}, ${revalidate}${tags}}`);
68
+ pushEntry(r.fullPath, 'ssr', id, `, ${revalidate}${tags}`);
58
69
  }
59
70
  for (const r of apiRoutes) {
60
71
  const name = apiRouteName(r.fullPath);
61
72
  const id = `__api_${toId(name)}`;
62
73
  const funcPath = `./server/api/${name}.js`;
63
74
  imports += `import { handle as ${id} } from ${JSON.stringify(funcPath)};\n`;
64
- routeEntries.push(`{ path: ${JSON.stringify('/api' + r.fullPath)}, type: 'api', handler: ${id} }`);
75
+ pushEntry('/api' + r.fullPath, 'api', id, '');
65
76
  }
77
+ routeEntries.sort((a, b) => a.specificity - b.specificity);
66
78
  const mwImport = hasMiddleware ? "import { execute as __executeMw } from './server/middleware.js';" : '';
67
79
  const hasMwLiteral = hasMiddleware ? 'true' : 'false';
68
80
  const eventsImport = hasEvents ? "import { executeStart as __eventsStart, executeRequest as __eventsRequest } from './server/events.js';" : '';
@@ -87,7 +99,7 @@ ${eventsImport}
87
99
  ${prerenderedList}
88
100
  ${isrCache}
89
101
  ${defaultNotFoundLine}
90
- const __routes = [${routeEntries.join(',\n')}];
102
+ const __routes = [${routeEntries.map((e) => e.entry).join(',\n')}];
91
103
 
92
104
  async function __invokeRoute(route, request) {
93
105
  try {
@@ -139,9 +151,10 @@ function __matchPath(pattern, pathname) {
139
151
  }
140
152
 
141
153
  export async function handleRequest(request) {
142
- const url = new URL(request.url);
143
- const pathname = url.pathname;
144
- const isDataRequest = request.headers.get('x-vesk-data') === '1';
154
+ try {
155
+ const url = new URL(request.url);
156
+ const pathname = url.pathname;
157
+ const isDataRequest = request.headers.get('x-vesk-data') === '1';
145
158
  ${serverStoreLine}
146
159
 
147
160
  if (__prerendered.has(pathname) && !isDataRequest) {
@@ -236,6 +249,17 @@ ${eventsRequestLine}
236
249
  status: 404,
237
250
  headers: { 'Content-Type': 'text/html' },
238
251
  });
252
+ } catch (e) {
253
+ // Any error that escapes the route (a thrown exception, a bad import, a
254
+ // middleware failure, ...) must not bubble out of handleRequest. On
255
+ // serverless platforms (Vercel, Netlify, Cloudflare) an uncaught throw is
256
+ // surfaced as FUNCTION_INVOCATION_FAILED — Next.js avoids this by wrapping
257
+ // its entry points the same way. Convert it into a proper 500 response.
258
+ return new Response(renderDefaultErrorPage({ url: request.url }), {
259
+ status: 500,
260
+ headers: { 'Content-Type': 'text/html' },
261
+ });
262
+ }
239
263
  }
240
264
  `;
241
265
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/adapter",
3
- "version": "0.2.86",
3
+ "version": "0.2.88",
4
4
  "type": "module",
5
5
  "description": "Vesk adapter — builds deployable .vesk/ output for Deno and Node serverless",
6
6
  "main": "./dist/index.js",
@@ -23,9 +23,9 @@
23
23
  "sharp": "^0.35.3"
24
24
  },
25
25
  "dependencies": {
26
- "@vesk/compiler": "^0.2.86",
27
- "@vesk/runtime": "^0.2.86",
28
- "@vesk/types": "^0.2.86"
26
+ "@vesk/compiler": "^0.2.88",
27
+ "@vesk/runtime": "^0.2.88",
28
+ "@vesk/types": "^0.2.88"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/ws": "^8.18.1",