@vercel/node 2.14.5 → 2.15.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/dist/edge-functions/edge-handler-template.js +28 -10
- package/dist/edge-functions/edge-handler.mjs +2 -7
- package/dist/index.js +6 -1
- package/dist/serverless-functions/helpers-web.d.ts +7 -0
- package/dist/serverless-functions/helpers-web.js +62 -0
- package/dist/serverless-functions/helpers.js +9 -2
- package/dist/serverless-functions/serverless-handler.mjs +31 -13
- package/dist/utils.js +5 -1
- package/package.json +3 -1
@@ -10,14 +10,14 @@ function getUrl(url, headers) {
|
|
10
10
|
return urlObj.toString();
|
11
11
|
}
|
12
12
|
|
13
|
-
async function respond(
|
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
|
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(
|
65
|
+
function registerFetchListener(module, options, dependencies) {
|
66
|
+
let handler;
|
67
|
+
|
66
68
|
addEventListener('fetch', async event => {
|
67
69
|
try {
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
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(
|
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
|
-
|
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
|
+
}
|
@@ -9,10 +9,17 @@ class ApiError extends Error {
|
|
9
9
|
this.statusCode = statusCode;
|
10
10
|
}
|
11
11
|
}
|
12
|
+
function normalizeContentType(contentType) {
|
13
|
+
if (!contentType) {
|
14
|
+
return 'text/plain';
|
15
|
+
}
|
16
|
+
const { parse: parseContentType } = require('content-type');
|
17
|
+
const { type } = parseContentType(contentType);
|
18
|
+
return type;
|
19
|
+
}
|
12
20
|
function getBodyParser(body, contentType) {
|
13
21
|
return function parseBody() {
|
14
|
-
const
|
15
|
-
const { type } = parseContentType(contentType);
|
22
|
+
const type = normalizeContentType(contentType);
|
16
23
|
if (type === 'application/json') {
|
17
24
|
try {
|
18
25
|
const str = body.toString();
|
@@ -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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
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 (
|
29
|
-
|
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
|
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
|
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
|
-
|
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.
|
3
|
+
"version": "2.15.1",
|
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",
|