@netlify/edge-bundler 12.1.1 → 12.2.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.
@@ -1,7 +1,7 @@
1
1
  import { type WriteStream } from 'fs';
2
2
  import { ExecaChildProcess } from 'execa';
3
3
  import { Logger } from './logger.js';
4
- declare const DENO_VERSION_RANGE = "^1.37.0";
4
+ declare const DENO_VERSION_RANGE = "1.37.0 - 1.44.4";
5
5
  type OnBeforeDownloadHook = () => void | Promise<void>;
6
6
  type OnAfterDownloadHook = (error?: Error) => void | Promise<void>;
7
7
  interface DenoOptions {
@@ -11,7 +11,9 @@ import { getBinaryExtension } from './platform.js';
11
11
  const DENO_VERSION_FILE = 'version.txt';
12
12
  // When updating DENO_VERSION_RANGE, ensure that the deno version installed in the
13
13
  // build-image/buildbot does satisfy this range!
14
- const DENO_VERSION_RANGE = '^1.37.0';
14
+ // We're pinning the range because of an issue with v1.45.0 of the Deno CLI:
15
+ // https://linear.app/netlify/issue/FRP-775/deno-cli-v1450-causing-issues
16
+ const DENO_VERSION_RANGE = '1.37.0 - 1.44.4';
15
17
  class DenoBridge {
16
18
  constructor(options) {
17
19
  var _a, _b, _c, _d, _e;
@@ -11,19 +11,28 @@ export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'
11
11
  export type Path = `/${string}`;
12
12
  export type OnError = 'fail' | 'bypass' | Path;
13
13
  export declare const isValidOnError: (value: unknown) => value is OnError;
14
- export interface FunctionConfig {
14
+ interface BaseFunctionConfig {
15
15
  cache?: Cache;
16
- path?: Path | Path[];
17
- excludedPath?: Path | Path[];
18
16
  onError?: OnError;
19
17
  name?: string;
20
18
  generator?: string;
21
19
  method?: HTTPMethod | HTTPMethod[];
22
20
  rateLimit?: RateLimit;
23
21
  }
22
+ interface FunctionConfigWithPath extends BaseFunctionConfig {
23
+ path?: Path | Path[];
24
+ excludedPath?: Path | Path[];
25
+ }
26
+ interface FunctionConfigWithPattern extends BaseFunctionConfig {
27
+ pattern: string | string[];
28
+ excludedPattern?: string | string[];
29
+ }
30
+ export type FunctionConfig = FunctionConfigWithPath | FunctionConfigWithPattern;
31
+ export type FunctionConfigWithAllPossibleFields = BaseFunctionConfig & Partial<FunctionConfigWithPath & FunctionConfigWithPattern>;
24
32
  export declare const getFunctionConfig: ({ func, importMap, deno, log, }: {
25
33
  func: EdgeFunction;
26
34
  importMap: ImportMap;
27
35
  deno: DenoBridge;
28
36
  log: Logger;
29
37
  }) => Promise<FunctionConfig>;
38
+ export {};
@@ -215,7 +215,7 @@ test('Loads function paths from the in-source `config` function', async () => {
215
215
  configPath: join(internalDirectory, 'config.json'),
216
216
  });
217
217
  const generatedFiles = await fs.readdir(distPath);
218
- expect(result.functions.length).toBe(7);
218
+ expect(result.functions.length).toBe(11);
219
219
  expect(generatedFiles.length).toBe(2);
220
220
  const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
221
221
  const manifest = JSON.parse(manifestFile);
@@ -223,7 +223,7 @@ test('Loads function paths from the in-source `config` function', async () => {
223
223
  expect(bundles.length).toBe(1);
224
224
  expect(bundles[0].format).toBe('eszip2');
225
225
  expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
226
- expect(routes.length).toBe(6);
226
+ expect(routes.length).toBe(12);
227
227
  expect(routes[0]).toEqual({
228
228
  function: 'framework-func2',
229
229
  pattern: '^/framework-func2/?$',
@@ -244,24 +244,54 @@ test('Loads function paths from the in-source `config` function', async () => {
244
244
  path: '/framework-func1',
245
245
  });
246
246
  expect(routes[3]).toEqual({
247
+ function: 'framework-func3',
248
+ pattern: '^/framework-func3(/.*)?$',
249
+ excluded_patterns: ['^/framework-func3/excluded$'],
250
+ });
251
+ expect(routes[4]).toEqual({
252
+ function: 'framework-func4',
253
+ pattern: '^/framework-func4(/.*)?$',
254
+ excluded_patterns: ['^/framework-func4/excluded$', '^/framework-func4-alt/excluded$'],
255
+ });
256
+ expect(routes[5]).toEqual({
257
+ function: 'framework-func4',
258
+ pattern: '^/framework-func4-alt(/.*)?$',
259
+ excluded_patterns: ['^/framework-func4/excluded$', '^/framework-func4-alt/excluded$'],
260
+ });
261
+ expect(routes[6]).toEqual({
247
262
  function: 'user-func1',
248
263
  pattern: '^/user-func1/?$',
249
264
  excluded_patterns: [],
250
265
  path: '/user-func1',
251
266
  });
252
- expect(routes[4]).toEqual({
267
+ expect(routes[7]).toEqual({
253
268
  function: 'user-func3',
254
269
  pattern: '^/user-func3/?$',
255
270
  excluded_patterns: [],
256
271
  path: '/user-func3',
257
272
  });
258
- expect(routes[5]).toEqual({
273
+ expect(routes[8]).toEqual({
259
274
  function: 'user-func5',
260
275
  pattern: '^/user-func5(?:/(.*))/?$',
261
276
  excluded_patterns: ['^/user-func5/excluded/?$'],
262
277
  path: '/user-func5/*',
263
278
  methods: ['GET'],
264
279
  });
280
+ expect(routes[9]).toEqual({
281
+ function: 'user-func6',
282
+ pattern: '^/user-func6(/.*)?$',
283
+ excluded_patterns: ['^/user-func6/excluded$'],
284
+ });
285
+ expect(routes[10]).toEqual({
286
+ function: 'user-func7',
287
+ pattern: '^/user-func7(/.*)?$',
288
+ excluded_patterns: ['^/user-func7/excluded$', '^/user-func7-alt/excluded$'],
289
+ });
290
+ expect(routes[11]).toEqual({
291
+ function: 'user-func7',
292
+ pattern: '^/user-func7-alt(/.*)?$',
293
+ excluded_patterns: ['^/user-func7/excluded$', '^/user-func7-alt/excluded$'],
294
+ });
265
295
  expect(postCacheRoutes.length).toBe(1);
266
296
  expect(postCacheRoutes[0]).toEqual({
267
297
  function: 'user-func4',
@@ -270,10 +300,22 @@ test('Loads function paths from the in-source `config` function', async () => {
270
300
  path: '/user-func4',
271
301
  methods: ['POST', 'PUT'],
272
302
  });
273
- expect(Object.keys(functionConfig)).toHaveLength(1);
303
+ expect(Object.keys(functionConfig)).toHaveLength(5);
274
304
  expect(functionConfig['user-func5']).toEqual({
275
305
  excluded_patterns: ['^/user-func5/excluded/?$'],
276
306
  });
307
+ expect(functionConfig['user-func6']).toEqual({
308
+ excluded_patterns: ['^/user-func6/excluded$'],
309
+ });
310
+ expect(functionConfig['user-func7']).toEqual({
311
+ excluded_patterns: ['^/user-func7/excluded$', '^/user-func7-alt/excluded$'],
312
+ });
313
+ expect(functionConfig['framework-func3']).toEqual({
314
+ excluded_patterns: ['^/framework-func3/excluded$'],
315
+ });
316
+ expect(functionConfig['framework-func4']).toEqual({
317
+ excluded_patterns: ['^/framework-func4/excluded$', '^/framework-func4-alt/excluded$'],
318
+ });
277
319
  await cleanup();
278
320
  });
279
321
  test('Passes validation if default export exists and is a function', async () => {
@@ -17,7 +17,7 @@ _featureFlags = {}) => {
17
17
  return declarations;
18
18
  };
19
19
  const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsVisited) => {
20
- var _a;
20
+ var _a, _b;
21
21
  const declarations = [];
22
22
  // For any declaration for which we also have a function configuration object,
23
23
  // we replace the path because that object takes precedence.
@@ -27,7 +27,15 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
27
27
  // If no config is found, add the declaration as is.
28
28
  declarations.push(declaration);
29
29
  }
30
- else if ((_a = config.path) === null || _a === void 0 ? void 0 : _a.length) {
30
+ else if ('pattern' in config && ((_a = config.pattern) === null || _a === void 0 ? void 0 : _a.length)) {
31
+ // If we have a pattern specified as either a string or non-empty array,
32
+ // create a declaration for each pattern.
33
+ const patterns = Array.isArray(config.pattern) ? config.pattern : [config.pattern];
34
+ patterns.forEach((pattern) => {
35
+ declarations.push({ ...declaration, cache: config.cache, pattern });
36
+ });
37
+ }
38
+ else if ('path' in config && ((_b = config.path) === null || _b === void 0 ? void 0 : _b.length)) {
31
39
  // If we have a path specified as either a string or non-empty array,
32
40
  // create a declaration for each path.
33
41
  const paths = Array.isArray(config.path) ? config.path : [config.path];
@@ -38,7 +46,7 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
38
46
  else {
39
47
  // With an in-source config without a path, add the config to the declaration.
40
48
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
- const { path, excludedPath, ...rest } = config;
49
+ const { path, excludedPath, pattern, excludedPattern, ...rest } = config;
42
50
  declarations.push({ ...declaration, ...rest });
43
51
  }
44
52
  functionsVisited.add(declaration.function);
@@ -48,23 +56,45 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
48
56
  const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited) => {
49
57
  const declarations = [];
50
58
  for (const name in functionConfigs) {
51
- const { cache, excludedPath, path, method } = functionConfigs[name];
52
- // If we have a path specified, create a declaration for each path.
53
- if (!functionsVisited.has(name) && path) {
54
- const paths = Array.isArray(path) ? path : [path];
55
- paths.forEach((singlePath) => {
56
- const declaration = { function: name, path: singlePath };
57
- if (cache) {
58
- declaration.cache = cache;
59
- }
60
- if (method) {
61
- declaration.method = method;
62
- }
63
- if (excludedPath) {
64
- declaration.excludedPath = excludedPath;
65
- }
66
- declarations.push(declaration);
67
- });
59
+ const functionConfig = functionConfigs[name];
60
+ const { cache, method } = functionConfigs[name];
61
+ if (!functionsVisited.has(name)) {
62
+ // If we have a pattern specified, create a declaration for each pattern.
63
+ if ('pattern' in functionConfig && functionConfig.pattern) {
64
+ const { pattern, excludedPattern } = functionConfig;
65
+ const patterns = Array.isArray(pattern) ? pattern : [pattern];
66
+ patterns.forEach((singlePattern) => {
67
+ const declaration = { function: name, pattern: singlePattern };
68
+ if (cache) {
69
+ declaration.cache = cache;
70
+ }
71
+ if (method) {
72
+ declaration.method = method;
73
+ }
74
+ if (excludedPattern) {
75
+ declaration.excludedPattern = excludedPattern;
76
+ }
77
+ declarations.push(declaration);
78
+ });
79
+ }
80
+ // If we don't have a pattern but we have a path specified, create a declaration for each path.
81
+ else if ('path' in functionConfig && functionConfig.path) {
82
+ const { path, excludedPath } = functionConfig;
83
+ const paths = Array.isArray(path) ? path : [path];
84
+ paths.forEach((singlePath) => {
85
+ const declaration = { function: name, path: singlePath };
86
+ if (cache) {
87
+ declaration.cache = cache;
88
+ }
89
+ if (method) {
90
+ declaration.method = method;
91
+ }
92
+ if (excludedPath) {
93
+ declaration.excludedPath = excludedPath;
94
+ }
95
+ declarations.push(declaration);
96
+ });
97
+ }
68
98
  }
69
99
  }
70
100
  return declarations;
@@ -27,13 +27,20 @@ const sanitizeEdgeFunctionConfig = (config) => {
27
27
  }
28
28
  return newConfig;
29
29
  };
30
- const addExcludedPatterns = (name, manifestFunctionConfig, excludedPath) => {
30
+ const addManifestExcludedPatternsFromConfigExcludedPath = (name, manifestFunctionConfig, excludedPath) => {
31
31
  if (excludedPath) {
32
32
  const paths = Array.isArray(excludedPath) ? excludedPath : [excludedPath];
33
33
  const excludedPatterns = paths.map(pathToRegularExpression).filter(nonNullable).map(serializePattern);
34
34
  manifestFunctionConfig[name].excluded_patterns.push(...excludedPatterns);
35
35
  }
36
36
  };
37
+ const addManifestExcludedPatternsFromConfigExcludedPattern = (name, manifestFunctionConfig, excludedPattern) => {
38
+ if (excludedPattern) {
39
+ const excludedPatterns = Array.isArray(excludedPattern) ? excludedPattern : [excludedPattern];
40
+ const normalizedExcludedPatterns = excludedPatterns.filter(nonNullable).map(normalizePattern).map(serializePattern);
41
+ manifestFunctionConfig[name].excluded_patterns.push(...normalizedExcludedPatterns);
42
+ }
43
+ };
37
44
  /**
38
45
  * Normalizes method names into arrays of uppercase strings.
39
46
  * (e.g. "get" becomes ["GET"])
@@ -53,25 +60,37 @@ const generateManifest = ({ bundles = [], declarations = [], functions, userFunc
53
60
  const manifestFunctionConfig = Object.fromEntries(functions.map(({ name }) => [name, { excluded_patterns: [] }]));
54
61
  const routedFunctions = new Set();
55
62
  const declarationsWithoutFunction = new Set();
56
- for (const [name, { excludedPath, onError, rateLimit }] of Object.entries(userFunctionConfig)) {
63
+ for (const [name, singleUserFunctionConfig] of Object.entries(userFunctionConfig)) {
57
64
  // If the config block is for a function that is not defined, discard it.
58
65
  if (manifestFunctionConfig[name] === undefined) {
59
66
  continue;
60
67
  }
61
- addExcludedPatterns(name, manifestFunctionConfig, excludedPath);
68
+ const { excludedPath, pattern, excludedPattern, onError, rateLimit } = singleUserFunctionConfig;
69
+ if (pattern && excludedPattern) {
70
+ addManifestExcludedPatternsFromConfigExcludedPattern(name, manifestFunctionConfig, excludedPattern);
71
+ }
72
+ else {
73
+ addManifestExcludedPatternsFromConfigExcludedPath(name, manifestFunctionConfig, excludedPath);
74
+ }
62
75
  manifestFunctionConfig[name] = {
63
76
  ...manifestFunctionConfig[name],
64
77
  on_error: onError,
65
78
  traffic_rules: getTrafficRulesConfig(rateLimit),
66
79
  };
67
80
  }
68
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
69
- for (const [name, { excludedPath, path, onError, rateLimit, ...rest }] of Object.entries(internalFunctionConfig)) {
81
+ for (const [name, singleInternalFunctionConfig] of Object.entries(internalFunctionConfig)) {
70
82
  // If the config block is for a function that is not defined, discard it.
71
83
  if (manifestFunctionConfig[name] === undefined) {
72
84
  continue;
73
85
  }
74
- addExcludedPatterns(name, manifestFunctionConfig, excludedPath);
86
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
+ const { onError, rateLimit, path, excludedPath, pattern, excludedPattern, ...rest } = singleInternalFunctionConfig;
88
+ if (pattern && excludedPattern) {
89
+ addManifestExcludedPatternsFromConfigExcludedPattern(name, manifestFunctionConfig, excludedPattern);
90
+ }
91
+ else {
92
+ addManifestExcludedPatternsFromConfigExcludedPath(name, manifestFunctionConfig, excludedPath);
93
+ }
75
94
  manifestFunctionConfig[name] = {
76
95
  ...manifestFunctionConfig[name],
77
96
  on_error: onError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/edge-bundler",
3
- "version": "12.1.1",
3
+ "version": "12.2.1",
4
4
  "description": "Intelligently prepare Netlify Edge Functions for deployment",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.js",
@@ -84,5 +84,5 @@
84
84
  "urlpattern-polyfill": "8.0.2",
85
85
  "uuid": "^9.0.0"
86
86
  },
87
- "gitHead": "b993b18469d4355e164f605e742e69dcb5612905"
87
+ "gitHead": "3a237a7c2582fd9b48f18c482d26d0566dd6d4f0"
88
88
  }