@vercel/node 2.9.13 → 2.10.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.
@@ -2,9 +2,18 @@
2
2
  /* global addEventListener */
3
3
 
4
4
  function buildUrl(requestDetails) {
5
- let proto = requestDetails.headers['x-forwarded-proto'].split(/\b/).shift(); // handling multi-protocol like https,http://...
6
- let host = requestDetails.headers['x-forwarded-host'];
7
- let path = requestDetails.url;
5
+ const host = requestDetails.headers['x-forwarded-host'] || '127.0.0.1';
6
+ const path = requestDetails.url || '/';
7
+
8
+ const allProtocols = requestDetails.headers['x-forwarded-proto'];
9
+ let proto;
10
+ if (allProtocols) {
11
+ // handle multi-protocol like: https,http://...
12
+ proto = allProtocols.split(/\b/).shift();
13
+ } else {
14
+ proto = 'http';
15
+ }
16
+
8
17
  return `${proto}://${host}${path}`;
9
18
  }
10
19
 
@@ -16,7 +25,7 @@ async function respond(
16
25
  dependencies
17
26
  ) {
18
27
  const { Request, Response } = dependencies;
19
- const { isMiddleware, entrypointLabel } = options;
28
+ const { isMiddleware } = options;
20
29
 
21
30
  let body;
22
31
 
@@ -26,7 +35,7 @@ async function respond(
26
35
  }
27
36
  }
28
37
 
29
- let request = new Request(buildUrl(requestDetails), {
38
+ const request = new Request(buildUrl(requestDetails), {
30
39
  headers: requestDetails.headers,
31
40
  method: requestDetails.method,
32
41
  body: body,
@@ -45,9 +54,7 @@ async function respond(
45
54
  },
46
55
  });
47
56
  } else {
48
- throw new Error(
49
- `Edge Function "${entrypointLabel}" did not return a response.`
50
- );
57
+ throw new Error(`Edge Function did not return a response.`);
51
58
  }
52
59
  }
53
60
  return response;
@@ -68,8 +75,8 @@ function toResponseError(error, Response) {
68
75
  }
69
76
 
70
77
  async function parseRequestEvent(event) {
71
- let serializedRequest = await event.request.text();
72
- let requestDetails = JSON.parse(serializedRequest);
78
+ const serializedRequest = await event.request.text();
79
+ const requestDetails = JSON.parse(serializedRequest);
73
80
  return requestDetails;
74
81
  }
75
82
 
