@netlify/edge-bundler 8.19.0 → 8.19.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/deno/bundle.ts CHANGED
@@ -3,4 +3,12 @@ import { writeStage2 } from './lib/stage2.ts'
3
3
  const [payload] = Deno.args
4
4
  const { basePath, destPath, externals, functions, importMapData } = JSON.parse(payload)
5
5
 
6
- await writeStage2({ basePath, destPath, externals, functions, importMapData })
6
+ try {
7
+ await writeStage2({ basePath, destPath, externals, functions, importMapData })
8
+ } catch (error) {
9
+ if (error instanceof Error && error.message.includes("The module's source code could not be parsed")) {
10
+ delete error.stack
11
+ }
12
+
13
+ throw error
14
+ }
package/deno/config.ts CHANGED
@@ -1,7 +1,9 @@
1
- const [functionURL, collectorURL, bootstrapURL, rawExitCodes] = Deno.args
1
+ // this needs to be updated whenever there's a change to globalThis.Netlify in bootstrap
2
+ import { Netlify } from "https://64e8753eae24930008fac6d9--edge.netlify.app/bootstrap/index-combined.ts"
3
+
4
+ const [functionURL, collectorURL, rawExitCodes] = Deno.args
2
5
  const exitCodes = JSON.parse(rawExitCodes)
3
6
 
4
- const { Netlify } = await import(bootstrapURL)
5
7
  globalThis.Netlify = Netlify
6
8
 
7
9
  let func
@@ -20,6 +20,10 @@ class BundleError extends Error {
20
20
  */
21
21
  const wrapBundleError = (input, options) => {
22
22
  if (input instanceof Error) {
23
+ if (input.message.includes("The module's source code could not be parsed")) {
24
+ // eslint-disable-next-line no-param-reassign
25
+ input.message = input.stderr;
26
+ }
23
27
  return new BundleError(input, options);
24
28
  }
25
29
  return input;
@@ -16,7 +16,7 @@ interface BundleOptions {
16
16
  internalSrcFolder?: string;
17
17
  bootstrapURL?: string;
18
18
  }
19
- declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths, onAfterDownload, onBeforeDownload, systemLogger, internalSrcFolder, bootstrapURL, }?: BundleOptions) => Promise<{
19
+ declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths, onAfterDownload, onBeforeDownload, systemLogger, internalSrcFolder, }?: BundleOptions) => Promise<{
20
20
  functions: import("./edge_function.js").EdgeFunction[];
21
21
  manifest: import("./manifest.js").Manifest;
22
22
  }>;
@@ -14,7 +14,7 @@ import { ImportMap } from './import_map.js';
14
14
  import { getLogger } from './logger.js';
15
15
  import { writeManifest } from './manifest.js';
16
16
  import { ensureLatestTypes } from './types.js';
17
- const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths = [], onAfterDownload, onBeforeDownload, systemLogger, internalSrcFolder, bootstrapURL = 'https://edge.netlify.com/bootstrap/index-combined.ts', } = {}) => {
17
+ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths = [], onAfterDownload, onBeforeDownload, systemLogger, internalSrcFolder, } = {}) => {
18
18
  const logger = getLogger(systemLogger, debug);
19
19
  const featureFlags = getFlags(inputFeatureFlags);
20
20
  const options = {
@@ -63,8 +63,8 @@ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], {
63
63
  await createFinalBundles([functionBundle], distDirectory, buildID);
64
64
  // Retrieving a configuration object for each function.
65
65
  // Run `getFunctionConfig` in parallel as it is a non-trivial operation and spins up deno
66
- const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig({ func, importMap, deno, log: logger, bootstrapURL })]);
67
- const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig({ func, importMap, deno, log: logger, bootstrapURL })]);
66
+ const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig({ func, importMap, deno, log: logger })]);
67
+ const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig({ func, importMap, deno, log: logger })]);
68
68
  // Creating a hash of function names to configuration objects.
69
69
  const internalFunctionsWithConfig = Object.fromEntries(await Promise.all(internalConfigPromises));
70
70
  const userFunctionsWithConfig = Object.fromEntries(await Promise.all(userConfigPromises));
@@ -68,7 +68,8 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
68
68
  await cleanup();
69
69
  });
