@netlify/edge-bundler 10.1.3 → 11.1.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.
- package/dist/node/feature_flags.d.ts +6 -2
- package/dist/node/feature_flags.js +3 -1
- package/dist/node/manifest.d.ts +1 -1
- package/dist/node/manifest.js +11 -5
- package/dist/node/manifest.test.js +16 -2
- package/dist/node/server/server.d.ts +2 -2
- package/dist/node/server/server.js +4 -9
- package/dist/node/server/server.test.js +2 -2
- package/package.json +3 -3
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
declare const defaultFlags: {
|
|
1
|
+
declare const defaultFlags: {
|
|
2
|
+
edge_bundler_pcre_regexp: boolean;
|
|
3
|
+
};
|
|
2
4
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
3
5
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
4
|
-
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
6
|
+
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
7
|
+
edge_bundler_pcre_regexp: boolean;
|
|
8
|
+
}) => FeatureFlags;
|
|
5
9
|
export { defaultFlags, getFlags };
|
|
6
10
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const defaultFlags = {
|
|
1
|
+
const defaultFlags = {
|
|
2
|
+
edge_bundler_pcre_regexp: false,
|
|
3
|
+
};
|
|
2
4
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
3
5
|
...result,
|
|
4
6
|
[key]: input[key] === undefined ? defaultValue : input[key],
|
package/dist/node/manifest.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface GenerateManifestOptions {
|
|
|
42
42
|
layers?: Layer[];
|
|
43
43
|
userFunctionConfig?: Record<string, FunctionConfig>;
|
|
44
44
|
}
|
|
45
|
-
declare const generateManifest: ({ bundles, declarations, functions, userFunctionConfig, internalFunctionConfig, importMap, layers, }: GenerateManifestOptions) => {
|
|
45
|
+
declare const generateManifest: ({ bundles, declarations, featureFlags, functions, userFunctionConfig, internalFunctionConfig, importMap, layers, }: GenerateManifestOptions) => {
|
|
46
46
|
declarationsWithoutFunction: string[];
|
|
47
47
|
manifest: Manifest;
|
|
48
48
|
unroutedFunctions: string[];
|
package/dist/node/manifest.js
CHANGED
|
@@ -46,7 +46,7 @@ const normalizeMethods = (method, name) => {
|
|
|
46
46
|
return method.toUpperCase();
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
|
-
const generateManifest = ({ bundles = [], declarations = [], functions, userFunctionConfig = {}, internalFunctionConfig = {}, importMap, layers = [], }) => {
|
|
49
|
+
const generateManifest = ({ bundles = [], declarations = [], featureFlags, functions, userFunctionConfig = {}, internalFunctionConfig = {}, importMap, layers = [], }) => {
|
|
50
50
|
const preCacheRoutes = [];
|
|
51
51
|
const postCacheRoutes = [];
|
|
52
52
|
const manifestFunctionConfig = Object.fromEntries(functions.map(({ name }) => [name, { excluded_patterns: [] }]));
|
|
@@ -74,14 +74,14 @@ const generateManifest = ({ bundles = [], declarations = [], functions, userFunc
|
|
|
74
74
|
declarationsWithoutFunction.add(declaration.function);
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
const pattern = getRegularExpression(declaration);
|
|
77
|
+
const pattern = getRegularExpression(declaration, Boolean(featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.edge_bundler_pcre_regexp));
|
|
78
78
|
// If there is no `pattern`, the declaration will never be triggered, so we
|
|
79
79
|
// can discard it.
|
|
80
80
|
if (!pattern) {
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
83
|
routedFunctions.add(declaration.function);
|
|
84
|
-
const excludedPattern = getExcludedRegularExpressions(declaration);
|
|
84
|
+
const excludedPattern = getExcludedRegularExpressions(declaration, Boolean(featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.edge_bundler_pcre_regexp));
|
|
85
85
|
const route = {
|
|
86
86
|
function: func.name,
|
|
87
87
|
pattern: serializePattern(pattern),
|
|
@@ -135,8 +135,11 @@ const pathToRegularExpression = (path) => {
|
|
|
135
135
|
throw wrapBundleError(error);
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
|
-
const getRegularExpression = (declaration) => {
|
|
138
|
+
const getRegularExpression = (declaration, pcreRegexpEngine) => {
|
|
139
139
|
if ('pattern' in declaration) {
|
|
140
|
+
if (pcreRegexpEngine) {
|
|
141
|
+
return declaration.pattern;
|
|
142
|
+
}
|
|
140
143
|
try {
|
|
141
144
|
return parsePattern(declaration.pattern);
|
|
142
145
|
}
|
|
@@ -146,11 +149,14 @@ const getRegularExpression = (declaration) => {
|
|
|
146
149
|
}
|
|
147
150
|
return pathToRegularExpression(declaration.path);
|
|
148
151
|
};
|
|
149
|
-
const getExcludedRegularExpressions = (declaration) => {
|
|
152
|
+
const getExcludedRegularExpressions = (declaration, pcreRegexpEngine) => {
|
|
150
153
|
if ('excludedPattern' in declaration && declaration.excludedPattern) {
|
|
151
154
|
const excludedPatterns = Array.isArray(declaration.excludedPattern)
|
|
152
155
|
? declaration.excludedPattern
|
|
153
156
|
: [declaration.excludedPattern];
|
|
157
|
+
if (pcreRegexpEngine) {
|
|
158
|
+
return excludedPatterns;
|
|
159
|
+
}
|
|
154
160
|
return excludedPatterns.map((excludedPattern) => {
|
|
155
161
|
try {
|
|
156
162
|
return parsePattern(excludedPattern);
|
|
@@ -386,15 +386,29 @@ test('Generates a manifest with layers', () => {
|
|
|
386
386
|
expect(manifest2.routes).toEqual(expectedRoutes);
|
|
387
387
|
expect(manifest2.layers).toEqual(layers);
|
|
388
388
|
});
|
|
389
|
-
test('Throws an error if the regular expression contains a negative lookahead', () => {
|
|
389
|
+
test('Throws an error if the regular expression contains a negative lookahead and support for the PCRE engine is disabled', () => {
|
|
390
390
|
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
391
|
-
const declarations = [{ function: 'func-1', pattern: '
|
|
391
|
+
const declarations = [{ function: 'func-1', pattern: '^\\/((?!api|_next\\/static|_next\\/image|favicon.ico).*)$' }];
|
|
392
392
|
expect(() => generateManifest({
|
|
393
393
|
bundles: [],
|
|
394
394
|
declarations,
|
|
395
395
|
functions,
|
|
396
396
|
})).toThrowError(/^Could not parse path declaration of function 'func-1': Regular expressions with lookaheads are not supported$/);
|
|
397
397
|
});
|
|
398
|
+
test('Accepts regular expressions with lookaheads if support for the PCRE engine is enabled', () => {
|
|
399
|
+
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
400
|
+
const declarations = [{ function: 'func-1', pattern: '^\\/((?!api|_next\\/static|_next\\/image|favicon.ico).*)$' }];
|
|
401
|
+
const { manifest } = generateManifest({
|
|
402
|
+
bundles: [],
|
|
403
|
+
declarations,
|
|
404
|
+
featureFlags: { edge_bundler_pcre_regexp: true },
|
|
405
|
+
functions,
|
|
406
|
+
});
|
|
407
|
+
const [route] = manifest.routes;
|
|
408
|
+
const regexp = new RegExp(route.pattern);
|
|
409
|
+
expect(regexp.test('/foo')).toBeTruthy();
|
|
410
|
+
expect(regexp.test('/_next/static/foo')).toBeFalsy();
|
|
411
|
+
});
|
|
398
412
|
test('Converts named capture groups to unnamed capture groups in regular expressions', () => {
|
|
399
413
|
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
400
414
|
const declarations = [{ function: 'func-1', pattern: '^/(?<name>\\w+)$' }];
|
|
@@ -12,6 +12,7 @@ import type { ModuleGraphJson } from '../vendor/module_graph/module_graph.js';
|
|
|
12
12
|
export type FormatFunction = (name: string) => string;
|
|
13
13
|
interface StartServerOptions {
|
|
14
14
|
getFunctionsConfig?: boolean;
|
|
15
|
+
importMapPaths?: string[];
|
|
15
16
|
}
|
|
16
17
|
interface InspectSettings {
|
|
17
18
|
enabled: boolean;
|
|
@@ -26,7 +27,6 @@ interface ServeOptions {
|
|
|
26
27
|
distImportMapPath?: string;
|
|
27
28
|
featureFlags?: FeatureFlags;
|
|
28
29
|
inspectSettings?: InspectSettings;
|
|
29
|
-
importMapPaths?: string[];
|
|
30
30
|
onAfterDownload?: OnAfterDownloadHook;
|
|
31
31
|
onBeforeDownload?: OnBeforeDownloadHook;
|
|
32
32
|
formatExportTypeError?: FormatFunction;
|
|
@@ -37,7 +37,7 @@ interface ServeOptions {
|
|
|
37
37
|
userLogger?: LogFunction;
|
|
38
38
|
systemLogger?: LogFunction;
|
|
39
39
|
}
|
|
40
|
-
export declare const serve: ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, featureFlags, formatExportTypeError, formatImportError,
|
|
40
|
+
export declare const serve: ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, featureFlags, formatExportTypeError, formatImportError, onAfterDownload, onBeforeDownload, port, rootPath, servePath, userLogger, systemLogger, }: ServeOptions) => Promise<(functions: EdgeFunction[], env?: NodeJS.ProcessEnv, options?: StartServerOptions) => Promise<{
|
|
41
41
|
features: Record<string, boolean>;
|
|
42
42
|
functionsConfig: FunctionConfig[];
|
|
43
43
|
graph: ModuleGraphJson;
|
|
@@ -18,9 +18,10 @@ const cleanDirectory = async (directory, except) => {
|
|
|
18
18
|
const toBeDeleted = files.filter((file) => !except.includes(join(directory, file)));
|
|
19
19
|
await Promise.all(toBeDeleted.map((file) => unlink(join(directory, file))));
|
|
20
20
|
};
|
|
21
|
-
const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImportMapPath, flags: denoFlags, formatExportTypeError, formatImportError,
|
|
21
|
+
const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImportMapPath, flags: denoFlags, formatExportTypeError, formatImportError, logger, port, rootPath, }) => {
|
|
22
22
|
const processRef = {};
|
|
23
23
|
const startServer = async (functions, env = {}, options = {}) => {
|
|
24
|
+
var _a;
|
|
24
25
|
if ((processRef === null || processRef === void 0 ? void 0 : processRef.ps) !== undefined) {
|
|
25
26
|
await killProcess(processRef.ps);
|
|
26
27
|
}
|
|
@@ -38,7 +39,8 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
|
|
|
38
39
|
formatImportError,
|
|
39
40
|
});
|
|
40
41
|
const features = {};
|
|
41
|
-
const importMap =
|
|
42
|
+
const importMap = new ImportMap();
|
|
43
|
+
await importMap.addFiles((_a = options.importMapPaths) !== null && _a !== void 0 ? _a : [], logger);
|
|
42
44
|
const npmSpecifiersWithExtraneousFiles = [];
|
|
43
45
|
// we keep track of the files that are relevant to the user's code, so we can clean up leftovers from past executions later
|
|
44
46
|
const relevantFiles = [stage2Path];
|
|
@@ -138,10 +140,6 @@ formatExportTypeError,
|
|
|
138
140
|
* a function.
|
|
139
141
|
*/
|
|
140
142
|
formatImportError,
|
|
141
|
-
/**
|
|
142
|
-
* Paths to any additional import map files.
|
|
143
|
-
*/
|
|
144
|
-
importMapPaths = [],
|
|
145
143
|
/**
|
|
146
144
|
* Callback function to be triggered after the Deno CLI has been downloaded.
|
|
147
145
|
*/
|
|
@@ -205,8 +203,6 @@ systemLogger, }) => {
|
|
|
205
203
|
flags.push(inspectSettings.address ? `--inspect=${inspectSettings.address}` : '--inspect');
|
|
206
204
|
}
|
|
207
205
|
}
|
|
208
|
-
const importMap = new ImportMap();
|
|
209
|
-
await importMap.addFiles(importMapPaths, logger);
|
|
210
206
|
const server = prepareServer({
|
|
211
207
|
basePath,
|
|
212
208
|
bootstrapURL,
|
|
@@ -217,7 +213,6 @@ systemLogger, }) => {
|
|
|
217
213
|
flags,
|
|
218
214
|
formatExportTypeError,
|
|
219
215
|
formatImportError,
|
|
220
|
-
importMap,
|
|
221
216
|
logger,
|
|
222
217
|
port,
|
|
223
218
|
rootPath,
|
|
@@ -19,7 +19,6 @@ test('Starts a server and serves requests for edge functions', async () => {
|
|
|
19
19
|
const server = await serve({
|
|
20
20
|
basePath,
|
|
21
21
|
bootstrapURL: 'https://edge.netlify.com/bootstrap/index-combined.ts',
|
|
22
|
-
importMapPaths,
|
|
23
22
|
port,
|
|
24
23
|
servePath,
|
|
25
24
|
});
|
|
@@ -39,6 +38,7 @@ test('Starts a server and serves requests for edge functions', async () => {
|
|
|
39
38
|
];
|
|
40
39
|
const options = {
|
|
41
40
|
getFunctionsConfig: true,
|
|
41
|
+
importMapPaths,
|
|
42
42
|
};
|
|
43
43
|
const { features, functionsConfig, graph, success, npmSpecifiersWithExtraneousFiles } = await server(functions, {
|
|
44
44
|
very_secret_secret: 'i love netlify',
|
|
@@ -97,7 +97,6 @@ test('Serves edge functions in a monorepo setup', async () => {
|
|
|
97
97
|
const server = await serve({
|
|
98
98
|
basePath,
|
|
99
99
|
bootstrapURL: 'https://edge.netlify.com/bootstrap/index-combined.ts',
|
|
100
|
-
importMapPaths,
|
|
101
100
|
port,
|
|
102
101
|
rootPath,
|
|
103
102
|
servePath,
|
|
@@ -110,6 +109,7 @@ test('Serves edge functions in a monorepo setup', async () => {
|
|
|
110
109
|
];
|
|
111
110
|
const options = {
|
|
112
111
|
getFunctionsConfig: true,
|
|
112
|
+
importMapPaths,
|
|
113
113
|
};
|
|
114
114
|
const { features, functionsConfig, graph, success, npmSpecifiersWithExtraneousFiles } = await server(functions, {
|
|
115
115
|
very_secret_secret: 'i love netlify',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -75,13 +75,13 @@
|
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@import-maps/resolve": "^1.0.1",
|
|
78
|
-
"@vercel/nft": "^0.
|
|
78
|
+
"@vercel/nft": "^0.26.0",
|
|
79
79
|
"ajv": "^8.11.2",
|
|
80
80
|
"ajv-errors": "^3.0.0",
|
|
81
81
|
"better-ajv-errors": "^1.2.0",
|
|
82
82
|
"common-path-prefix": "^3.0.0",
|
|
83
83
|
"env-paths": "^3.0.0",
|
|
84
|
-
"esbuild": "0.19.
|
|
84
|
+
"esbuild": "0.19.11",
|
|
85
85
|
"execa": "^6.0.0",
|
|
86
86
|
"find-up": "^6.3.0",
|
|
87
87
|
"get-package-name": "^2.2.0",
|