@vercel/config 0.0.13 → 0.0.16
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/README.md +75 -298
- package/dist/cli.js +58 -30
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -1
- package/dist/router.d.ts +35 -97
- package/dist/router.js +176 -304
- package/dist/types.d.ts +208 -0
- package/dist/types.js +6 -0
- package/dist/utils/validation.d.ts +27 -0
- package/dist/utils/validation.js +96 -1
- package/dist/v1/index.d.ts +9 -0
- package/dist/v1/index.js +27 -0
- package/package.json +15 -1
package/dist/router.js
CHANGED
|
@@ -111,187 +111,35 @@ class Router {
|
|
|
111
111
|
});
|
|
112
112
|
return { proxy, accessedVars };
|
|
113
113
|
}
|
|
114
|
+
// Deprecated: extractEnvVars method no longer needed after refactor
|
|
114
115
|
/**
|
|
115
|
-
*
|
|
116
|
-
* Environment variables are identified by the pattern $VAR_NAME where VAR_NAME
|
|
117
|
-
* is typically uppercase with underscores (e.g., $API_KEY, $BEARER_TOKEN).
|
|
118
|
-
*/
|
|
119
|
-
extractEnvVars(args) {
|
|
120
|
-
const envVars = new Set();
|
|
121
|
-
const values = Array.isArray(args) ? args : [args];
|
|
122
|
-
for (const value of values) {
|
|
123
|
-
const matches = value.match(/\$([A-Z][A-Z0-9_]*)/g);
|
|
124
|
-
if (matches) {
|
|
125
|
-
for (const match of matches) {
|
|
126
|
-
envVars.add(match.substring(1));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return Array.from(envVars);
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
116
|
+
* @deprecated No longer used after refactor to return schema objects directly
|
|
133
117
|
* Internal helper to convert TransformOptions to Transform array
|
|
134
118
|
* @param options Transform options to convert
|
|
135
119
|
* @param trackedEnvVars Optional set of environment variables that were accessed via the env proxy
|
|
136
120
|
*/
|
|
137
|
-
transformOptionsToTransforms
|
|
138
|
-
const transforms = [];
|
|
139
|
-
// Helper to get env vars for a value
|
|
140
|
-
const getEnvVars = (value) => {
|
|
141
|
-
if (trackedEnvVars) {
|
|
142
|
-
return Array.from(trackedEnvVars).filter(envVar => {
|
|
143
|
-
const valueStr = Array.isArray(value) ? value.join(' ') : value;
|
|
144
|
-
return valueStr.includes(`$${envVar}`);
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
return this.extractEnvVars(value);
|
|
148
|
-
};
|
|
149
|
-
// SET operations
|
|
150
|
-
// Convert requestHeaders (set)
|
|
151
|
-
if (options.requestHeaders) {
|
|
152
|
-
for (const [key, value] of Object.entries(options.requestHeaders)) {
|
|
153
|
-
const envVars = getEnvVars(value);
|
|
154
|
-
transforms.push({
|
|
155
|
-
type: 'request.headers',
|
|
156
|
-
op: 'set',
|
|
157
|
-
target: { key },
|
|
158
|
-
args: value,
|
|
159
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Convert responseHeaders (set)
|
|
164
|
-
if (options.responseHeaders) {
|
|
165
|
-
for (const [key, value] of Object.entries(options.responseHeaders)) {
|
|
166
|
-
const envVars = getEnvVars(value);
|
|
167
|
-
transforms.push({
|
|
168
|
-
type: 'response.headers',
|
|
169
|
-
op: 'set',
|
|
170
|
-
target: { key },
|
|
171
|
-
args: value,
|
|
172
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// Convert requestQuery (set)
|
|
177
|
-
if (options.requestQuery) {
|
|
178
|
-
for (const [key, value] of Object.entries(options.requestQuery)) {
|
|
179
|
-
const envVars = getEnvVars(value);
|
|
180
|
-
transforms.push({
|
|
181
|
-
type: 'request.query',
|
|
182
|
-
op: 'set',
|
|
183
|
-
target: { key },
|
|
184
|
-
args: value,
|
|
185
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
// APPEND operations
|
|
190
|
-
// Convert appendRequestHeaders
|
|
191
|
-
if (options.appendRequestHeaders) {
|
|
192
|
-
for (const [key, value] of Object.entries(options.appendRequestHeaders)) {
|
|
193
|
-
const envVars = getEnvVars(value);
|
|
194
|
-
transforms.push({
|
|
195
|
-
type: 'request.headers',
|
|
196
|
-
op: 'append',
|
|
197
|
-
target: { key },
|
|
198
|
-
args: value,
|
|
199
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
// Convert appendResponseHeaders
|
|
204
|
-
if (options.appendResponseHeaders) {
|
|
205
|
-
for (const [key, value] of Object.entries(options.appendResponseHeaders)) {
|
|
206
|
-
const envVars = getEnvVars(value);
|
|
207
|
-
transforms.push({
|
|
208
|
-
type: 'response.headers',
|
|
209
|
-
op: 'append',
|
|
210
|
-
target: { key },
|
|
211
|
-
args: value,
|
|
212
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
// Convert appendRequestQuery
|
|
217
|
-
if (options.appendRequestQuery) {
|
|
218
|
-
for (const [key, value] of Object.entries(options.appendRequestQuery)) {
|
|
219
|
-
const envVars = getEnvVars(value);
|
|
220
|
-
transforms.push({
|
|
221
|
-
type: 'request.query',
|
|
222
|
-
op: 'append',
|
|
223
|
-
target: { key },
|
|
224
|
-
args: value,
|
|
225
|
-
...(envVars.length > 0 && { env: envVars }),
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
// DELETE operations
|
|
230
|
-
// Convert deleteRequestHeaders
|
|
231
|
-
if (options.deleteRequestHeaders) {
|
|
232
|
-
for (const key of options.deleteRequestHeaders) {
|
|
233
|
-
transforms.push({
|
|
234
|
-
type: 'request.headers',
|
|
235
|
-
op: 'delete',
|
|
236
|
-
target: { key },
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
// Convert deleteResponseHeaders
|
|
241
|
-
if (options.deleteResponseHeaders) {
|
|
242
|
-
for (const key of options.deleteResponseHeaders) {
|
|
243
|
-
transforms.push({
|
|
244
|
-
type: 'response.headers',
|
|
245
|
-
op: 'delete',
|
|
246
|
-
target: { key },
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
// Convert deleteRequestQuery
|
|
251
|
-
if (options.deleteRequestQuery) {
|
|
252
|
-
for (const key of options.deleteRequestQuery) {
|
|
253
|
-
transforms.push({
|
|
254
|
-
type: 'request.query',
|
|
255
|
-
op: 'delete',
|
|
256
|
-
target: { key },
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return transforms;
|
|
261
|
-
}
|
|
121
|
+
// Deprecated: transformOptionsToTransforms method removed after refactor
|
|
262
122
|
/**
|
|
263
|
-
*
|
|
264
|
-
* Automatically enables rewrite caching by adding the x-vercel-enable-rewrite-caching header.
|
|
123
|
+
* Creates a rewrite rule. Returns either a Rewrite object (simple case) or Route with transforms.
|
|
265
124
|
*
|
|
266
125
|
* @example
|
|
267
126
|
* // Simple rewrite
|
|
268
127
|
* router.rewrite('/api/(.*)', 'https://old-on-prem.com/$1')
|
|
269
128
|
*
|
|
270
|
-
* // With transforms
|
|
129
|
+
* // With transforms
|
|
271
130
|
* router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({
|
|
272
|
-
* requestHeaders: {
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* }
|
|
276
|
-
* }));
|
|
277
|
-
*
|
|
278
|
-
* // With transforms using object (legacy)
|
|
279
|
-
* router.rewrite('/users/:userId', 'https://api.example.com/users/$1', {
|
|
280
|
-
* requestHeaders: {
|
|
281
|
-
* 'x-user-id': param('userId')
|
|
282
|
-
* }
|
|
283
|
-
* });
|
|
131
|
+
* requestHeaders: { 'x-user-id': userId }
|
|
132
|
+
* }))
|
|
133
|
+
* @internal Can return Route with transforms internally
|
|
284
134
|
*/
|
|
285
135
|
rewrite(source, destination, optionsOrCallback) {
|
|
286
136
|
this.validateSourcePattern(source);
|
|
287
137
|
(0, validation_1.validateCaptureGroupReferences)(source, destination);
|
|
288
138
|
let options;
|
|
289
|
-
let trackedEnvVars;
|
|
290
139
|
// Handle callback syntax
|
|
291
140
|
if (typeof optionsOrCallback === 'function') {
|
|
292
141
|
const pathParams = this.extractPathParams(source);
|
|
293
|
-
const { proxy: envProxy
|
|
294
|
-
trackedEnvVars = accessedVars;
|
|
142
|
+
const { proxy: envProxy } = this.createEnvProxy();
|
|
295
143
|
// Create params object with path parameters as $paramName
|
|
296
144
|
const paramsObj = {};
|
|
297
145
|
for (const param of pathParams) {
|
|
@@ -304,101 +152,86 @@ class Router {
|
|
|
304
152
|
else {
|
|
305
153
|
options = optionsOrCallback;
|
|
306
154
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
155
|
+
const { has, missing, requestHeaders, responseHeaders, requestQuery } = options || {};
|
|
156
|
+
// Check if any transforms were provided
|
|
157
|
+
const hasTransforms = requestHeaders || responseHeaders || requestQuery;
|
|
158
|
+
if (hasTransforms) {
|
|
159
|
+
// Build a Route object with transforms
|
|
160
|
+
const transforms = [];
|
|
161
|
+
if (requestHeaders) {
|
|
162
|
+
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
163
|
+
transforms.push({
|
|
164
|
+
type: 'request.headers',
|
|
165
|
+
op: 'set',
|
|
166
|
+
target: { key },
|
|
167
|
+
args: value,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (responseHeaders) {
|
|
172
|
+
for (const [key, value] of Object.entries(responseHeaders)) {
|
|
173
|
+
transforms.push({
|
|
174
|
+
type: 'response.headers',
|
|
175
|
+
op: 'set',
|
|
176
|
+
target: { key },
|
|
177
|
+
args: value,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (requestQuery) {
|
|
182
|
+
for (const [key, value] of Object.entries(requestQuery)) {
|
|
183
|
+
transforms.push({
|
|
184
|
+
type: 'request.query',
|
|
185
|
+
op: 'set',
|
|
186
|
+
target: { key },
|
|
187
|
+
args: value,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const route = {
|
|
192
|
+
src: source,
|
|
193
|
+
dest: destination,
|
|
194
|
+
transforms,
|
|
195
|
+
};
|
|
196
|
+
if (has)
|
|
197
|
+
route.has = has;
|
|
198
|
+
if (missing)
|
|
199
|
+
route.missing = missing;
|
|
200
|
+
return route;
|
|
201
|
+
}
|
|
202
|
+
// Simple rewrite without transforms
|
|
203
|
+
const rewrite = {
|
|
328
204
|
source,
|
|
329
205
|
destination,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
has
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
// Only enable rewrite caching for rewrites without transforms
|
|
337
|
-
// (transforms convert to routes, which don't need the caching header)
|
|
338
|
-
if (!transforms) {
|
|
339
|
-
this.headerRules.push({
|
|
340
|
-
source,
|
|
341
|
-
headers: [{ key: 'x-vercel-enable-rewrite-caching', value: '1' }],
|
|
342
|
-
has,
|
|
343
|
-
missing,
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
return this;
|
|
206
|
+
};
|
|
207
|
+
if (has)
|
|
208
|
+
rewrite.has = has;
|
|
209
|
+
if (missing)
|
|
210
|
+
rewrite.missing = missing;
|
|
211
|
+
return rewrite;
|
|
347
212
|
}
|
|
348
213
|
/**
|
|
349
|
-
*
|
|
350
|
-
* Automatically enables rewrite caching for all loaded rules by adding the x-vercel-enable-rewrite-caching header.
|
|
214
|
+
* Creates a redirect rule. Returns either a Redirect object (simple case) or Route with transforms.
|
|
351
215
|
*
|
|
352
216
|
* @example
|
|
353
|
-
* // This will automatically enable caching for all rewrites
|
|
354
|
-
* await router.rewrites(() => fetchRewriteRulesFromDB());
|
|
355
|
-
*/
|
|
356
|
-
async rewrites(provider) {
|
|
357
|
-
const rules = await provider();
|
|
358
|
-
this.rewriteRules.push(...rules);
|
|
359
|
-
// Automatically enable rewrite caching for all rules
|
|
360
|
-
const headerRules = rules.map((rule) => ({
|
|
361
|
-
source: rule.source,
|
|
362
|
-
headers: [{ key: 'x-vercel-enable-rewrite-caching', value: '1' }],
|
|
363
|
-
has: rule.has,
|
|
364
|
-
missing: rule.missing,
|
|
365
|
-
}));
|
|
366
|
-
this.headerRules.push(...headerRules);
|
|
367
|
-
return this;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Adds a single redirect rule (synchronous).
|
|
371
|
-
* @example
|
|
372
217
|
* // Simple redirect
|
|
373
218
|
* router.redirect('/old-path', '/new-path', { permanent: true })
|
|
374
219
|
*
|
|
375
|
-
* // With transforms
|
|
220
|
+
* // With transforms
|
|
376
221
|
* router.redirect('/users/:userId', '/new-users/$1', ({userId, env}) => ({
|
|
377
222
|
* permanent: true,
|
|
378
|
-
* requestHeaders: {
|
|
379
|
-
* 'x-user-id': userId,
|
|
380
|
-
* 'x-api-key': env.API_KEY
|
|
381
|
-
* }
|
|
223
|
+
* requestHeaders: { 'x-user-id': userId }
|
|
382
224
|
* }))
|
|
383
|
-
*
|
|
384
|
-
* // With transforms using object (legacy)
|
|
385
|
-
* router.redirect('/users/:userId', '/new-users/$1', {
|
|
386
|
-
* permanent: true,
|
|
387
|
-
* requestHeaders: {
|
|
388
|
-
* 'x-user-id': param('userId')
|
|
389
|
-
* }
|
|
390
|
-
* })
|
|
225
|
+
* @internal Can return Route with transforms internally
|
|
391
226
|
*/
|
|
392
227
|
redirect(source, destination, optionsOrCallback) {
|
|
393
228
|
this.validateSourcePattern(source);
|
|
394
229
|
(0, validation_1.validateCaptureGroupReferences)(source, destination);
|
|
395
230
|
let options;
|
|
396
|
-
let trackedEnvVars;
|
|
397
231
|
// Handle callback syntax
|
|
398
232
|
if (typeof optionsOrCallback === 'function') {
|
|
399
233
|
const pathParams = this.extractPathParams(source);
|
|
400
|
-
const { proxy: envProxy
|
|
401
|
-
trackedEnvVars = accessedVars;
|
|
234
|
+
const { proxy: envProxy } = this.createEnvProxy();
|
|
402
235
|
// Create params object with path parameters as $paramName
|
|
403
236
|
const paramsObj = {};
|
|
404
237
|
for (const param of pathParams) {
|
|
@@ -411,92 +244,75 @@ class Router {
|
|
|
411
244
|
else {
|
|
412
245
|
options = optionsOrCallback;
|
|
413
246
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
deleteRequestHeaders,
|
|
429
|
-
deleteResponseHeaders,
|
|
430
|
-
deleteRequestQuery,
|
|
431
|
-
};
|
|
432
|
-
const transforms = this.transformOptionsToTransforms(transformOpts, trackedEnvVars);
|
|
433
|
-
this.routeRules.push({
|
|
247
|
+
const { permanent, statusCode, has, missing, requestHeaders } = options || {};
|
|
248
|
+
// Check if transforms were provided
|
|
249
|
+
if (requestHeaders) {
|
|
250
|
+
// Build a Route object with transforms
|
|
251
|
+
const transforms = [];
|
|
252
|
+
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
253
|
+
transforms.push({
|
|
254
|
+
type: 'request.headers',
|
|
255
|
+
op: 'set',
|
|
256
|
+
target: { key },
|
|
257
|
+
args: value,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const route = {
|
|
434
261
|
src: source,
|
|
435
262
|
dest: destination,
|
|
436
|
-
...(methods && { methods }),
|
|
437
|
-
transforms,
|
|
438
263
|
redirect: true,
|
|
439
264
|
status: statusCode || (permanent ? 308 : 307),
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
destination,
|
|
448
|
-
permanent,
|
|
449
|
-
statusCode,
|
|
450
|
-
has,
|
|
451
|
-
missing,
|
|
452
|
-
});
|
|
265
|
+
transforms,
|
|
266
|
+
};
|
|
267
|
+
if (has)
|
|
268
|
+
route.has = has;
|
|
269
|
+
if (missing)
|
|
270
|
+
route.missing = missing;
|
|
271
|
+
return route;
|
|
453
272
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
273
|
+
// Simple redirect without transforms
|
|
274
|
+
const redirect = {
|
|
275
|
+
source,
|
|
276
|
+
destination,
|
|
277
|
+
};
|
|
278
|
+
if (permanent !== undefined)
|
|
279
|
+
redirect.permanent = permanent;
|
|
280
|
+
if (statusCode !== undefined)
|
|
281
|
+
redirect.statusCode = statusCode;
|
|
282
|
+
if (has)
|
|
283
|
+
redirect.has = has;
|
|
284
|
+
if (missing)
|
|
285
|
+
redirect.missing = missing;
|
|
286
|
+
return redirect;
|
|
463
287
|
}
|
|
464
288
|
/**
|
|
465
|
-
*
|
|
289
|
+
* Creates a header rule matching the vercel.json schema.
|
|
466
290
|
* @example
|
|
467
291
|
* router.header('/api/(.*)', [{ key: 'X-Custom', value: 'HelloWorld' }])
|
|
468
292
|
*/
|
|
469
293
|
header(source, headers, options) {
|
|
470
294
|
this.validateSourcePattern(source);
|
|
471
|
-
|
|
472
|
-
return this;
|
|
295
|
+
return { source, headers, ...options };
|
|
473
296
|
}
|
|
474
297
|
/**
|
|
475
|
-
*
|
|
476
|
-
|
|
477
|
-
async headers(provider) {
|
|
478
|
-
const rules = await provider();
|
|
479
|
-
this.headerRules.push(...rules);
|
|
480
|
-
return this;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Adds a typed "Cache-Control" header, leveraging `pretty-cache-header`.
|
|
484
|
-
* This method is purely for convenience, so you can do:
|
|
298
|
+
* Creates a Cache-Control header rule, leveraging `pretty-cache-header`.
|
|
299
|
+
* Returns a HeaderRule matching the vercel.json schema.
|
|
485
300
|
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
301
|
+
* @example
|
|
302
|
+
* router.cacheControl('/my-page', {
|
|
303
|
+
* public: true,
|
|
304
|
+
* maxAge: '1week',
|
|
305
|
+
* staleWhileRevalidate: '1year'
|
|
306
|
+
* })
|
|
491
307
|
*/
|
|
492
308
|
cacheControl(source, cacheOptions, options) {
|
|
309
|
+
this.validateSourcePattern(source);
|
|
493
310
|
const value = (0, pretty_cache_header_1.cacheHeader)(cacheOptions);
|
|
494
|
-
|
|
311
|
+
return {
|
|
495
312
|
source,
|
|
496
313
|
headers: [{ key: 'Cache-Control', value }],
|
|
497
314
|
...options,
|
|
498
|
-
}
|
|
499
|
-
return this;
|
|
315
|
+
};
|
|
500
316
|
}
|
|
501
317
|
/**
|
|
502
318
|
* Adds a route with transforms support.
|
|
@@ -607,11 +423,67 @@ class Router {
|
|
|
607
423
|
});
|
|
608
424
|
// Combine with existing routes
|
|
609
425
|
const allRoutes = [...routesFromRewrites, ...this.routeRules];
|
|
610
|
-
// If routes exist,
|
|
426
|
+
// If routes exist, convert everything to routes format
|
|
427
|
+
// Vercel doesn't allow mixing routes with redirects, rewrites, headers, cleanUrls, or trailingSlash
|
|
611
428
|
if (allRoutes.length > 0) {
|
|
429
|
+
// Convert standalone redirects to routes
|
|
430
|
+
const routesFromRedirects = this.redirectRules.map(redirectRule => {
|
|
431
|
+
const route = {
|
|
432
|
+
src: redirectRule.source,
|
|
433
|
+
dest: redirectRule.destination,
|
|
434
|
+
redirect: true,
|
|
435
|
+
status: redirectRule.statusCode || (redirectRule.permanent ? 308 : 307),
|
|
436
|
+
};
|
|
437
|
+
if (redirectRule.has)
|
|
438
|
+
route.has = redirectRule.has;
|
|
439
|
+
if (redirectRule.missing)
|
|
440
|
+
route.missing = redirectRule.missing;
|
|
441
|
+
return route;
|
|
442
|
+
});
|
|
443
|
+
// Convert legacy rewrites (without transforms) to routes
|
|
444
|
+
const routesFromLegacyRewrites = legacyRewrites.map(rewrite => {
|
|
445
|
+
const route = {
|
|
446
|
+
src: rewrite.source,
|
|
447
|
+
dest: rewrite.destination,
|
|
448
|
+
};
|
|
449
|
+
if (rewrite.has)
|
|
450
|
+
route.has = rewrite.has;
|
|
451
|
+
if (rewrite.missing)
|
|
452
|
+
route.missing = rewrite.missing;
|
|
453
|
+
return route;
|
|
454
|
+
});
|
|
455
|
+
// Convert standalone headers to routes (except rewrite caching headers)
|
|
456
|
+
const routesFromHeaders = this.headerRules
|
|
457
|
+
.filter(rule => {
|
|
458
|
+
// Exclude rewrite caching headers (they're automatically added for rewrites)
|
|
459
|
+
const isCachingHeader = rule.headers.length === 1 &&
|
|
460
|
+
rule.headers[0].key === 'x-vercel-enable-rewrite-caching';
|
|
461
|
+
return !isCachingHeader;
|
|
462
|
+
})
|
|
463
|
+
.map(headerRule => {
|
|
464
|
+
const transforms = headerRule.headers.map(header => ({
|
|
465
|
+
type: 'response.headers',
|
|
466
|
+
op: 'set',
|
|
467
|
+
target: { key: header.key },
|
|
468
|
+
args: header.value,
|
|
469
|
+
}));
|
|
470
|
+
const route = {
|
|
471
|
+
src: headerRule.source,
|
|
472
|
+
transforms,
|
|
473
|
+
};
|
|
474
|
+
if (headerRule.has)
|
|
475
|
+
route.has = headerRule.has;
|
|
476
|
+
if (headerRule.missing)
|
|
477
|
+
route.missing = headerRule.missing;
|
|
478
|
+
return route;
|
|
479
|
+
});
|
|
480
|
+
// Combine all routes: redirects, legacy rewrites, rewrites with transforms, explicit routes, and headers as routes
|
|
481
|
+
const combinedRoutes = [...routesFromRedirects, ...routesFromLegacyRewrites, ...routesFromRewrites, ...this.routeRules, ...routesFromHeaders];
|
|
612
482
|
const config = {
|
|
613
|
-
routes:
|
|
483
|
+
routes: combinedRoutes,
|
|
614
484
|
};
|
|
485
|
+
// NOTE: crons are now handled via export const crons in vercel.ts
|
|
486
|
+
// They are no longer included in router.getConfig()
|
|
615
487
|
// Only include optional fields if they're explicitly set
|
|
616
488
|
if (this.bulkRedirectsPathConfig !== undefined) {
|
|
617
489
|
config.bulkRedirectsPath = this.bulkRedirectsPathConfig;
|
|
@@ -631,7 +503,7 @@ class Router {
|
|
|
631
503
|
rewrites: legacyRewrites,
|
|
632
504
|
cleanUrls: this.cleanUrlsConfig,
|
|
633
505
|
trailingSlash: this.trailingSlashConfig,
|
|
634
|
-
|
|
506
|
+
// NOTE: crons are now handled via export const crons in vercel.ts
|
|
635
507
|
};
|
|
636
508
|
// Only include optional fields if they're explicitly set
|
|
637
509
|
if (this.bulkRedirectsPathConfig !== undefined) {
|