70
70
  test('Adds a custom error property to user errors during bundling', async () => {
71
- expect.assertions(2);
71
+ process.env.NO_COLOR = 'true';
72
+ expect.assertions(3);
72
73
  const { basePath, cleanup, distPath } = await useFixture('invalid_functions');
73
74
  const sourceDirectory = join(basePath, 'functions');
74
75
  const declarations = [
@@ -82,6 +83,16 @@ test('Adds a custom error property to user errors during bundling', async () =>
82
83
  }
83
84
  catch (error) {
84
85
  expect(error).toBeInstanceOf(BundleError);
86
+ const [messageBeforeStack] = error.message.split('at <anonymous> (file://');
87
+ expect(messageBeforeStack).toMatchInlineSnapshot(`
88
+ "error: Uncaught (in promise) Error: The module's source code could not be parsed: Unexpected eof at file:///root/functions/func1.ts:1:27
89
+
90
+ export default async () =>
91
+ ~
92
+ const ret = new Error(getStringFromWasm0(arg0, arg1));
93
+ ^
94
+ "
95
+ `);
85
96
  expect(error.customErrorInfo).toEqual({
86
97
  location: {
87
98
  format: 'eszip',
@@ -19,10 +19,9 @@ export interface FunctionConfig {
19
19
  generator?: string;
20
20
  method?: HTTPMethod | HTTPMethod[];
21
21
  }
22
- export declare const getFunctionConfig: ({ func, importMap, deno, bootstrapURL, log, }: {
22
+ export declare const getFunctionConfig: ({ func, importMap, deno, log, }: {
23
23
  func: EdgeFunction;
24
24
  importMap: ImportMap;
25
25
  deno: DenoBridge;
26
- bootstrapURL: string;
27
26
  log: Logger;
28
27
  }) => Promise<FunctionConfig>;
@@ -26,7 +26,7 @@ const getConfigExtractor = () => {
26
26
  const configExtractorPath = join(packagePath, 'deno', 'config.ts');
27
27
  return configExtractorPath;
28
28
  };
29
- export const getFunctionConfig = async ({ func, importMap, deno, bootstrapURL, log, }) => {
29
+ export const getFunctionConfig = async ({ func, importMap, deno, log, }) => {
30
30
  // The extractor is a Deno script that will import the function and run its
31
31
  // `config` export, if one exists.
32
32
  const extractorPath = getConfigExtractor();
@@ -50,7 +50,6 @@ export const getFunctionConfig = async ({ func, importMap, deno, bootstrapURL, l
50
50
  extractorPath,
51
51
  pathToFileURL(func.path).href,
52
52
  pathToFileURL(collector.path).href,
53
- bootstrapURL,
54
53
  JSON.stringify(ConfigExitCode),
55
54
  ], { rejectOnExitCode: false });
56
55
  if (exitCode !== ConfigExitCode.Success) {
@@ -9,7 +9,6 @@ import { DenoBridge } from './bridge.js';
9
9
  import { bundle } from './bundler.js';
10
10
  import { getFunctionConfig } from './config.js';
11
11
  import { ImportMap } from './import_map.js';
12
- const bootstrapURL = 'https://edge.netlify.com/bootstrap/index-combined.ts';
13
12
  const importMapFile = {
14
13
  baseURL: new URL('file:///some/path/import-map.json'),
15
14
  imports: {
@@ -122,7 +121,6 @@ describe('`getFunctionConfig` extracts configuration properties from function fi
122
121
  importMap: new ImportMap([importMapFile]),
123
122
  deno,
124
123
  log: logger,
125
- bootstrapURL,
126
124
  });
127
125
  if (func.error) {
128
126
  await expect(funcCall()).rejects.toThrowError(func.error);
@@ -246,7 +244,6 @@ test('Passes validation if default export exists and is a function', async () =>
246
244
  importMap: new ImportMap([importMapFile]),
247
245
  deno,
248
246
  log: logger,
249
- bootstrapURL,
250
247
  })).resolves.not.toThrow();
251
248
  await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
252
249
  });
@@ -276,7 +273,6 @@ test('Fails validation if default export is not function', async () => {
276
273
  importMap: new ImportMap([importMapFile]),
277
274
  deno,
278
275
  log: logger,
279
- bootstrapURL,
280
276
  });
281
277
  await expect(config).rejects.toThrowError(invalidDefaultExportErr(path));
282
278
  await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
@@ -306,7 +302,6 @@ test('Fails validation if default export is not present', async () => {
306
302
  importMap: new ImportMap([importMapFile]),
307
303
  deno,
308
304
  log: logger,
309
- bootstrapURL,
310
305
  });
311
306
  await expect(config).rejects.toThrowError(invalidDefaultExportErr(path));
312
307
  await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
@@ -6,7 +6,7 @@ import { parse } from '@import-maps/resolve';
6
6
  import { isFileNotFoundError } from './utils/error.js';
7
7
  const INTERNAL_IMPORTS = {
8
8
  '@netlify/edge-functions': 'https://edge.netlify.com/v1/index.ts',
9
- 'netlify:edge': 'https://edge.netlify.com/v1/index.ts',
9
+ 'netlify:edge': 'https://edge.netlify.com/v1/index.ts?v=legacy',
10
10
  };
11
11
  // ImportMap can take several import map files and merge them into a final
12
12
  // import map object, also adding the internal imports in the right order.
@@ -21,7 +21,8 @@ test('Handles import maps with full URLs without specifying a base URL', () => {
21
21
  };
22
22
  const map = new ImportMap([inputFile1, inputFile2]);
23
23
  const { imports } = map.getContents();
24
- expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
24
+ expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts?v=legacy');
25
+ expect(imports['@netlify/edge-functions']).toBe('https://edge.netlify.com/v1/index.ts');
25
26
  expect(imports['alias:jamstack']).toBe('https://jamstack.org/');
26
27
  expect(imports['alias:pets']).toBe('https://petsofnetlify.com/');
27
28
  });
@@ -36,7 +37,8 @@ test('Resolves relative paths to absolute paths if a base path is not provided',
36
37
  const map = new ImportMap([inputFile1]);
37
38
  const { imports } = map.getContents();
38
39
  const expectedPath = join(cwd(), 'my-cool-site', 'heart', 'pets');
39
- expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
40
+ expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts?v=legacy');
41
+ expect(imports['@netlify/edge-functions']).toBe('https://edge.netlify.com/v1/index.ts');
40
42
  expect(imports['alias:pets']).toBe(`${pathToFileURL(expectedPath).toString()}/`);
41
43
  });
42
44
  describe('Returns the fully resolved import map', () => {
@@ -70,7 +72,7 @@ describe('Returns the fully resolved import map', () => {
70
72
  specifier2: 'file:///some/full/path/file2.js',
71
73
  specifier1: 'file:///some/full/path/file.js',
72
74
  '@netlify/edge-functions': 'https://edge.netlify.com/v1/index.ts',
73
- 'netlify:edge': 'https://edge.netlify.com/v1/index.ts',
75
+ 'netlify:edge': 'https://edge.netlify.com/v1/index.ts?v=legacy',
74
76
  });
75
77
  expect(scopes).toStrictEqual({
76
78
  'file:///some/cool/path/with/scopes/': {
@@ -92,7 +94,7 @@ describe('Returns the fully resolved import map', () => {
92
94
  specifier2: 'file:///root/full/path/file2.js',
93
95
  specifier1: 'file:///root/full/path/file.js',
94
96
  '@netlify/edge-functions': 'https://edge.netlify.com/v1/index.ts',
95
- 'netlify:edge': 'https://edge.netlify.com/v1/index.ts',
97
+ 'netlify:edge': 'https://edge.netlify.com/v1/index.ts?v=legacy',
96
98
  });
97
99
  expect(scopes).toStrictEqual({
98
100
  'file:///root/cool/path/with/scopes/': {
@@ -128,6 +130,7 @@ test('Writes import map file to disk', async () => {
128
130
  const { imports } = JSON.parse(createdFile);
129
131
  const expectedPath = join(cwd(), 'my-cool-site', 'heart', 'pets', 'file.ts');
130
132
  await file.cleanup();
131
- expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
133
+ expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts?v=legacy');
134
+ expect(imports['@netlify/edge-functions']).toBe('https://edge.netlify.com/v1/index.ts');
132
135
  expect(imports['alias:pets']).toBe(pathToFileURL(expectedPath).toString());
133
136
  });
@@ -43,7 +43,7 @@ const prepareServer = ({ bootstrapURL, deno, distDirectory, flags: denoFlags, fo
43
43
  });
44
44
  let functionsConfig = [];
45
45
  if (options.getFunctionsConfig) {
46
- functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig({ func, importMap, deno, bootstrapURL, log: logger })));
46
+ functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig({ func, importMap, deno, log: logger })));
47
47
  }
48
48
  const success = await waitForServer(port, processRef.ps);
49
49
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/edge-bundler",
3
- "version": "8.19.0",
3
+ "version": "8.19.1",
4
4
  "description": "Intelligently prepare Netlify Edge Functions for deployment",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.js",