@vercel/node 2.4.4 → 2.5.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.
@@ -70,7 +70,7 @@ const static_config_1 = require("@vercel/static-config");
70
70
  const ts_morph_1 = require("ts-morph");
71
71
  const esbuild_1 = __importDefault(require("esbuild"));
72
72
  const node_fetch_1 = __importDefault(require("node-fetch"));
73
- const util_1 = require("util");
73
+ const edge_wasm_plugin_1 = require("./edge-wasm-plugin");
74
74
  function logError(error) {
75
75
  console.error(error.message);
76
76
  if (error.stack) {
@@ -126,24 +126,25 @@ async function serializeRequest(message) {
126
126
  body,
127
127
  });
128
128
  }
129
- async function compileUserCode(entrypoint) {
129
+ async function compileUserCode(entrypointPath, entrypointLabel) {
130
+ const { wasmAssets, plugin: edgeWasmPlugin } = edge_wasm_plugin_1.createEdgeWasmPlugin();
130
131
  try {
131
132
  const result = await esbuild_1.default.build({
132
133
  platform: 'node',
133
134
  target: 'node14',
134
135
  sourcemap: 'inline',
135
136
  bundle: true,
136
- entryPoints: [entrypoint],
137
+ plugins: [edgeWasmPlugin],
138
+ entryPoints: [entrypointPath],
137
139
  write: false,
138
140
  format: 'cjs',
139
141
  });
140
142
  const compiledFile = result.outputFiles?.[0];
141
143
  if (!compiledFile) {
142
- throw new Error(`Compilation of ${entrypoint} produced no output files.`);
144
+ throw new Error(`Compilation of ${entrypointLabel} produced no output files.`);
143
145
  }
144
- const userCode = new util_1.TextDecoder().decode(compiledFile.contents);
145
- return `
146
- ${userCode};
146
+ const userCode = `
147
+ ${compiledFile.text};
147
148
 
148
149
  addEventListener('fetch', async (event) => {
149
150
  try {
@@ -173,6 +174,10 @@ async function compileUserCode(entrypoint) {
173
174
 
174
175
  let response = await edgeHandler(event.request, event);
175
176
 
177
+ if (!response) {
178
+ throw new Error('Edge Function "${entrypointLabel}" did not return a response.');
179
+ }
180
+
176
181
  return event.respondWith(response);
177
182
  } catch (error) {
178
183
  // we can't easily show a meaningful stack trace
@@ -185,6 +190,7 @@ async function compileUserCode(entrypoint) {
185
190
  }));
186
191
  }
187
192
  })`;
193
+ return { userCode, wasmAssets };
188
194
  }
189
195
  catch (error) {
190
196
  // We can't easily show a meaningful stack trace from ncc -> edge-runtime.
@@ -194,20 +200,25 @@ async function compileUserCode(entrypoint) {
194
200
  return undefined;
195
201
  }
196
202
  }
197
- async function createEdgeRuntime(userCode) {
203
+ async function createEdgeRuntime(params) {
198
204
  try {
199
- if (!userCode) {
205
+ if (!params) {
200
206
  return undefined;
201
207
  }
208
+ const wasmBindings = await params.wasmAssets.getContext();
202
209
  const edgeRuntime = new edge_runtime_1.EdgeRuntime({
203
- initialCode: userCode,
210
+ initialCode: params.userCode,
204
211
  extend: (context) => {
205
212
  Object.assign(context, {
206
- __dirname: '',
207
- module: {
208
- exports: {},
213
+ // This is required for esbuild wrapping logic to resolve
214
+ module: {},
215
+ // This is required for environment variable access.
216
+ // In production, env var access is provided by static analysis
217
+ // so that only the used values are available.
218
+ process: {
219
+ env: process.env,
209
220
  },
210
- });
221
+ }, wasmBindings);
211
222
  return context;
212
223
  },
213
224
  });
@@ -223,8 +234,8 @@ async function createEdgeRuntime(userCode) {
223
234
  return undefined;
224
235
  }
225
236
  }
226
- async function createEdgeEventHandler(entrypoint) {
227
- const userCode = await compileUserCode(entrypoint);
237
+ async function createEdgeEventHandler(entrypointPath, entrypointLabel) {
238
+ const userCode = await compileUserCode(entrypointPath, entrypointLabel);
228
239
  const server = await createEdgeRuntime(userCode);
229
240
  return async function (request) {
230
241
  if (!server) {
@@ -266,15 +277,15 @@ function parseRuntime(entrypoint, entryPointPath) {
266
277
  return runtime;
267
278
  }
268
279
  async function createEventHandler(entrypoint, config, options) {
269
- const entryPointPath = path_1.join(process.cwd(), entrypoint);
270
- const runtime = parseRuntime(entrypoint, entryPointPath);
280
+ const entrypointPath = path_1.join(process.cwd(), entrypoint);
281
+ const runtime = parseRuntime(entrypoint, entrypointPath);
271
282
  // `middleware.js`/`middleware.ts` file is always run as
272
283
  // an Edge Function, otherwise needs to be opted-in via
273
284
  // `export const config = { runtime: 'experimental-edge' }`
274
285
  if (config.middleware === true || runtime === 'experimental-edge') {
275
- return createEdgeEventHandler(entryPointPath);
286
+ return createEdgeEventHandler(entrypointPath, entrypoint);
276
287
  }
277
- return createServerlessEventHandler(entryPointPath, options);
288
+ return createServerlessEventHandler(entrypointPath, options);
278
289
  }
279
290
  let handleEvent;
280
291
  let handlerEventError;
@@ -0,0 +1,21 @@
1
+ import type { Plugin } from 'esbuild';
2
+ export declare class WasmAssets {
3
+ private readonly assets;
4
+ /**
5
+ * Declare a WebAssembly binding
6
+ */
7
+ declare(filePath: string): Promise<string>;
8
+ /**
9
+ * Get an object with the context needed to execute the code
10
+ * built with the plugin
11
+ */
12
+ getContext(): Promise<Record<string, WebAssembly.Module>>;
13
+ /**
14
+ * Allow to iterate easily
15
+ */
16
+ [Symbol.iterator](): IterableIterator<[string, string]>;
17
+ }
18
+ export declare function createEdgeWasmPlugin(): {
19
+ plugin: Plugin;
20
+ wasmAssets: WasmAssets;
21
+ };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ // copied from `edge-functions-bridge`:
3
+ // https://github.com/vercel/runtimes/blob/c076db9e3ce5635f7c2690396e3d9f791a0fd808/packages/edge-functions-bridge/src/get-edge-function-source.ts#L282-L317
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.createEdgeWasmPlugin = exports.WasmAssets = void 0;
6
+ const crypto_1 = require("crypto");
7
+ const fs_1 = require("fs");
8
+ class WasmAssets {
9
+ constructor() {
10
+ this.assets = new Map();
11
+ }
12
+ /**
13
+ * Declare a WebAssembly binding
14
+ */
15
+ async declare(filePath) {
16
+ const hash = sha1(await fs_1.promises.readFile(filePath));
17
+ const name = `wasm_${hash}`;
18
+ this.assets.set(name, filePath);
19
+ return name;
20
+ }
21
+ /**
22
+ * Get an object with the context needed to execute the code
23
+ * built with the plugin
24
+ */
25
+ async getContext() {
26
+ const promises = [];
27
+ const context = {};
28
+ for (const [name, filePath] of this.assets) {
29
+ promises.push((async () => {
30
+ const bytes = await fs_1.promises.readFile(filePath);
31
+ context[name] = await WebAssembly.compile(bytes);
32
+ })());
33
+ }
34
+ await Promise.all(promises);
35
+ return context;
36
+ }
37
+ /**
38
+ * Allow to iterate easily
39
+ */
40
+ [Symbol.iterator]() {
41
+ return this.assets[Symbol.iterator]();
42
+ }
43
+ }
44
+ exports.WasmAssets = WasmAssets;
45
+ function createEdgeWasmPlugin() {
46
+ const wasmAssets = new WasmAssets();
47
+ const plugin = {
48
+ name: 'vercel-wasm',
49
+ setup(b) {
50
+ b.onResolve({ filter: /\.wasm\?module/i }, async (data) => {
51
+ const wasmFile = data.path.replace(/\?module$/, '');
52
+ const resolvedPath = await b.resolve(wasmFile, {
53
+ importer: data.importer,
54
+ resolveDir: data.resolveDir,
55
+ });
56
+ if (!resolvedPath.path) {
57
+ return {
58
+ errors: [
59
+ { text: `WebAssembly file could not be located: ${wasmFile}` },
60
+ ],
61
+ };
62
+ }
63
+ const name = await wasmAssets.declare(resolvedPath.path);
64
+ return {
65
+ path: name,
66
+ namespace: 'vercel-wasm',
67
+ };
68
+ });
69
+ b.onLoad({ namespace: 'vercel-wasm', filter: /.+/ }, args => {
70
+ return {
71
+ loader: 'js',
72
+ contents: `export default globalThis[${JSON.stringify(args.path)}]`,
73
+ };
74
+ });
75
+ },
76
+ };
77
+ return { plugin, wasmAssets };
78
+ }
79
+ exports.createEdgeWasmPlugin = createEdgeWasmPlugin;
80
+ function sha1(data) {
81
+ return crypto_1.createHash('sha1').update(data).digest('hex');
82
+ }