@netlify/edge-bundler 8.14.0 → 8.14.2
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/node/bridge.test.js +3 -3
- package/dist/node/bundler.js +2 -2
- package/dist/node/bundler.test.js +20 -20
- package/dist/node/config.d.ts +1 -2
- package/dist/node/config.js +7 -22
- package/dist/node/config.test.js +11 -47
- package/dist/node/declaration.d.ts +1 -1
- package/dist/node/declaration.js +15 -25
- package/dist/node/declaration.test.js +1 -24
- package/dist/node/downloader.js +0 -1
- package/dist/node/downloader.test.js +1 -1
- package/dist/node/feature_flags.d.ts +0 -4
- package/dist/node/feature_flags.js +0 -2
- package/dist/node/formats/javascript.js +4 -5
- package/dist/node/main.test.js +1 -1
- package/dist/node/server/server.js +1 -1
- package/dist/node/stage_2.test.js +5 -6
- package/dist/node/types.test.js +3 -3
- package/package.json +3 -4
package/dist/node/bridge.test.js
CHANGED
|
@@ -53,7 +53,7 @@ test('Does not inherit environment variables if `extendEnv` is false', async ()
|
|
|
53
53
|
});
|
|
54
54
|
output = output.trim().replace(/\n+/g, '\n');
|
|
55
55
|
expect(output).toBe('LULU=LALA');
|
|
56
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
56
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
57
57
|
});
|
|
58
58
|
test('Does inherit environment variables if `extendEnv` is true', async () => {
|
|
59
59
|
var _a;
|
|
@@ -78,7 +78,7 @@ test('Does inherit environment variables if `extendEnv` is true', async () => {
|
|
|
78
78
|
// lets remove holes, split lines and sort lines by name, as different OSes might order them different
|
|
79
79
|
const environmentVariables = output.trim().replace(/\n+/g, '\n').split('\n').sort();
|
|
80
80
|
expect(environmentVariables).toEqual(['LULU=LALA', 'TADA=TUDU']);
|
|
81
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
81
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
82
82
|
});
|
|
83
83
|
test('Does inherit environment variables if `extendEnv` is not set', async () => {
|
|
84
84
|
var _a;
|
|
@@ -103,5 +103,5 @@ test('Does inherit environment variables if `extendEnv` is not set', async () =>
|
|
|
103
103
|
// lets remove holes, split lines and sort lines by name, as different OSes might order them different
|
|
104
104
|
const environmentVariables = output.trim().replace(/\n+/g, '\n').split('\n').sort();
|
|
105
105
|
expect(environmentVariables).toEqual(['LULU=LALA', 'TADA=TUDU']);
|
|
106
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
106
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
107
107
|
});
|
package/dist/node/bundler.js
CHANGED
|
@@ -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, logger
|
|
67
|
-
const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig(func, importMap, deno, logger
|
|
66
|
+
const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig(func, importMap, deno, logger)]);
|
|
67
|
+
const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig(func, importMap, deno, 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));
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { access, readdir, readFile, rm, writeFile } from 'fs/promises';
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import process from 'process';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
|
-
import { deleteAsync } from 'del';
|
|
6
5
|
import tmp from 'tmp-promise';
|
|
7
6
|
import { test, expect, vi } from 'vitest';
|
|
8
7
|
import { importMapSpecifier } from '../shared/consts.js';
|
|
@@ -26,10 +25,10 @@ test('Produces an ESZIP bundle', async () => {
|
|
|
26
25
|
configPath: join(internalDirectory, 'config.json'),
|
|
27
26
|
importMapPaths: [join(userDirectory, 'import_map.json')],
|
|
28
27
|
});
|
|
29
|
-
const generatedFiles = await
|
|
28
|
+
const generatedFiles = await readdir(distPath);
|
|
30
29
|
expect(result.functions.length).toBe(3);
|
|
31
30
|
expect(generatedFiles.length).toBe(2);
|
|
32
|
-
const manifestFile = await
|
|
31
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
33
32
|
const manifest = JSON.parse(manifestFile);
|
|
34
33
|
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
35
34
|
const { bundles, import_map: importMapURL } = manifest;
|
|
@@ -57,10 +56,10 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
|
|
|
57
56
|
basePath,
|
|
58
57
|
configPath: join(sourceDirectory, 'config.json'),
|
|
59
58
|
});
|
|
60
|
-
const generatedFiles = await
|
|
59
|
+
const generatedFiles = await readdir(distPath);
|
|
61
60
|
expect(result.functions.length).toBe(1);
|
|
62
61
|
expect(generatedFiles.length).toBe(2);
|
|
63
|
-
const manifestFile = await
|
|
62
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
64
63
|
const manifest = JSON.parse(manifestFile);
|
|
65
64
|
const { bundles } = manifest;
|
|
66
65
|
expect(bundles.length).toBe(1);
|
|
@@ -164,10 +163,10 @@ test('Uses the cache directory as the `DENO_DIR` value', async () => {
|
|
|
164
163
|
configPath: join(sourceDirectory, 'config.json'),
|
|
165
164
|
};
|
|
166
165
|
const result = await bundle([sourceDirectory], distPath, declarations, options);
|
|
167
|
-
const outFiles = await
|
|
166
|
+
const outFiles = await readdir(distPath);
|
|
168
167
|
expect(result.functions.length).toBe(1);
|
|
169
168
|
expect(outFiles.length).toBe(2);
|
|
170
|
-
const denoDir = await
|
|
169
|
+
const denoDir = await readdir(join(cacheDir.path, 'deno_dir'));
|
|
171
170
|
expect(denoDir.includes('gen')).toBe(true);
|
|
172
171
|
await cleanup();
|
|
173
172
|
});
|
|
@@ -184,10 +183,10 @@ test('Supports import maps with relative paths', async () => {
|
|
|
184
183
|
basePath,
|
|
185
184
|
configPath: join(sourceDirectory, 'config.json'),
|
|
186
185
|
});
|
|
187
|
-
const generatedFiles = await
|
|
186
|
+
const generatedFiles = await readdir(distPath);
|
|
188
187
|
expect(result.functions.length).toBe(1);
|
|
189
188
|
expect(generatedFiles.length).toBe(2);
|
|
190
|
-
const manifestFile = await
|
|
189
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
191
190
|
const manifest = JSON.parse(manifestFile);
|
|
192
191
|
const { bundles } = manifest;
|
|
193
192
|
expect(bundles.length).toBe(1);
|
|
@@ -212,7 +211,7 @@ test('Ignores any user-defined `deno.json` files', async () => {
|
|
|
212
211
|
'https://deno.land/': 'https://black.hole/',
|
|
213
212
|
},
|
|
214
213
|
};
|
|
215
|
-
await
|
|
214
|
+
await writeFile(importMapFile.path, JSON.stringify(importMap));
|
|
216
215
|
// Deno configuration files need to be in the current working directory.
|
|
217
216
|
// There's not a great way for us to set the working directory of the `deno`
|
|
218
217
|
// process that we'll run, so our best bet is to write the file to whatever
|
|
@@ -222,7 +221,7 @@ test('Ignores any user-defined `deno.json` files', async () => {
|
|
|
222
221
|
importMap: importMapFile.path,
|
|
223
222
|
};
|
|
224
223
|
try {
|
|
225
|
-
await
|
|
224
|
+
await access(denoConfigPath);
|
|
226
225
|
throw new Error(`The file at '${denoConfigPath} would be overwritten by this test. Please move the file to a different location and try again.'`);
|
|
227
226
|
}
|
|
228
227
|
catch (error) {
|
|
@@ -230,13 +229,14 @@ test('Ignores any user-defined `deno.json` files', async () => {
|
|
|
230
229
|
throw error;
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
|
-
await
|
|
232
|
+
await writeFile(denoConfigPath, JSON.stringify(denoConfig));
|
|
234
233
|
expect(() => bundle([sourceDirectory], distPath, declarations, {
|
|
235
234
|
basePath,
|
|
236
235
|
configPath: join(sourceDirectory, 'config.json'),
|
|
237
236
|
})).not.toThrow();
|
|
238
237
|
await cleanup();
|
|
239
|
-
await
|
|
238
|
+
await rm(denoConfigPath, { force: true, recursive: true, maxRetries: 10 });
|
|
239
|
+
await rm(importMapFile.path, { force: true, recursive: true, maxRetries: 10 });
|
|
240
240
|
});
|
|
241
241
|
test('Processes a function that imports a custom layer', async () => {
|
|
242
242
|
const { basePath, cleanup, distPath } = await useFixture('with_layers');
|
|
@@ -252,10 +252,10 @@ test('Processes a function that imports a custom layer', async () => {
|
|
|
252
252
|
basePath,
|
|
253
253
|
configPath: join(sourceDirectory, 'config.json'),
|
|
254
254
|
});
|
|
255
|
-
const generatedFiles = await
|
|
255
|
+
const generatedFiles = await readdir(distPath);
|
|
256
256
|
expect(result.functions.length).toBe(1);
|
|
257
257
|
expect(generatedFiles.length).toBe(2);
|
|
258
|
-
const manifestFile = await
|
|
258
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
259
259
|
const manifest = JSON.parse(manifestFile);
|
|
260
260
|
const { bundles, layers } = manifest;
|
|
261
261
|
expect(bundles.length).toBe(1);
|
|
@@ -278,10 +278,10 @@ test('Loads declarations and import maps from the deploy configuration and in-so
|
|
|
278
278
|
configPath: join(basePath, '.netlify', 'edge-functions', 'manifest.json'),
|
|
279
279
|
internalSrcFolder: directories[1],
|
|
280
280
|
});
|
|
281
|
-
const generatedFiles = await
|
|
281
|
+
const generatedFiles = await readdir(distPath);
|
|
282
282
|
expect(result.functions.length).toBe(3);
|
|
283
283
|
expect(generatedFiles.length).toBe(2);
|
|
284
|
-
const manifestFile = await
|
|
284
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
285
285
|
const manifest = JSON.parse(manifestFile);
|
|
286
286
|
const { bundles, function_config: functionConfig } = manifest;
|
|
287
287
|
expect(bundles.length).toBe(1);
|
|
@@ -317,7 +317,7 @@ test("Ignores entries in `importMapPaths` that don't point to an existing import
|
|
|
317
317
|
},
|
|
318
318
|
},
|
|
319
319
|
};
|
|
320
|
-
await
|
|
320
|
+
await writeFile(importMap.path, JSON.stringify(importMapContents));
|
|
321
321
|
const nonExistingImportMapPath = join(distPath, 'some-file-that-does-not-exist.json');
|
|
322
322
|
const result = await bundle([sourceDirectory], distPath, [
|
|
323
323
|
{
|
|
@@ -329,7 +329,7 @@ test("Ignores entries in `importMapPaths` that don't point to an existing import
|
|
|
329
329
|
importMapPaths: [nonExistingImportMapPath, importMap.path],
|
|
330
330
|
systemLogger,
|
|
331
331
|
});
|
|
332
|
-
const generatedFiles = await
|
|
332
|
+
const generatedFiles = await readdir(distPath);
|
|
333
333
|
expect(result.functions.length).toBe(2);
|
|
334
334
|
expect(generatedFiles.length).toBe(2);
|
|
335
335
|
expect(systemLogger).toHaveBeenCalledWith(`Did not find an import map file at '${nonExistingImportMapPath}'.`);
|
package/dist/node/config.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DenoBridge } from './bridge.js';
|
|
2
2
|
import { EdgeFunction } from './edge_function.js';
|
|
3
|
-
import { FeatureFlags } from './feature_flags.js';
|
|
4
3
|
import { ImportMap } from './import_map.js';
|
|
5
4
|
import { Logger } from './logger.js';
|
|
6
5
|
export declare const enum Cache {
|
|
@@ -18,4 +17,4 @@ export interface FunctionConfig {
|
|
|
18
17
|
name?: string;
|
|
19
18
|
generator?: string;
|
|
20
19
|
}
|
|
21
|
-
export declare const getFunctionConfig: (func: EdgeFunction, importMap: ImportMap, deno: DenoBridge, log: Logger
|
|
20
|
+
export declare const getFunctionConfig: (func: EdgeFunction, importMap: ImportMap, deno: DenoBridge, log: Logger) => Promise<FunctionConfig>;
|
package/dist/node/config.js
CHANGED
|
@@ -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, 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();
|
|
@@ -53,7 +53,7 @@ export const getFunctionConfig = async (func, importMap, deno, log, featureFlags
|
|
|
53
53
|
JSON.stringify(ConfigExitCode),
|
|
54
54
|
], { rejectOnExitCode: false });
|
|
55
55
|
if (exitCode !== ConfigExitCode.Success) {
|
|
56
|
-
handleConfigError(func, exitCode, stderr, log
|
|
56
|
+
handleConfigError(func, exitCode, stderr, log);
|
|
57
57
|
return {};
|
|
58
58
|
}
|
|
59
59
|
if (stdout !== '') {
|
|
@@ -65,7 +65,7 @@ export const getFunctionConfig = async (func, importMap, deno, log, featureFlags
|
|
|
65
65
|
collectorData = JSON.parse(collectorDataJSON);
|
|
66
66
|
}
|
|
67
67
|
catch {
|
|
68
|
-
handleConfigError(func, ConfigExitCode.UnhandledError, stderr, log
|
|
68
|
+
handleConfigError(func, ConfigExitCode.UnhandledError, stderr, log);
|
|
69
69
|
}
|
|
70
70
|
finally {
|
|
71
71
|
await collector.cleanup();
|
|
@@ -75,35 +75,20 @@ export const getFunctionConfig = async (func, importMap, deno, log, featureFlags
|
|
|
75
75
|
}
|
|
76
76
|
return collectorData;
|
|
77
77
|
};
|
|
78
|
-
const handleConfigError = (func, exitCode, stderr, log
|
|
78
|
+
const handleConfigError = (func, exitCode, stderr, log) => {
|
|
79
79
|
switch (exitCode) {
|
|
80
80
|
case ConfigExitCode.ImportError:
|
|
81
81
|
log.user(stderr);
|
|
82
|
-
|
|
83
|
-
throw new BundleError(new Error(`Could not load edge function at '${func.path}'. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
log.user(`Could not load edge function at '${func.path}'`);
|
|
87
|
-
}
|
|
82
|
+
throw new BundleError(new Error(`Could not load edge function at '${func.path}'. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
88
83
|
break;
|
|
89
84
|
case ConfigExitCode.NoConfig:
|
|
90
85
|
log.system(`No in-source config found for edge function at '${func.path}'`);
|
|
91
86
|
break;
|
|
92
87
|
case ConfigExitCode.InvalidExport:
|
|
93
|
-
|
|
94
|
-
throw new BundleError(new Error(`The 'config' export in edge function at '${func.path}' must be an object. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
log.user(`'config' export in edge function at '${func.path}' must be an object`);
|
|
98
|
-
}
|
|
88
|
+
throw new BundleError(new Error(`The 'config' export in edge function at '${func.path}' must be an object. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
99
89
|
break;
|
|
100
90
|
case ConfigExitCode.SerializationError:
|
|
101
|
-
|
|
102
|
-
throw new BundleError(new Error(`The 'config' object in the edge function at '${func.path}' must contain primitive values only. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
log.user(`'config' object in edge function at '${func.path}' must contain primitive values only`);
|
|
106
|
-
}
|
|
91
|
+
throw new BundleError(new Error(`The 'config' object in the edge function at '${func.path}' must contain primitive values only. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
107
92
|
break;
|
|
108
93
|
case ConfigExitCode.InvalidDefaultExport:
|
|
109
94
|
throw new BundleError(new Error(`Default export in '${func.path}' must be a function. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
package/dist/node/config.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
|
+
import { rm } from 'fs/promises';
|
|
2
3
|
import { join, resolve } from 'path';
|
|
3
4
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import { deleteAsync } from 'del';
|
|
5
5
|
import tmp from 'tmp-promise';
|
|
6
6
|
import { test, expect, vi, describe } from 'vitest';
|
|
7
7
|
import { fixturesDir, useFixture } from '../test/util.js';
|
|
@@ -34,8 +34,7 @@ const functions = [
|
|
|
34
34
|
`,
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
testName: 'config with wrong type
|
|
38
|
-
expectedConfig: {},
|
|
37
|
+
testName: 'config with wrong type',
|
|
39
38
|
name: 'func3',
|
|
40
39
|
source: `
|
|
41
40
|
export default async () => new Response("Hello from function two")
|
|
@@ -43,27 +42,9 @@ const functions = [
|
|
|
43
42
|
export const config = () => ({})
|
|
44
43
|
`,
|
|
45
44
|
error: /^The 'config' export in edge function at '(.*)' must be an object\. More on the Edge Functions API at https:\/\/ntl\.fyi\/edge-api\.$/,
|
|
46
|
-
featureFlags: {
|
|
47
|
-
edge_functions_invalid_config_throw: true,
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
testName: 'config with wrong type (log)',
|
|
52
|
-
expectedConfig: {},
|
|
53
|
-
name: 'func3',
|
|
54
|
-
source: `
|
|
55
|
-
export default async () => new Response("Hello from function two")
|
|
56
|
-
|
|
57
|
-
export const config = () => ({})
|
|
58
|
-
`,
|
|
59
|
-
userLog: /^'config' export in edge function at '(.*)' must be an object$/,
|
|
60
|
-
featureFlags: {
|
|
61
|
-
edge_functions_invalid_config_throw: false,
|
|
62
|
-
},
|
|
63
45
|
},
|
|
64
46
|
{
|
|
65
|
-
testName: 'config with syntax error
|
|
66
|
-
expectedConfig: {},
|
|
47
|
+
testName: 'config with syntax error',
|
|
67
48
|
name: 'func4',
|
|
68
49
|
source: `
|
|
69
50
|
export default async () => new Response("Hello from function two")
|
|
@@ -71,23 +52,6 @@ const functions = [
|
|
|
71
52
|
export const config
|
|
72
53
|
`,
|
|
73
54
|
error: /^Could not load edge function at '(.*)'\. More on the Edge Functions API at https:\/\/ntl\.fyi\/edge-api\.$/,
|
|
74
|
-
featureFlags: {
|
|
75
|
-
edge_functions_invalid_config_throw: true,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
testName: 'config with syntax error (log)',
|
|
80
|
-
expectedConfig: {},
|
|
81
|
-
name: 'func4',
|
|
82
|
-
source: `
|
|
83
|
-
export default async () => new Response("Hello from function two")
|
|
84
|
-
|
|
85
|
-
export const config
|
|
86
|
-
`,
|
|
87
|
-
userLog: /^Could not load edge function at '(.*)'$/,
|
|
88
|
-
featureFlags: {
|
|
89
|
-
edge_functions_invalid_config_throw: false,
|
|
90
|
-
},
|
|
91
55
|
},
|
|
92
56
|
{
|
|
93
57
|
testName: 'config with correct onError',
|
|
@@ -152,7 +116,7 @@ describe('`getFunctionConfig` extracts configuration properties from function fi
|
|
|
152
116
|
const funcCall = () => getFunctionConfig({
|
|
153
117
|
name: func.name,
|
|
154
118
|
path,
|
|
155
|
-
}, new ImportMap([importMapFile]), deno, logger
|
|
119
|
+
}, new ImportMap([importMapFile]), deno, logger);
|
|
156
120
|
if (func.error) {
|
|
157
121
|
await expect(funcCall()).rejects.toThrowError(func.error);
|
|
158
122
|
}
|
|
@@ -165,7 +129,7 @@ describe('`getFunctionConfig` extracts configuration properties from function fi
|
|
|
165
129
|
expect(config).toEqual(func.expectedConfig);
|
|
166
130
|
expect(logger.user).not.toHaveBeenCalled();
|
|
167
131
|
}
|
|
168
|
-
await
|
|
132
|
+
await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
|
|
169
133
|
});
|
|
170
134
|
});
|
|
171
135
|
test('Loads function paths from the in-source `config` function', async () => {
|
|
@@ -231,8 +195,8 @@ test('Passes validation if default export exists and is a function', async () =>
|
|
|
231
195
|
await expect(getFunctionConfig({
|
|
232
196
|
name: func.name,
|
|
233
197
|
path,
|
|
234
|
-
}, new ImportMap([importMapFile]), deno, logger
|
|
235
|
-
await
|
|
198
|
+
}, new ImportMap([importMapFile]), deno, logger)).resolves.not.toThrow();
|
|
199
|
+
await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
|
|
236
200
|
});
|
|
237
201
|
test('Fails validation if default export is not function', async () => {
|
|
238
202
|
const { path: tmpDir } = await tmp.dir();
|
|
@@ -255,9 +219,9 @@ test('Fails validation if default export is not function', async () => {
|
|
|
255
219
|
const config = getFunctionConfig({
|
|
256
220
|
name: func.name,
|
|
257
221
|
path,
|
|
258
|
-
}, new ImportMap([importMapFile]), deno, logger
|
|
222
|
+
}, new ImportMap([importMapFile]), deno, logger);
|
|
259
223
|
await expect(config).rejects.toThrowError(invalidDefaultExportErr(path));
|
|
260
|
-
await
|
|
224
|
+
await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
|
|
261
225
|
});
|
|
262
226
|
test('Fails validation if default export is not present', async () => {
|
|
263
227
|
const { path: tmpDir } = await tmp.dir();
|
|
@@ -279,7 +243,7 @@ test('Fails validation if default export is not present', async () => {
|
|
|
279
243
|
const config = getFunctionConfig({
|
|
280
244
|
name: func.name,
|
|
281
245
|
path,
|
|
282
|
-
}, new ImportMap([importMapFile]), deno, logger
|
|
246
|
+
}, new ImportMap([importMapFile]), deno, logger);
|
|
283
247
|
await expect(config).rejects.toThrowError(invalidDefaultExportErr(path));
|
|
284
|
-
await
|
|
248
|
+
await rm(tmpDir, { force: true, recursive: true, maxRetries: 10 });
|
|
285
249
|
});
|
|
@@ -15,6 +15,6 @@ type DeclarationWithPattern = BaseDeclaration & {
|
|
|
15
15
|
excludedPattern?: string;
|
|
16
16
|
};
|
|
17
17
|
export type Declaration = DeclarationWithPath | DeclarationWithPattern;
|
|
18
|
-
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[],
|
|
18
|
+
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[], _featureFlags?: FeatureFlags) => Declaration[];
|
|
19
19
|
export declare const parsePattern: (pattern: string) => string;
|
|
20
20
|
export {};
|
package/dist/node/declaration.js
CHANGED
|
@@ -1,30 +1,20 @@
|
|
|
1
1
|
import regexpAST from 'regexp-tree';
|
|
2
|
-
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations,
|
|
2
|
+
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations,
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
_featureFlags = {}) => {
|
|
3
5
|
const functionsVisited = new Set();
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// 4. Declarations from the users ISC
|
|
17
|
-
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
|
|
18
|
-
];
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
declarations = [
|
|
22
|
-
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
|
|
23
|
-
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
|
|
24
|
-
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
|
|
25
|
-
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
|
|
26
|
-
];
|
|
27
|
-
}
|
|
6
|
+
const declarations = [
|
|
7
|
+
// INTEGRATIONS
|
|
8
|
+
// 1. Declarations from the integrations deploy config
|
|
9
|
+
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
|
|
10
|
+
// 2. Declarations from the integrations ISC
|
|
11
|
+
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
|
|
12
|
+
// USER
|
|
13
|
+
// 3. Declarations from the users toml config
|
|
14
|
+
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
|
|
15
|
+
// 4. Declarations from the users ISC
|
|
16
|
+
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
|
|
17
|
+
];
|
|
28
18
|
return declarations;
|
|
29
19
|
};
|
|
30
20
|
const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsVisited) => {
|
|
@@ -18,30 +18,7 @@ test('Ensure the order of edge functions with FF', () => {
|
|
|
18
18
|
const internalFuncConfig = {
|
|
19
19
|
'framework-isc-c': { path: ['/path1', '/path2'] },
|
|
20
20
|
};
|
|
21
|
-
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations
|
|
22
|
-
edge_functions_correct_order: true,
|
|
23
|
-
})).toMatchSnapshot();
|
|
24
|
-
});
|
|
25
|
-
test('Ensure the order of edge functions without FF', () => {
|
|
26
|
-
const deployConfigDeclarations = [
|
|
27
|
-
{ function: 'framework-manifest-a', path: '/path1' },
|
|
28
|
-
{ function: 'framework-manifest-c', path: '/path3' },
|
|
29
|
-
{ function: 'framework-manifest-b', path: '/path2' },
|
|
30
|
-
];
|
|
31
|
-
const tomlConfig = [
|
|
32
|
-
{ function: 'user-toml-a', path: '/path1' },
|
|
33
|
-
{ function: 'user-toml-c', path: '/path3' },
|
|
34
|
-
{ function: 'user-toml-b', path: '/path2' },
|
|
35
|
-
];
|
|
36
|
-
const userFuncConfig = {
|
|
37
|
-
'user-isc-c': { path: ['/path1', '/path2'] },
|
|
38
|
-
};
|
|
39
|
-
const internalFuncConfig = {
|
|
40
|
-
'framework-isc-c': { path: ['/path1', '/path2'] },
|
|
41
|
-
};
|
|
42
|
-
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations, {
|
|
43
|
-
edge_functions_correct_order: false,
|
|
44
|
-
})).toMatchSnapshot();
|
|
21
|
+
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations)).toMatchSnapshot();
|
|
45
22
|
});
|
|
46
23
|
test('In-source config takes precedence over netlify.toml config', () => {
|
|
47
24
|
const tomlConfig = [
|
package/dist/node/downloader.js
CHANGED
|
@@ -42,7 +42,6 @@ const downloadVersion = async (versionRange) => {
|
|
|
42
42
|
const version = await getLatestVersionForRange(versionRange);
|
|
43
43
|
const url = getReleaseURL(version);
|
|
44
44
|
const res = await fetch(url);
|
|
45
|
-
// eslint-disable-next-line no-magic-numbers
|
|
46
45
|
if (res.body === null || res.status < 200 || res.status > 299) {
|
|
47
46
|
throw new Error(`Download failed with status code ${res.status}`);
|
|
48
47
|
}
|
|
@@ -30,7 +30,7 @@ beforeEach(async (ctx) => {
|
|
|
30
30
|
ctx.tmpDir = tmpDir.path;
|
|
31
31
|
});
|
|
32
32
|
afterEach(async (ctx) => {
|
|
33
|
-
await rm(ctx.tmpDir, { force: true, recursive: true });
|
|
33
|
+
await rm(ctx.tmpDir, { force: true, recursive: true, maxRetries: 10 });
|
|
34
34
|
});
|
|
35
35
|
test('tries downloading binary up to 4 times', async (ctx) => {
|
|
36
36
|
nock.disableNetConnect();
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
declare const defaultFlags: {
|
|
2
|
-
edge_functions_correct_order: boolean;
|
|
3
2
|
edge_functions_fail_unsupported_regex: boolean;
|
|
4
|
-
edge_functions_invalid_config_throw: boolean;
|
|
5
3
|
};
|
|
6
4
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
7
5
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
8
6
|
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
9
|
-
edge_functions_correct_order: boolean;
|
|
10
7
|
edge_functions_fail_unsupported_regex: boolean;
|
|
11
|
-
edge_functions_invalid_config_throw: boolean;
|
|
12
8
|
}) => FeatureFlags;
|
|
13
9
|
export { defaultFlags, getFlags };
|
|
14
10
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const defaultFlags = {
|
|
2
|
-
edge_functions_correct_order: false,
|
|
3
2
|
edge_functions_fail_unsupported_regex: false,
|
|
4
|
-
edge_functions_invalid_config_throw: false,
|
|
5
3
|
};
|
|
6
4
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
7
5
|
...result,
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdir, rm, writeFile } from 'fs/promises';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import { deleteAsync } from 'del';
|
|
5
4
|
const defaultFormatExportTypeError = (name) => `The Edge Function "${name}" has failed to load. Does it have a function as the default export?`;
|
|
6
5
|
const defaultFormatImportError = (name) => `There was an error with Edge Function "${name}".`;
|
|
7
6
|
const generateStage2 = async ({ bootstrapURL, distDirectory, fileName, formatExportTypeError, formatImportError, functions, }) => {
|
|
8
|
-
await
|
|
9
|
-
await
|
|
7
|
+
await rm(distDirectory, { force: true, recursive: true, maxRetries: 3 });
|
|
8
|
+
await mkdir(distDirectory, { recursive: true });
|
|
10
9
|
const entryPoint = getLocalEntryPoint(functions, { bootstrapURL, formatExportTypeError, formatImportError });
|
|
11
10
|
const stage2Path = join(distDirectory, fileName);
|
|
12
|
-
await
|
|
11
|
+
await writeFile(stage2Path, entryPoint);
|
|
13
12
|
return stage2Path;
|
|
14
13
|
};
|
|
15
14
|
// For the local development environment, we import the user functions with
|
package/dist/node/main.test.js
CHANGED
|
@@ -43,5 +43,5 @@ test('Downloads the Deno CLI on demand and caches it for subsequent calls', asyn
|
|
|
43
43
|
expect((_d = output2 === null || output2 === void 0 ? void 0 : output2.stdout) !== null && _d !== void 0 ? _d : '').toMatch(expectedOutput);
|
|
44
44
|
expect(beforeDownload).toHaveBeenCalledTimes(1);
|
|
45
45
|
expect(afterDownload).toHaveBeenCalledTimes(1);
|
|
46
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
46
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
47
47
|
});
|
|
@@ -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, logger
|
|
46
|
+
functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig(func, importMap, deno, logger)));
|
|
47
47
|
}
|
|
48
48
|
const success = await waitForServer(port, processRef.ps);
|
|
49
49
|
return {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rm, writeFile } from 'fs/promises';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import { deleteAsync } from 'del';
|
|
5
4
|
import { execa } from 'execa';
|
|
6
5
|
import tmp from 'tmp-promise';
|
|
7
6
|
import { test, expect } from 'vitest';
|
|
@@ -23,18 +22,18 @@ test('`getLocalEntryPoint` returns a valid stage 2 file for local development',
|
|
|
23
22
|
`;
|
|
24
23
|
const printerPath = join(tmpDir, 'printer.mjs');
|
|
25
24
|
const bootstrapURL = pathToFileURL(printerPath).toString();
|
|
26
|
-
await
|
|
25
|
+
await writeFile(printerPath, printer);
|
|
27
26
|
const functions = [
|
|
28
27
|
{ name: 'func1', path: join(tmpDir, 'func1.mjs'), response: 'Hello from function 1' },
|
|
29
28
|
{ name: 'func2', path: join(tmpDir, 'func2.mjs'), response: 'Hello from function 2' },
|
|
30
29
|
];
|
|
31
30
|
for (const func of functions) {
|
|
32
31
|
const contents = `export default () => ${JSON.stringify(func.response)}`;
|
|
33
|
-
await
|
|
32
|
+
await writeFile(func.path, contents);
|
|
34
33
|
}
|
|
35
34
|
const stage2 = getLocalEntryPoint(functions.map(({ name, path }) => ({ name, path })), { bootstrapURL });
|
|
36
35
|
const stage2Path = join(tmpDir, 'stage2.mjs');
|
|
37
|
-
await
|
|
36
|
+
await writeFile(stage2Path, stage2);
|
|
38
37
|
const { stdout, stderr } = await execa('deno', ['run', '--allow-all', stage2Path]);
|
|
39
38
|
expect(stderr).toBe('');
|
|
40
39
|
const { metadata, responses } = JSON.parse(stdout);
|
|
@@ -42,5 +41,5 @@ test('`getLocalEntryPoint` returns a valid stage 2 file for local development',
|
|
|
42
41
|
expect(responses[func.name]).toBe(func.response);
|
|
43
42
|
expect(metadata.functions[func.name].url).toBe(pathToFileURL(func.path).toString());
|
|
44
43
|
}
|
|
45
|
-
await
|
|
44
|
+
await rm(tmpDir, { force: true, recursive: true });
|
|
46
45
|
});
|
package/dist/node/types.test.js
CHANGED
|
@@ -24,7 +24,7 @@ test('`ensureLatestTypes` updates the Deno CLI cache if the local version of typ
|
|
|
24
24
|
expect(mock).toHaveBeenCalledWith(['cache', '-r', mockURL]);
|
|
25
25
|
expect(versionFile).toBe(mockVersion);
|
|
26
26
|
mock.mockRestore();
|
|
27
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
27
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
28
28
|
});
|
|
29
29
|
test('`ensureLatestTypes` does not update the Deno CLI cache if the local version of types is up-to-date', async () => {
|
|
30
30
|
const mockURL = 'https://edge.netlify';
|
|
@@ -43,7 +43,7 @@ test('`ensureLatestTypes` does not update the Deno CLI cache if the local versio
|
|
|
43
43
|
expect(latestVersionMock.isDone()).toBe(true);
|
|
44
44
|
expect(mock).not.toHaveBeenCalled();
|
|
45
45
|
mock.mockRestore();
|
|
46
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
46
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
47
47
|
});
|
|
48
48
|
test('`ensureLatestTypes` does not throw if the types URL is not available', async () => {
|
|
49
49
|
const mockURL = 'https://edge.netlify';
|
|
@@ -59,5 +59,5 @@ test('`ensureLatestTypes` does not throw if the types URL is not available', asy
|
|
|
59
59
|
expect(latestVersionMock.isDone()).toBe(true);
|
|
60
60
|
expect(mock).not.toHaveBeenCalled();
|
|
61
61
|
mock.mockRestore();
|
|
62
|
-
await rm(tmpDir.path, { force: true, recursive: true });
|
|
62
|
+
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
63
63
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "8.14.
|
|
3
|
+
"version": "8.14.2",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@types/node": "^14.18.32",
|
|
59
59
|
"@types/semver": "^7.3.9",
|
|
60
60
|
"@types/uuid": "^9.0.0",
|
|
61
|
-
"@vitest/coverage-c8": "^0.
|
|
61
|
+
"@vitest/coverage-c8": "^0.31.0",
|
|
62
62
|
"archiver": "^5.3.1",
|
|
63
63
|
"chalk": "^4.1.2",
|
|
64
64
|
"cpy": "^9.0.1",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"nock": "^13.2.4",
|
|
68
68
|
"tar": "^6.1.11",
|
|
69
69
|
"typescript": "^5.0.0",
|
|
70
|
-
"vitest": "^0.
|
|
70
|
+
"vitest": "^0.31.0"
|
|
71
71
|
},
|
|
72
72
|
"engines": {
|
|
73
73
|
"node": "^14.16.0 || >=16.0.0"
|
|
@@ -78,7 +78,6 @@
|
|
|
78
78
|
"ajv-errors": "^3.0.0",
|
|
79
79
|
"better-ajv-errors": "^1.2.0",
|
|
80
80
|
"common-path-prefix": "^3.0.0",
|
|
81
|
-
"del": "^7.0.0",
|
|
82
81
|
"env-paths": "^3.0.0",
|
|
83
82
|
"execa": "^6.0.0",
|
|
84
83
|
"find-up": "^6.3.0",
|