@@ -78,8 +85,8 @@ async function parseRequestEvent(event) {
78
85
  function registerFetchListener(userEdgeHandler, options, dependencies) {
79
86
  addEventListener('fetch', async event => {
80
87
  try {
81
- let requestDetails = await parseRequestEvent(event);
82
- let response = await respond(
88
+ const requestDetails = await parseRequestEvent(event);
89
+ const response = await respond(
83
90
  userEdgeHandler,
84
91
  requestDetails,
85
92
  event,
@@ -12,6 +12,7 @@ const node_fetch_1 = __importDefault(require("node-fetch"));
12
12
  const edge_wasm_plugin_1 = require("./edge-wasm-plugin");
13
13
  const utils_1 = require("../utils");
14
14
  const fs_1 = require("fs");
15
+ const edge_node_compat_plugin_1 = require("./edge-node-compat-plugin");
15
16
  const NODE_VERSION_MAJOR = process.version.match(/^v(\d+)\.\d+/)?.[1];
16
17
  const NODE_VERSION_IDENTIFIER = `node${NODE_VERSION_MAJOR}`;
17
18
  if (!NODE_VERSION_MAJOR) {
@@ -30,6 +31,7 @@ async function serializeRequest(message) {
30
31
  }
31
32
  async function compileUserCode(entrypointFullPath, entrypointRelativePath, isMiddleware) {
32
33
  const { wasmAssets, plugin: edgeWasmPlugin } = edge_wasm_plugin_1.createEdgeWasmPlugin();
34
+ const nodeCompatPlugin = edge_node_compat_plugin_1.createNodeCompatPlugin();
33
35
  try {
34
36
  const result = await esbuild_1.default.build({
35
37
  // bundling behavior: use globals (like "browser") instead
@@ -41,7 +43,7 @@ async function compileUserCode(entrypointFullPath, entrypointRelativePath, isMid
41
43
  sourcemap: 'inline',
42
44
  legalComments: 'none',
43
45
  bundle: true,
44
- plugins: [edgeWasmPlugin],
46
+ plugins: [edgeWasmPlugin, nodeCompatPlugin.plugin],
45
47
  entryPoints: [entrypointFullPath],
46
48
  write: false,
47
49
  format: 'cjs',
@@ -79,7 +81,11 @@ async function compileUserCode(entrypointFullPath, entrypointRelativePath, isMid
79
81
  };
80
82
  registerFetchListener(userEdgeHandler, options, dependencies);
81
83
  `;
82
- return { userCode, wasmAssets };
84
+ return {
85
+ userCode,
86
+ wasmAssets,
87
+ nodeCompatBindings: nodeCompatPlugin.bindings,
88
+ };
83
89
  }
84
90
  catch (error) {
85
91
  // We can't easily show a meaningful stack trace from ncc -> edge-runtime.
@@ -95,6 +101,7 @@ async function createEdgeRuntime(params) {
95
101
  return undefined;
96
102
  }
97
103
  const wasmBindings = await params.wasmAssets.getContext();
104
+ const nodeCompatBindings = params.nodeCompatBindings.getContext();
98
105
  const edgeRuntime = new edge_runtime_1.EdgeRuntime({
99
106
  initialCode: params.userCode,
100
107
  extend: (context) => {
@@ -107,6 +114,8 @@ async function createEdgeRuntime(params) {
107
114
  process: {
108
115
  env: process.env,
109
116
  },
117
+ // These are the global bindings for Node.js compatibility
118
+ ...nodeCompatBindings,
110
119
  // These are the global bindings for WebAssembly module
111
120
  ...wasmBindings,
112
121
  });
@@ -0,0 +1,15 @@
1
+ import type { Plugin } from 'esbuild';
2
+ export declare class NodeCompatBindings {
3
+ private bindings;
4
+ use(modulePath: `node:${string}`): string;
5
+ getContext(): Record<string, unknown>;
6
+ }
7
+ /**
8
+ * Allows to enable Node.js compatibility by detecting namespaced `node:`
9
+ * imports and producing metadata to bind global variables for each.
10
+ * It requires from the consumer to add the imports.
11
+ */
12
+ export declare function createNodeCompatPlugin(): {
13
+ plugin: Plugin;
14
+ bindings: NodeCompatBindings;
15
+ };
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createNodeCompatPlugin = exports.NodeCompatBindings = void 0;
7
+ const buffer_1 = __importDefault(require("buffer"));
8
+ const events_1 = __importDefault(require("events"));
9
+ const async_hooks_1 = __importDefault(require("async_hooks"));
10
+ const assert_1 = __importDefault(require("assert"));
11
+ const util_1 = __importDefault(require("util"));
12
+ const SUPPORTED_NODE_MODULES = [
13
+ 'buffer',
14
+ 'events',
15
+ 'assert',
16
+ 'util',
17
+ 'async_hooks',
18
+ ];
19
+ const getSupportedNodeModuleRegex = () => new RegExp(`^(?:node:)?(?:${SUPPORTED_NODE_MODULES.join('|')})$`);
20
+ function pick(obj, keys) {
21
+ const res = {};
22
+ for (const key of keys) {
23
+ res[key] = obj[key];
24
+ }
25
+ return res;
26
+ }
27
+ const NativeModuleMap = () => {
28
+ const mods = {
29
+ buffer: pick(buffer_1.default, [
30
+ 'constants',
31
+ 'kMaxLength',
32
+ 'kStringMaxLength',
33
+ 'Buffer',
34
+ 'SlowBuffer',
35
+ ]),
36
+ events: pick(events_1.default, [
37
+ 'EventEmitter',
38
+ 'captureRejectionSymbol',
39
+ 'defaultMaxListeners',
40
+ 'errorMonitor',
41
+ 'listenerCount',
42
+ 'on',
43
+ 'once',
44
+ ]),
45
+ async_hooks: pick(async_hooks_1.default, [
46
+ 'AsyncLocalStorage',
47
+ 'AsyncResource',
48
+ ]),
49
+ assert: pick(assert_1.default, [
50
+ 'AssertionError',
51
+ 'deepEqual',
52
+ 'deepStrictEqual',
53
+ 'doesNotMatch',
54
+ 'doesNotReject',
55
+ 'doesNotThrow',
56
+ 'equal',
57
+ 'fail',
58
+ 'ifError',
59
+ 'match',
60
+ 'notDeepEqual',
61
+ 'notDeepStrictEqual',
62
+ 'notEqual',
63
+ 'notStrictEqual',
64
+ 'ok',
65
+ 'rejects',
66
+ 'strict',
67
+ 'strictEqual',
68
+ 'throws',
69
+ ]),
70
+ util: pick(util_1.default, [
71
+ '_extend',
72
+ 'callbackify',
73
+ 'format',
74
+ 'inherits',
75
+ 'promisify',
76
+ 'types',
77
+ ]),
78
+ };
79
+ return new Map(Object.entries(mods));
80
+ };
81
+ const NODE_COMPAT_NAMESPACE = 'vercel-node-compat';
82
+ class NodeCompatBindings {
83
+ constructor() {
84
+ this.bindings = new Map();
85
+ }
86
+ use(modulePath) {
87
+ const stripped = modulePath.replace(/^node:/, '');
88
+ const name = `__vc_node_${stripped}__`;
89
+ if (!this.bindings.has(modulePath)) {
90
+ const value = NativeModuleMap().get(stripped);
91
+ if (value === undefined) {
92
+ throw new Error(`Could not find module ${modulePath}`);
93
+ }
94
+ this.bindings.set(modulePath, {
95
+ modulePath: modulePath,
96
+ name,
97
+ value,
98
+ });
99
+ }
100
+ return name;
101
+ }
102
+ getContext() {
103
+ const context = {};
104
+ for (const binding of this.bindings.values()) {
105
+ context[binding.name] = binding.value;
106
+ }
107
+ return context;
108
+ }
109
+ }
110
+ exports.NodeCompatBindings = NodeCompatBindings;
111
+ /**
112
+ * Allows to enable Node.js compatibility by detecting namespaced `node:`
113
+ * imports and producing metadata to bind global variables for each.
114
+ * It requires from the consumer to add the imports.
115
+ */
116
+ function createNodeCompatPlugin() {
117
+ const bindings = new NodeCompatBindings();
118
+ const plugin = {
119
+ name: 'vc-node-compat',
120
+ setup(b) {
121
+ b.onResolve({ filter: getSupportedNodeModuleRegex() }, async (args) => {
122
+ const importee = args.path.replace('node:', '');
123
+ if (!SUPPORTED_NODE_MODULES.includes(importee)) {
124
+ return;
125
+ }
126
+ return {
127
+ namespace: NODE_COMPAT_NAMESPACE,
128
+ path: args.path,
129
+ };
130
+ });
131
+ b.onLoad({ filter: /.+/, namespace: NODE_COMPAT_NAMESPACE }, async (args) => {
132
+ const fullName = args.path.startsWith('node:')
133
+ ? args.path
134
+ : `node:${args.path}`;
135
+ const globalName = bindings.use(fullName);
136
+ return {
137
+ contents: `module.exports = ${globalName};`,
138
+ loader: 'js',
139
+ };
140
+ });
141
+ },
142
+ };
143
+ return {
144
+ plugin,
145
+ bindings,
146
+ };
147
+ }
148
+ exports.createNodeCompatPlugin = createNodeCompatPlugin;
package/dist/index.js CHANGED
@@ -302075,7 +302075,9 @@ async function compile(workPath, baseDir, entrypointPath, config, nodeVersion, i
302075
302075
  shouldAddSourcemapSupport = true;
302076
302076
  return source;
302077
302077
  }
302078
- const conditions = isEdgeFunction ? ['worker', 'browser'] : undefined;
302078
+ const conditions = isEdgeFunction
302079
+ ? ['edge-light', 'browser', 'module', 'import', 'require']
302080
+ : undefined;
302079
302081
  const { fileList, esmFileList, warnings } = await nft_1.nodeFileTrace([...inputFiles], {
302080
302082
  base: baseDir,
302081
302083
  processCwd: workPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/node",
3
- "version": "2.9.13",
3
+ "version": "2.10.0",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -31,7 +31,7 @@
31
31
  "dependencies": {
32
32
  "@edge-runtime/vm": "2.0.0",
33
33
  "@types/node": "14.18.33",
34
- "@vercel/build-utils": "6.4.0",
34
+ "@vercel/build-utils": "6.5.0",
35
35
  "@vercel/node-bridge": "3.1.14",
36
36
  "@vercel/static-config": "2.0.14",
37
37
  "edge-runtime": "2.0.0",
@@ -64,5 +64,5 @@
64
64
  "test-listen": "1.1.0",
65
65
  "ts-morph": "12.0.0"
66
66
  },
67
- "gitHead": "b2c68f1301b6a5eb41b6261b7faac6a8fa4c53eb"
67
+ "gitHead": "6a7fa1526c6652c24350ef4797664a945775cf52"
68
68
  }