@vercel/node 2.14.5 → 2.15.0

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.
@@ -10,14 +10,14 @@ function getUrl(url, headers) {
10
10
  return urlObj.toString();
11
11
  }
12
12
 
13
- async function respond(userEdgeHandler, event, options, dependencies) {
13
+ async function respond(handler, event, options, dependencies) {
14
14
  const { Request, Response } = dependencies;
15
15
  const { isMiddleware } = options;
16
16
  event.request.headers.set(
17
17
  'host',
18
18
  event.request.headers.get('x-forwarded-host')
19
19
  );
20
- let response = await userEdgeHandler(
20
+ let response = await handler(
21
21
  new Request(
22
22
  getUrl(event.request.url, event.request.headers),
23
23
  event.request
@@ -62,16 +62,34 @@ async function parseRequestEvent(event) {
62
62
 
63
63
  // This will be invoked by logic using this template
64
64
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
65
- function registerFetchListener(userEdgeHandler, options, dependencies) {
65
+ function registerFetchListener(module, options, dependencies) {
66
+ let handler;
67
+
66
68
  addEventListener('fetch', async event => {
67
69
  try {
68
- const response = await respond(
69
- userEdgeHandler,
70
- event,
71
- options,
72
- dependencies
73
- );
74
- return event.respondWith(response);
70
+ if (typeof module.default === 'function') {
71
+ handler = module.default;
72
+ } else {
73
+ if (
74
+ ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'DELETE', 'PATCH'].some(
75
+ method => typeof module[method] === 'function'
76
+ )
77
+ ) {
78
+ const method = event.request.method ?? 'GET';
79
+ handler =
80
+ typeof module[method] === 'function'
81
+ ? module[method]
82
+ : () => new dependencies.Response(null, { status: 405 });
83
+ }
84
+ }
85
+ if (!handler) {
86
+ const url = getUrl(event.request.url, event.request.headers);
87
+ throw new Error(
88
+ `No default or HTTP-named export was found at ${url}. Add one to handle requests. Learn more: https://vercel.link/creating-edge-middleware`
89
+ );
90
+ }
91
+ const response = await respond(handler, event, options, dependencies);
92
+ event.respondWith(response);
75
93
  } catch (error) {
76
94
  event.respondWith(toResponseError(error, dependencies.Response));
77
95
  }
@@ -57,12 +57,7 @@ async function compileUserCode(entrypointFullPath, entrypointRelativePath, isMid
57
57
 
58
58
  // user code
59
59
  ${compiledFile.text};
60
- const userEdgeHandler = module.exports.default;
61
- if (!userEdgeHandler) {
62
- throw new Error(
63
- 'No default export was found. Add a default export to handle requests. Learn more: https://vercel.link/creating-edge-middleware'
64
- );
65
- }
60
+ const userModule = module.exports;
66
61
 
67
62
  // request metadata
68
63
  const isMiddleware = ${isMiddleware};
@@ -72,7 +67,7 @@ async function compileUserCode(entrypointFullPath, entrypointRelativePath, isMid
72
67
  ${edgeHandlerTemplate};
73
68
  const dependencies = { Request, Response };
74
69
  const options = { isMiddleware, entrypointLabel };
75
- registerFetchListener(userEdgeHandler, options, dependencies);
70
+ registerFetchListener(userModule, options, dependencies);
76
71
  `;
77
72
  return {
78
73
  userCode,
package/dist/index.js CHANGED
@@ -139288,6 +139288,7 @@ const build = async ({ files, entrypoint, workPath, repoRootPath, config = {}, m
139288
139288
  shouldAddSourcemapSupport,
139289
139289
  awsLambdaHandler,
139290
139290
  supportsResponseStreaming,
139291
+ maxDuration: staticConfig?.maxDuration,
139291
139292
  });
139292
139293
  }
139293
139294
  return { routes, output };
@@ -139906,7 +139907,11 @@ function entrypointToOutputPath(entrypoint, zeroConfig) {
139906
139907
  }
139907
139908
  exports.entrypointToOutputPath = entrypointToOutputPath;
139908
139909
  function logError(error) {
139909
- console.error(error.message);
139910
+ let message = error.message;
139911
+ if (!message.startsWith('Error:')) {
139912
+ message = `Error: ${message}`;
139913
+ }
139914
+ console.error(message);
139910
139915
  if (error.stack) {
139911
139916
  // only show the stack trace if debug is enabled
139912
139917
  // because it points to internals, not user code
@@ -0,0 +1,7 @@
1
+ import type { ServerResponse, IncomingMessage } from 'http';
2
+ /**
3
+ * When users export at least one HTTP handler, we will generate
4
+ * a generic handler routing to the right method. If there is no
5
+ * handler function exported returns null.
6
+ */
7
+ export declare function getWebExportsHandler(listener: any, methods: string[]): (req: IncomingMessage, res: ServerResponse) => void;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWebExportsHandler = void 0;
4
+ const node_utils_1 = require("@edge-runtime/node-utils");
5
+ class FetchEvent {
6
+ constructor(request) {
7
+ this.request = request;
8
+ this.response = null;
9
+ this.awaiting = new Set();
10
+ }
11
+ respondWith(response) {
12
+ this.response = response;
13
+ }
14
+ waitUntil() {
15
+ throw new Error('waitUntil is not implemented yet for Node.js');
16
+ }
17
+ }
18
+ const webHandlerToNodeHandler = (0, node_utils_1.buildToNodeHandler)({
19
+ Headers,
20
+ ReadableStream,
21
+ Request: class extends Request {
22
+ constructor(input, init) {
23
+ super(input, addDuplexToInit(init));
24
+ }
25
+ },
26
+ Uint8Array: Uint8Array,
27
+ FetchEvent: FetchEvent,
28
+ }, { defaultOrigin: 'https://vercel.com' });
29
+ /**
30
+ * When users export at least one HTTP handler, we will generate
31
+ * a generic handler routing to the right method. If there is no
32
+ * handler function exported returns null.
33
+ */
34
+ function getWebExportsHandler(listener, methods) {
35
+ const handlerByMethod = {};
36
+ for (const key of methods) {
37
+ handlerByMethod[key] =
38
+ typeof listener[key] !== 'undefined'
39
+ ? webHandlerToNodeHandler(listener[key])
40
+ : defaultHttpHandler;
41
+ }
42
+ return (req, res) => {
43
+ const method = req.method ?? 'GET';
44
+ handlerByMethod[method](req, res);
45
+ };
46
+ }
47
+ exports.getWebExportsHandler = getWebExportsHandler;
48
+ /**
49
+ * Add `duplex: 'half'` by default to all requests
50
+ * https://github.com/vercel/edge-runtime/blob/bf167c418247a79d3941bfce4a5d43c37f512502/packages/primitives/src/primitives/fetch.js#L22-L26
51
+ * https://developer.chrome.com/articles/fetch-streaming-requests/#streaming-request-bodies
52
+ */
53
+ function addDuplexToInit(init) {
54
+ if (typeof init === 'undefined' || typeof init === 'object') {
55
+ return { duplex: 'half', ...init };
56
+ }
57
+ return init;
58
+ }
59
+ function defaultHttpHandler(_, res) {
60
+ res.statusCode = 405;
61
+ res.end();
62
+ }
@@ -7,32 +7,50 @@ import fetch from 'node-fetch';
7
7
  import { listen } from 'async-listen';
8
8
  import { isAbsolute } from 'path';
9
9
  import { pathToFileURL } from 'url';
10
- async function createServerlessServer(userCode, options) {
11
- const server = createServer(async (req, res) => {
12
- if (options.shouldAddHelpers)
13
- await addHelpers(req, res);
14
- return userCode(req, res);
15
- });
10
+ const [NODE_MAJOR] = process.versions.node.split('.').map(v => Number(v));
11
+ /* https://nextjs.org/docs/app/building-your-application/routing/router-handlers#supported-http-methods */
12
+ const HTTP_METHODS = [
13
+ 'GET',
14
+ 'HEAD',
15
+ 'OPTIONS',
16
+ 'POST',
17
+ 'PUT',
18
+ 'DELETE',
19
+ 'PATCH',
20
+ ];
21
+ async function createServerlessServer(userCode) {
22
+ const server = createServer(userCode);
16
23
  exitHook(() => server.close());
17
24
  return { url: await listen(server) };
18
25
  }
19
- async function compileUserCode(entrypointPath) {
26
+ async function compileUserCode(entrypointPath, options) {
20
27
  const id = isAbsolute(entrypointPath)
21
28
  ? pathToFileURL(entrypointPath).href
22
29
  : entrypointPath;
23
- let fn = await import(id);
30
+ let listener = await import(id);
24
31
  /**
25
32
  * In some cases we might have nested default props due to TS => JS
26
33
  */
27
34
  for (let i = 0; i < 5; i++) {
28
- if (fn.default)
29
- fn = fn.default;
35
+ if (listener.default)
36
+ listener = listener.default;
37
+ }
38
+ if (HTTP_METHODS.some(method => typeof listener[method] === 'function')) {
39
+ if (NODE_MAJOR < 18) {
40
+ throw new Error('Node.js v18 or above is required to use HTTP method exports in your functions.');
41
+ }
42
+ const { getWebExportsHandler } = await import('./helpers-web.js');
43
+ return getWebExportsHandler(listener, HTTP_METHODS);
30
44
  }
31
- return fn;
45
+ return async (req, res) => {
46
+ if (options.shouldAddHelpers)
47
+ await addHelpers(req, res);
48
+ return listener(req, res);
49
+ };
32
50
  }
33
51
  export async function createServerlessEventHandler(entrypointPath, options) {
34
- const userCode = await compileUserCode(entrypointPath);
35
- const server = await createServerlessServer(userCode, options);
52
+ const userCode = await compileUserCode(entrypointPath, options);
53
+ const server = await createServerlessServer(userCode);
36
54
  return async function (request) {
37
55
  const url = new URL(request.url ?? '/', server.url);
38
56
  // @ts-expect-error
package/dist/utils.js CHANGED
@@ -46,7 +46,11 @@ function entrypointToOutputPath(entrypoint, zeroConfig) {
46
46
  }
47
47
  exports.entrypointToOutputPath = entrypointToOutputPath;
48
48
  function logError(error) {
49
- console.error(error.message);
49
+ let message = error.message;
50
+ if (!message.startsWith('Error:')) {
51
+ message = `Error: ${message}`;
52
+ }
53
+ console.error(message);
50
54
  if (error.stack) {
51
55
  // only show the stack trace if debug is enabled
52
56
  // because it points to internals, not user code
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/node",
3
- "version": "2.14.5",
3
+ "version": "2.15.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -13,6 +13,8 @@
13
13
  "dist"
14
14
  ],
15
15
  "dependencies": {
16
+ "@edge-runtime/node-utils": "2.0.3",
17
+ "@edge-runtime/primitives": "2.1.2",
16
18
  "@edge-runtime/vm": "2.0.0",
17
19
  "@types/node": "14.18.33",
18
20
  "@types/node-fetch": "2.6.3",