@netlify/edge-bundler 14.1.0 → 14.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.
- package/dist/node/config.test.js +3 -3
- package/dist/node/declaration.d.ts +2 -2
- package/dist/node/declaration.js +2 -2
- package/dist/node/manifest.test.js +8 -8
- package/dist/node/validation/manifest/index.test.js +93 -0
- package/dist/node/validation/manifest/schema.d.ts +62 -0
- package/dist/node/validation/manifest/schema.js +30 -0
- package/package.json +2 -2
package/dist/node/config.test.js
CHANGED
|
@@ -265,14 +265,14 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
265
265
|
path: '/user-func1',
|
|
266
266
|
headers: {
|
|
267
267
|
'x-must-be-there': {
|
|
268
|
-
|
|
268
|
+
matcher: 'exists',
|
|
269
269
|
},
|
|
270
270
|
'x-must-match': {
|
|
271
271
|
pattern: '^(foo|bar)$',
|
|
272
|
-
|
|
272
|
+
matcher: 'regex',
|
|
273
273
|
},
|
|
274
274
|
'x-must-not-be-there': {
|
|
275
|
-
|
|
275
|
+
matcher: 'missing',
|
|
276
276
|
},
|
|
277
277
|
},
|
|
278
278
|
});
|
|
@@ -2,9 +2,9 @@ import { FunctionConfig, HeadersConfig, HTTPMethod, Path } from './config.js';
|
|
|
2
2
|
import { FeatureFlags } from './feature_flags.js';
|
|
3
3
|
export type HeaderMatch = {
|
|
4
4
|
pattern: string;
|
|
5
|
-
|
|
5
|
+
matcher: 'regex';
|
|
6
6
|
} | {
|
|
7
|
-
|
|
7
|
+
matcher: 'exists' | 'missing';
|
|
8
8
|
};
|
|
9
9
|
type HeaderMatchers = Record<string, HeaderMatch>;
|
|
10
10
|
interface BaseDeclaration {
|
package/dist/node/declaration.js
CHANGED
|
@@ -130,10 +130,10 @@ export const getHeaderMatchers = (headers) => {
|
|
|
130
130
|
}
|
|
131
131
|
for (const header in headers) {
|
|
132
132
|
if (typeof headers[header] === 'boolean') {
|
|
133
|
-
matchers[header] = {
|
|
133
|
+
matchers[header] = { matcher: headers[header] ? 'exists' : 'missing' };
|
|
134
134
|
}
|
|
135
135
|
else if (typeof headers[header] === 'string') {
|
|
136
|
-
matchers[header] = {
|
|
136
|
+
matchers[header] = { matcher: 'regex', pattern: normalizePattern(headers[header]) };
|
|
137
137
|
}
|
|
138
138
|
else {
|
|
139
139
|
throw new BundleError(new Error(headerConfigError));
|
|
@@ -215,11 +215,11 @@ test('excludedPath from ISC goes into function_config, TOML goes into routes', (
|
|
|
215
215
|
},
|
|
216
216
|
});
|
|
217
217
|
const matcher = getRouteMatcher(manifest);
|
|
218
|
-
expect(matcher('/showcases/boho-
|
|
218
|
+
expect(matcher('/showcases/boho-matcher')).toBeDefined();
|
|
219
219
|
expect(matcher('/checkout/address')).toBeDefined();
|
|
220
220
|
expect(matcher('/checkout/terms-and-conditions')).toBeUndefined();
|
|
221
221
|
expect(matcher('/checkout/scrooge-mc-duck-animation.css')).toBeUndefined();
|
|
222
|
-
expect(matcher('/showcases/boho-
|
|
222
|
+
expect(matcher('/showcases/boho-matcher/expensive-chair.jpg')).toBeUndefined();
|
|
223
223
|
});
|
|
224
224
|
test('URLPattern named groups are supported', () => {
|
|
225
225
|
const functions = [{ name: 'customisation', path: '/path/to/customisation.ts' }];
|
|
@@ -570,25 +570,25 @@ describe('Header matching', () => {
|
|
|
570
570
|
path: '/f1/*',
|
|
571
571
|
headers: {
|
|
572
572
|
'x-absent': {
|
|
573
|
-
|
|
573
|
+
matcher: 'missing',
|
|
574
574
|
},
|
|
575
575
|
'x-also-present': {
|
|
576
|
-
|
|
576
|
+
matcher: 'exists',
|
|
577
577
|
},
|
|
578
578
|
'x-match-exact': {
|
|
579
579
|
pattern: '^exact$',
|
|
580
|
-
|
|
580
|
+
matcher: 'regex',
|
|
581
581
|
},
|
|
582
582
|
'x-match-prefix': {
|
|
583
583
|
pattern: '^prefix(.*)$',
|
|
584
|
-
|
|
584
|
+
matcher: 'regex',
|
|
585
585
|
},
|
|
586
586
|
'x-match-suffix': {
|
|
587
587
|
pattern: '^(.*)suffix$',
|
|
588
|
-
|
|
588
|
+
matcher: 'regex',
|
|
589
589
|
},
|
|
590
590
|
'x-present': {
|
|
591
|
-
|
|
591
|
+
matcher: 'exists',
|
|
592
592
|
},
|
|
593
593
|
},
|
|
594
594
|
},
|
|
@@ -142,3 +142,96 @@ describe('import map URL', () => {
|
|
|
142
142
|
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
|
+
describe('route headers', () => {
|
|
146
|
+
test('should accept valid headers with exists matcher', () => {
|
|
147
|
+
const manifest = getBaseManifest();
|
|
148
|
+
manifest.routes[0].headers = {
|
|
149
|
+
'x-custom-header': {
|
|
150
|
+
matcher: 'exists',
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
154
|
+
});
|
|
155
|
+
test('should accept valid headers with missing matcher', () => {
|
|
156
|
+
const manifest = getBaseManifest();
|
|
157
|
+
manifest.routes[0].headers = {
|
|
158
|
+
'x-custom-header': {
|
|
159
|
+
matcher: 'missing',
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
163
|
+
});
|
|
164
|
+
test('should accept valid headers with regex matcher and pattern', () => {
|
|
165
|
+
const manifest = getBaseManifest();
|
|
166
|
+
manifest.routes[0].headers = {
|
|
167
|
+
'x-custom-header': {
|
|
168
|
+
matcher: 'regex',
|
|
169
|
+
pattern: '^Bearer .+$',
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
173
|
+
});
|
|
174
|
+
test('should throw on missing matcher property', () => {
|
|
175
|
+
const manifest = getBaseManifest();
|
|
176
|
+
manifest.routes[0].headers = {
|
|
177
|
+
'x-custom-header': {
|
|
178
|
+
pattern: '^Bearer .+$',
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
182
|
+
});
|
|
183
|
+
test('should throw on invalid matcher value', () => {
|
|
184
|
+
const manifest = getBaseManifest();
|
|
185
|
+
manifest.routes[0].headers = {
|
|
186
|
+
'x-custom-header': {
|
|
187
|
+
matcher: 'invalid',
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
191
|
+
});
|
|
192
|
+
test('should throw when matcher is regex but pattern is missing', () => {
|
|
193
|
+
const manifest = getBaseManifest();
|
|
194
|
+
manifest.routes[0].headers = {
|
|
195
|
+
'x-custom-header': {
|
|
196
|
+
matcher: 'regex',
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
200
|
+
});
|
|
201
|
+
test('should throw on invalid pattern format', () => {
|
|
202
|
+
const manifest = getBaseManifest();
|
|
203
|
+
manifest.routes[0].headers = {
|
|
204
|
+
'x-custom-header': {
|
|
205
|
+
matcher: 'regex',
|
|
206
|
+
pattern: '/^Bearer .+/',
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
210
|
+
});
|
|
211
|
+
test('should throw on additional property in headers', () => {
|
|
212
|
+
const manifest = getBaseManifest();
|
|
213
|
+
manifest.routes[0].headers = {
|
|
214
|
+
'x-custom-header': {
|
|
215
|
+
matcher: 'exists',
|
|
216
|
+
foo: 'bar',
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
220
|
+
});
|
|
221
|
+
test('should accept multiple headers with different matchers', () => {
|
|
222
|
+
const manifest = getBaseManifest();
|
|
223
|
+
manifest.routes[0].headers = {
|
|
224
|
+
'x-exists-header': {
|
|
225
|
+
matcher: 'exists',
|
|
226
|
+
},
|
|
227
|
+
'x-missing-header': {
|
|
228
|
+
matcher: 'missing',
|
|
229
|
+
},
|
|
230
|
+
authorization: {
|
|
231
|
+
matcher: 'regex',
|
|
232
|
+
pattern: '^Bearer [a-zA-Z0-9]+$',
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -57,6 +57,37 @@ declare const edgeManifestSchema: {
|
|
|
57
57
|
enum: string[];
|
|
58
58
|
};
|
|
59
59
|
};
|
|
60
|
+
headers: {
|
|
61
|
+
type: string;
|
|
62
|
+
patternProperties: {
|
|
63
|
+
'.*': {
|
|
64
|
+
type: string;
|
|
65
|
+
required: string[];
|
|
66
|
+
properties: {
|
|
67
|
+
pattern: {
|
|
68
|
+
type: string;
|
|
69
|
+
format: string;
|
|
70
|
+
};
|
|
71
|
+
matcher: {
|
|
72
|
+
type: string;
|
|
73
|
+
enum: string[];
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
additionalProperties: boolean;
|
|
77
|
+
if: {
|
|
78
|
+
properties: {
|
|
79
|
+
matcher: {
|
|
80
|
+
const: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
then: {
|
|
85
|
+
required: string[];
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
additionalProperties: boolean;
|
|
90
|
+
};
|
|
60
91
|
};
|
|
61
92
|
additionalProperties: boolean;
|
|
62
93
|
};
|
|
@@ -99,6 +130,37 @@ declare const edgeManifestSchema: {
|
|
|
99
130
|
enum: string[];
|
|
100
131
|
};
|
|
101
132
|
};
|
|
133
|
+
headers: {
|
|
134
|
+
type: string;
|
|
135
|
+
patternProperties: {
|
|
136
|
+
'.*': {
|
|
137
|
+
type: string;
|
|
138
|
+
required: string[];
|
|
139
|
+
properties: {
|
|
140
|
+
pattern: {
|
|
141
|
+
type: string;
|
|
142
|
+
format: string;
|
|
143
|
+
};
|
|
144
|
+
matcher: {
|
|
145
|
+
type: string;
|
|
146
|
+
enum: string[];
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
additionalProperties: boolean;
|
|
150
|
+
if: {
|
|
151
|
+
properties: {
|
|
152
|
+
matcher: {
|
|
153
|
+
const: string;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
then: {
|
|
158
|
+
required: string[];
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
additionalProperties: boolean;
|
|
163
|
+
};
|
|
102
164
|
};
|
|
103
165
|
additionalProperties: boolean;
|
|
104
166
|
};
|
|
@@ -15,6 +15,35 @@ const excludedPatternsSchema = {
|
|
|
15
15
|
errorMessage: 'excluded_patterns must be an array of regex that starts with ^ and ends with $ (e.g. ^/blog/[d]{4}$)',
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
|
+
const headersSchema = {
|
|
19
|
+
type: 'object',
|
|
20
|
+
patternProperties: {
|
|
21
|
+
'.*': {
|
|
22
|
+
type: 'object',
|
|
23
|
+
required: ['matcher'],
|
|
24
|
+
properties: {
|
|
25
|
+
pattern: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
format: 'regexPattern',
|
|
28
|
+
},
|
|
29
|
+
matcher: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
enum: ['exists', 'missing', 'regex'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
if: {
|
|
36
|
+
properties: {
|
|
37
|
+
matcher: { const: 'regex' },
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
then: {
|
|
41
|
+
required: ['pattern'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
additionalProperties: false,
|
|
46
|
+
};
|
|
18
47
|
const routesSchema = {
|
|
19
48
|
type: 'object',
|
|
20
49
|
required: ['function', 'pattern'],
|
|
@@ -33,6 +62,7 @@ const routesSchema = {
|
|
|
33
62
|
type: 'array',
|
|
34
63
|
items: { type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'] },
|
|
35
64
|
},
|
|
65
|
+
headers: headersSchema,
|
|
36
66
|
},
|
|
37
67
|
additionalProperties: false,
|
|
38
68
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "14.1
|
|
3
|
+
"version": "14.2.1",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"urlpattern-polyfill": "8.0.2",
|
|
82
82
|
"uuid": "^11.0.0"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "18c4e2a28edc081235558f151b4c2d41b8e204e8"
|
|
85
85
|
}
|