@netlify/edge-bundler 14.0.6 → 14.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/deno/vendor/deno.land/std@0.98.0/async/mux_async_iterator.ts +1 -1
- package/deno/vendor/deno.land/std@0.98.0/async/pool.ts +1 -1
- package/deno/vendor/deno.land/x/eszip@v0.55.2/eszip_wasm.generated.js +1 -1
- package/dist/node/bridge.d.ts +1 -1
- package/dist/node/config.d.ts +2 -0
- package/dist/node/config.test.js +12 -0
- package/dist/node/declaration.d.ts +10 -1
- package/dist/node/declaration.js +32 -6
- package/dist/node/manifest.d.ts +2 -1
- package/dist/node/manifest.js +4 -2
- package/dist/node/manifest.test.js +83 -1
- package/dist/node/server/util.d.ts +1 -1
- package/dist/node/validation/manifest/index.js +0 -1
- package/package.json +5 -4
|
@@ -13,7 +13,7 @@ interface TaggedYieldedValue<T> {
|
|
|
13
13
|
*/
|
|
14
14
|
export class MuxAsyncIterator<T> implements AsyncIterable<T> {
|
|
15
15
|
private iteratorCount = 0;
|
|
16
|
-
private yields:
|
|
16
|
+
private yields: TaggedYieldedValue<T>[] = [];
|
|
17
17
|
// deno-lint-ignore no-explicit-any
|
|
18
18
|
private throws: any[] = [];
|
|
19
19
|
private signal: Deferred<void> = deferred();
|
|
@@ -31,7 +31,7 @@ export function pooledMap<T, R>(
|
|
|
31
31
|
// Start processing items from the iterator
|
|
32
32
|
(async () => {
|
|
33
33
|
const writer = res.writable.getWriter();
|
|
34
|
-
const executing:
|
|
34
|
+
const executing: Promise<unknown>[] = [];
|
|
35
35
|
try {
|
|
36
36
|
for await (const item of array) {
|
|
37
37
|
const p = Promise.resolve().then(() => iteratorFn(item));
|
|
@@ -703,8 +703,8 @@ const imports = {
|
|
|
703
703
|
},
|
|
704
704
|
};
|
|
705
705
|
|
|
706
|
-
import { Loader } from "https://deno.land/x/wasmbuild@0.15.1/loader.ts";
|
|
707
706
|
import { cacheToLocalDir } from "https://deno.land/x/wasmbuild@0.15.1/cache.ts";
|
|
707
|
+
import { Loader } from "https://deno.land/x/wasmbuild@0.15.1/loader.ts";
|
|
708
708
|
|
|
709
709
|
const loader = new Loader({
|
|
710
710
|
imports,
|
package/dist/node/bridge.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type WriteStream } from 'fs';
|
|
2
|
-
import { ExecaChildProcess } from 'execa';
|
|
2
|
+
import { type ExecaChildProcess } from 'execa';
|
|
3
3
|
import { Logger } from './logger.js';
|
|
4
4
|
declare const DENO_VERSION_RANGE = "1.39.0 - 2.2.4";
|
|
5
5
|
type OnBeforeDownloadHook = () => void | Promise<void>;
|
package/dist/node/config.d.ts
CHANGED
|
@@ -11,8 +11,10 @@ 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 type HeadersConfig = Record<string, boolean | string>;
|
|
14
15
|
interface BaseFunctionConfig {
|
|
15
16
|
cache?: Cache;
|
|
17
|
+
header?: HeadersConfig;
|
|
16
18
|
onError?: OnError;
|
|
17
19
|
name?: string;
|
|
18
20
|
generator?: string;
|
package/dist/node/config.test.js
CHANGED
|
@@ -263,6 +263,18 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
263
263
|
pattern: '^/user-func1/?$',
|
|
264
264
|
excluded_patterns: [],
|
|
265
265
|
path: '/user-func1',
|
|
266
|
+
headers: {
|
|
267
|
+
'x-must-be-there': {
|
|
268
|
+
style: 'exists',
|
|
269
|
+
},
|
|
270
|
+
'x-must-match': {
|
|
271
|
+
pattern: '^(foo|bar)$',
|
|
272
|
+
style: 'regex',
|
|
273
|
+
},
|
|
274
|
+
'x-must-not-be-there': {
|
|
275
|
+
style: 'missing',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
266
278
|
});
|
|
267
279
|
expect(routes[7]).toEqual({
|
|
268
280
|
function: 'user-func3',
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import { FunctionConfig, HTTPMethod, Path } from './config.js';
|
|
1
|
+
import { FunctionConfig, HeadersConfig, HTTPMethod, Path } from './config.js';
|
|
2
2
|
import { FeatureFlags } from './feature_flags.js';
|
|
3
|
+
export type HeaderMatch = {
|
|
4
|
+
pattern: string;
|
|
5
|
+
style: 'regex';
|
|
6
|
+
} | {
|
|
7
|
+
style: 'exists' | 'missing';
|
|
8
|
+
};
|
|
9
|
+
type HeaderMatchers = Record<string, HeaderMatch>;
|
|
3
10
|
interface BaseDeclaration {
|
|
4
11
|
cache?: string;
|
|
5
12
|
function: string;
|
|
13
|
+
header?: HeadersConfig;
|
|
6
14
|
method?: HTTPMethod | HTTPMethod[];
|
|
7
15
|
name?: string;
|
|
8
16
|
generator?: string;
|
|
@@ -22,4 +30,5 @@ export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFu
|
|
|
22
30
|
* `$` characters.
|
|
23
31
|
*/
|
|
24
32
|
export declare const normalizePattern: (pattern: string) => string;
|
|
33
|
+
export declare const getHeaderMatchers: (headers?: HeadersConfig) => HeaderMatchers;
|
|
25
34
|
export {};
|
package/dist/node/declaration.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
_featureFlags = {}) => {
|
|
1
|
+
import { BundleError } from './bundle_error.js';
|
|
2
|
+
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations, _featureFlags = {}) => {
|
|
4
3
|
const functionsVisited = new Set();
|
|
5
4
|
const declarations = [
|
|
6
5
|
// INTEGRATIONS
|
|
@@ -45,7 +44,6 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
|
|
|
45
44
|
}
|
|
46
45
|
else {
|
|
47
46
|
// With an in-source config without a path, add the config to the declaration.
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
49
47
|
const { path, excludedPath, pattern, excludedPattern, ...rest } = config;
|
|
50
48
|
declarations.push({ ...declaration, ...rest });
|
|
51
49
|
}
|
|
@@ -61,7 +59,7 @@ const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited
|
|
|
61
59
|
if (!functionsVisited.has(name)) {
|
|
62
60
|
// If we have a pattern specified, create a declaration for each pattern.
|
|
63
61
|
if ('pattern' in functionConfig && functionConfig.pattern) {
|
|
64
|
-
const { pattern, excludedPattern } = functionConfig;
|
|
62
|
+
const { header, pattern, excludedPattern } = functionConfig;
|
|
65
63
|
const patterns = Array.isArray(pattern) ? pattern : [pattern];
|
|
66
64
|
patterns.forEach((singlePattern) => {
|
|
67
65
|
const declaration = { function: name, pattern: singlePattern };
|
|
@@ -74,12 +72,15 @@ const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited
|
|
|
74
72
|
if (excludedPattern) {
|
|
75
73
|
declaration.excludedPattern = excludedPattern;
|
|
76
74
|
}
|
|
75
|
+
if (header) {
|
|
76
|
+
declaration.header = header;
|
|
77
|
+
}
|
|
77
78
|
declarations.push(declaration);
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
81
|
// If we don't have a pattern but we have a path specified, create a declaration for each path.
|
|
81
82
|
else if ('path' in functionConfig && functionConfig.path) {
|
|
82
|
-
const { path, excludedPath } = functionConfig;
|
|
83
|
+
const { header, path, excludedPath } = functionConfig;
|
|
83
84
|
const paths = Array.isArray(path) ? path : [path];
|
|
84
85
|
paths.forEach((singlePath) => {
|
|
85
86
|
const declaration = { function: name, path: singlePath };
|
|
@@ -92,6 +93,9 @@ const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited
|
|
|
92
93
|
if (excludedPath) {
|
|
93
94
|
declaration.excludedPath = excludedPath;
|
|
94
95
|
}
|
|
96
|
+
if (header) {
|
|
97
|
+
declaration.header = header;
|
|
98
|
+
}
|
|
95
99
|
declarations.push(declaration);
|
|
96
100
|
});
|
|
97
101
|
}
|
|
@@ -115,3 +119,25 @@ export const normalizePattern = (pattern) => {
|
|
|
115
119
|
// Strip leading and forward slashes.
|
|
116
120
|
return regexp.toString().slice(1, -1);
|
|
117
121
|
};
|
|
122
|
+
const headerConfigError = `The 'header' configuration property must be an object where keys are strings and values are either booleans or strings (e.g. { "x-header-present": true, "x-header-absent": false, "x-header-matching": "^prefix" }).`;
|
|
123
|
+
export const getHeaderMatchers = (headers) => {
|
|
124
|
+
const matchers = {};
|
|
125
|
+
if (!headers) {
|
|
126
|
+
return matchers;
|
|
127
|
+
}
|
|
128
|
+
if (Object.getPrototypeOf(headers) !== Object.prototype) {
|
|
129
|
+
throw new BundleError(new Error(headerConfigError));
|
|
130
|
+
}
|
|
131
|
+
for (const header in headers) {
|
|
132
|
+
if (typeof headers[header] === 'boolean') {
|
|
133
|
+
matchers[header] = { style: headers[header] ? 'exists' : 'missing' };
|
|
134
|
+
}
|
|
135
|
+
else if (typeof headers[header] === 'string') {
|
|
136
|
+
matchers[header] = { style: 'regex', pattern: normalizePattern(headers[header]) };
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
throw new BundleError(new Error(headerConfigError));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return matchers;
|
|
143
|
+
};
|
package/dist/node/manifest.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Bundle } from './bundle.js';
|
|
2
2
|
import { FunctionConfig } from './config.js';
|
|
3
|
-
import { Declaration } from './declaration.js';
|
|
3
|
+
import { Declaration, type HeaderMatch } from './declaration.js';
|
|
4
4
|
import { EdgeFunction } from './edge_function.js';
|
|
5
5
|
import { FeatureFlags } from './feature_flags.js';
|
|
6
6
|
import { Layer } from './layer.js';
|
|
7
7
|
interface Route {
|
|
8
8
|
function: string;
|
|
9
|
+
headers?: Record<string, HeaderMatch>;
|
|
9
10
|
pattern: string;
|
|
10
11
|
excluded_patterns: string[];
|
|
11
12
|
path?: string;
|
package/dist/node/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { wrapBundleError } from './bundle_error.js';
|
|
4
|
-
import { normalizePattern } from './declaration.js';
|
|
4
|
+
import { getHeaderMatchers, normalizePattern } from './declaration.js';
|
|
5
5
|
import { getPackageVersion } from './package_json.js';
|
|
6
6
|
import { RateLimitAction, RateLimitAlgorithm, RateLimitAggregator } from './rate_limit.js';
|
|
7
7
|
import { nonNullable } from './utils/non_nullable.js';
|
|
@@ -83,7 +83,6 @@ const generateManifest = ({ bundles = [], declarations = [], functions, userFunc
|
|
|
83
83
|
if (manifestFunctionConfig[name] === undefined) {
|
|
84
84
|
continue;
|
|
85
85
|
}
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
87
86
|
const { onError, rateLimit, path, excludedPath, pattern, excludedPattern, ...rest } = singleInternalFunctionConfig;
|
|
88
87
|
if (pattern && excludedPattern) {
|
|
89
88
|
addManifestExcludedPatternsFromConfigExcludedPattern(name, manifestFunctionConfig, excludedPattern);
|
|
@@ -120,6 +119,9 @@ const generateManifest = ({ bundles = [], declarations = [], functions, userFunc
|
|
|
120
119
|
if ('method' in declaration) {
|
|
121
120
|
route.methods = normalizeMethods(declaration.method, func.name);
|
|
122
121
|
}
|
|
122
|
+
if ('header' in declaration) {
|
|
123
|
+
route.headers = getHeaderMatchers(declaration.header);
|
|
124
|
+
}
|
|
123
125
|
if ('path' in declaration) {
|
|
124
126
|
route.path = declaration.path;
|
|
125
127
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { test, expect } from 'vitest';
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
|
2
2
|
// @ts-expect-error current tsconfig.json doesn't allow this, but I don't want to change it
|
|
3
3
|
import { version } from '../package.json' assert { type: 'json' };
|
|
4
4
|
import { getRouteMatcher } from '../test/util.js';
|
|
@@ -514,3 +514,85 @@ test('Generates a manifest with rewrite config', () => {
|
|
|
514
514
|
expect(manifest.routes).toEqual(expectedRoutes);
|
|
515
515
|
expect(manifest.function_config).toEqual(expectedFunctionConfig);
|
|
516
516
|
});
|
|
517
|
+
describe('Header matching', () => {
|
|
518
|
+
test('Throws a bundling error if the type is incorrect', () => {
|
|
519
|
+
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
520
|
+
expect(() => generateManifest({
|
|
521
|
+
bundles: [],
|
|
522
|
+
// @ts-expect-error Incorrect type
|
|
523
|
+
declarations: [{ function: 'func-1', path: '/f1/*', header: 'foo' }],
|
|
524
|
+
functions,
|
|
525
|
+
})).toThrowError(BundleError);
|
|
526
|
+
expect(() => generateManifest({
|
|
527
|
+
bundles: [],
|
|
528
|
+
declarations: [
|
|
529
|
+
{
|
|
530
|
+
function: 'func-1',
|
|
531
|
+
path: '/f1/*',
|
|
532
|
+
header: {
|
|
533
|
+
'x-correct': true,
|
|
534
|
+
// @ts-expect-error Incorrect type
|
|
535
|
+
'x-not-correct': {
|
|
536
|
+
problem: true,
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
functions,
|
|
542
|
+
})).toThrowError(BundleError);
|
|
543
|
+
});
|
|
544
|
+
test('Writes header matching rules to the manifest', () => {
|
|
545
|
+
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
546
|
+
const declarations = [
|
|
547
|
+
{
|
|
548
|
+
function: 'func-1',
|
|
549
|
+
path: '/f1/*',
|
|
550
|
+
header: {
|
|
551
|
+
'x-present': true,
|
|
552
|
+
'x-also-present': true,
|
|
553
|
+
'x-absent': false,
|
|
554
|
+
'x-match-prefix': '^prefix(.*)',
|
|
555
|
+
'x-match-exact': 'exact',
|
|
556
|
+
'x-match-suffix': '(.*)suffix$',
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
];
|
|
560
|
+
const { manifest } = generateManifest({
|
|
561
|
+
bundles: [],
|
|
562
|
+
declarations,
|
|
563
|
+
functions,
|
|
564
|
+
});
|
|
565
|
+
const expectedRoutes = [
|
|
566
|
+
{
|
|
567
|
+
function: 'func-1',
|
|
568
|
+
pattern: '^/f1(?:/(.*))/?$',
|
|
569
|
+
excluded_patterns: [],
|
|
570
|
+
path: '/f1/*',
|
|
571
|
+
headers: {
|
|
572
|
+
'x-absent': {
|
|
573
|
+
style: 'missing',
|
|
574
|
+
},
|
|
575
|
+
'x-also-present': {
|
|
576
|
+
style: 'exists',
|
|
577
|
+
},
|
|
578
|
+
'x-match-exact': {
|
|
579
|
+
pattern: '^exact$',
|
|
580
|
+
style: 'regex',
|
|
581
|
+
},
|
|
582
|
+
'x-match-prefix': {
|
|
583
|
+
pattern: '^prefix(.*)$',
|
|
584
|
+
style: 'regex',
|
|
585
|
+
},
|
|
586
|
+
'x-match-suffix': {
|
|
587
|
+
pattern: '^(.*)suffix$',
|
|
588
|
+
style: 'regex',
|
|
589
|
+
},
|
|
590
|
+
'x-present': {
|
|
591
|
+
style: 'exists',
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
];
|
|
596
|
+
expect(manifest.routes).toEqual(expectedRoutes);
|
|
597
|
+
});
|
|
598
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecaChildProcess } from 'execa';
|
|
1
|
+
import { type ExecaChildProcess } from 'execa';
|
|
2
2
|
declare const killProcess: (ps: ExecaChildProcess<string>) => Promise<unknown> | undefined;
|
|
3
3
|
declare const waitForServer: (port: number, ps?: ExecaChildProcess<string>) => Promise<boolean>;
|
|
4
4
|
export { killProcess, waitForServer };
|
|
@@ -19,7 +19,6 @@ const initializeValidator = () => {
|
|
|
19
19
|
return manifestValidator;
|
|
20
20
|
};
|
|
21
21
|
// throws on validation error
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
22
|
export const validateManifest = (manifestData, _featureFlags = {}) => {
|
|
24
23
|
const validate = initializeValidator();
|
|
25
24
|
const valid = validate(manifestData);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "14.0
|
|
3
|
+
"version": "14.1.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -42,12 +42,13 @@
|
|
|
42
42
|
"test": "test/node"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/node": "^18.
|
|
45
|
+
"@types/node": "^18.19.111",
|
|
46
46
|
"@types/semver": "^7.3.9",
|
|
47
47
|
"@types/uuid": "^10.0.0",
|
|
48
48
|
"@vitest/coverage-v8": "^3.0.0",
|
|
49
49
|
"archiver": "^7.0.0",
|
|
50
50
|
"chalk": "^5.4.0",
|
|
51
|
+
"cpy": "^11.1.0",
|
|
51
52
|
"nock": "^14.0.0",
|
|
52
53
|
"npm-run-all2": "^6.0.0",
|
|
53
54
|
"tar": "^7.0.0",
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
"better-ajv-errors": "^1.2.0",
|
|
65
66
|
"common-path-prefix": "^3.0.0",
|
|
66
67
|
"env-paths": "^3.0.0",
|
|
67
|
-
"esbuild": "0.25.
|
|
68
|
+
"esbuild": "0.25.6",
|
|
68
69
|
"execa": "^8.0.0",
|
|
69
70
|
"find-up": "^7.0.0",
|
|
70
71
|
"get-package-name": "^2.2.0",
|
|
@@ -80,5 +81,5 @@
|
|
|
80
81
|
"urlpattern-polyfill": "8.0.2",
|
|
81
82
|
"uuid": "^11.0.0"
|
|
82
83
|
},
|
|
83
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "ea236c6df25a511cc0f0412759610da917c10b20"
|
|
84
85
|
}
|