@vercel/config 0.0.21 → 0.0.23

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 CHANGED
@@ -13,10 +13,8 @@ npm install @vercel/config
13
13
  Create a `vercel.ts` file in your project root:
14
14
 
15
15
  ```typescript
16
- import { createRouter } from '@vercel/config';
17
- import type { VercelConfig } from '@vercel/config';
18
-
19
- const router = createRouter();
16
+ import { routes, deploymentEnv } from '@vercel/config/v1';
17
+ import type { VercelConfig } from '@vercel/config/v1';
20
18
 
21
19
  export const config: VercelConfig = {
22
20
  buildCommand: 'npm run build',
@@ -24,25 +22,33 @@ export const config: VercelConfig = {
24
22
 
25
23
  rewrites: [
26
24
  // Simple rewrite
27
- router.rewrite('/api/(.*)', 'https://backend.api.example.com/$1'),
25
+ routes.rewrite('/api/(.*)', 'https://backend.api.example.com/$1'),
26
+
27
+ // Rewrite with transforms (no path params)
28
+ routes.rewrite('/(.*)', 'https://api.example.com/$1', {
29
+ requestHeaders: {
30
+ 'authorization': `Bearer ${deploymentEnv('API_TOKEN')}`
31
+ }
32
+ }),
28
33
 
29
- // Rewrite with transforms
30
- router.rewrite('/users/:userId', 'https://api.example.com/users/$1',
31
- ({ userId, env }) => ({
34
+ // Type-safe path parameters with callback
35
+ routes.rewrite('/users/:userId/posts/:postId', 'https://api.example.com/users/$1/posts/$2',
36
+ ({ userId, postId }) => ({
32
37
  requestHeaders: {
33
38
  'x-user-id': userId,
34
- 'authorization': `Bearer ${env.API_TOKEN}`
39
+ 'x-post-id': postId,
40
+ 'authorization': `Bearer ${deploymentEnv('API_KEY')}`
35
41
  }
36
42
  })
37
43
  )
38
44
  ],
39
45
 
40
46
  redirects: [
41
- router.redirect('/old-docs', '/docs', { permanent: true })
47
+ routes.redirect('/old-docs', '/docs', { permanent: true })
42
48
  ],
43
49
 
44
50
  headers: [
45
- router.cacheControl('/static/(.*)', {
51
+ routes.cacheControl('/static/(.*)', {
46
52
  public: true,
47
53
  maxAge: '1 week',
48
54
  immutable: true
@@ -58,7 +64,9 @@ export const config: VercelConfig = {
58
64
  ## Features
59
65
 
60
66
  - **Type-safe configuration** - Full TypeScript support with IDE autocomplete
61
- - **Readable syntax** - Helper methods like `router.redirect()`, `router.rewrite()`, `router.header()`
67
+ - **Type-safe path parameters** - Extract `:userId` from patterns with full IntelliSense
68
+ - **Deployment environment variables** - Use `deploymentEnv()` for Vercel project env vars
69
+ - **Readable syntax** - Helper methods like `routes.redirect()`, `routes.rewrite()`, `routes.header()`
62
70
  - **Transforms** - Modify request/response headers and query parameters on the fly
63
71
  - **Conditions** - Advanced routing with `has` and `missing` conditions
64
72
  - **CLI tools** - `compile` and `validate` commands for development
package/dist/router.d.ts CHANGED
@@ -1,21 +1,35 @@
1
1
  import type { Redirect, Rewrite } from './types';
2
2
  /**
3
- * Helper function to reference a path parameter in transforms.
4
- * Path parameters are extracted from the route pattern (e.g., :userId).
3
+ * Type utility to extract path parameter names from a route pattern string.
4
+ * Supports :paramName syntax used in path-to-regexp patterns.
5
5
  *
6
6
  * @example
7
- * param('userId') // Returns '$userId'
7
+ * ExtractPathParams<'/users/:userId/posts/:postId'> // 'userId' | 'postId'
8
+ * ExtractPathParams<'/api/(.*)'> // never
8
9
  */
9
- export declare function param(name: string): string;
10
+ type ExtractPathParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? (Param extends `${infer P}(${string}` ? P : Param) | ExtractPathParams<`/${Rest}`> : T extends `${string}:${infer Param}` ? Param extends `${infer P}(${string}` ? P : Param : never;
10
11
  /**
11
- * Helper function to reference a runtime environment variable in transforms.
12
- * These are environment variables that get resolved at request time by Vercel's routing layer,
13
- * not at build time.
12
+ * Creates an object type where keys are the extracted path parameter names
13
+ * and values are strings (the resolved $paramName values).
14
+ */
15
+ type PathParams<T extends string> = {
16
+ [K in ExtractPathParams<T>]: string;
17
+ };
18
+ /**
19
+ * Helper function to reference a Vercel project environment variable.
20
+ * These are placeholders that get resolved at request time by Vercel's routing layer.
21
+ * They are set per-deployment and don't change until you redeploy.
14
22
  *
15
23
  * @example
16
- * runtimeEnv('BEARER_TOKEN') // Returns '$BEARER_TOKEN'
24
+ * // Usage in rewrites with type-safe path params:
25
+ * routes.rewrite('/users/:userId', 'https://api.example.com/$1', ({ userId }) => ({
26
+ * requestHeaders: {
27
+ * 'x-user-id': userId,
28
+ * 'authorization': `Bearer ${deploymentEnv('API_KEY')}`
29
+ * }
30
+ * }))
17
31
  */
18
- export declare function runtimeEnv(name: string): string;
32
+ export declare function deploymentEnv(name: string): string;
19
33
  /**
20
34
  * Template literal type for durations recognized by pretty-cache-header.
21
35
  *
@@ -264,6 +278,8 @@ export interface Route {
264
278
  status?: number;
265
279
  /** Headers to set (alternative to using transforms) */
266
280
  headers?: Record<string, string>;
281
+ /** Environment variables referenced in dest or transforms */
282
+ env?: string[];
267
283
  }
268
284
  /**
269
285
  * Represents a single HTTP header key/value pair.
@@ -489,11 +505,6 @@ export declare class Router {
489
505
  * extractPathParams('/users/:userId/posts/:postId') // Returns ['userId', 'postId']
490
506
  */
491
507
  private extractPathParams;
492
- /**
493
- * Creates a Proxy object that tracks environment variable accesses.
494
- * Returns both the proxy and a set of accessed environment variable names.
495
- */
496
- private createEnvProxy;
497
508
  /**
498
509
  * Creates a rewrite rule. Returns either a Rewrite object (simple case) or Route with transforms.
499
510
  *
@@ -501,27 +512,42 @@ export declare class Router {
501
512
  * // Simple rewrite
502
513
  * router.rewrite('/api/(.*)', 'https://old-on-prem.com/$1')
503
514
  *
504
- * // With transforms
505
- * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({
506
- * requestHeaders: { 'x-user-id': userId }
515
+ * // With transforms but no path params
516
+ * router.rewrite('/(.*)', 'https://api.example.com/$1', {
517
+ * requestHeaders: {
518
+ * 'authorization': `Bearer ${deploymentEnv('API_KEY')}`
519
+ * }
520
+ * })
521
+ *
522
+ * // With type-safe path params
523
+ * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({ userId }) => ({
524
+ * requestHeaders: {
525
+ * 'x-user-id': userId,
526
+ * 'authorization': `Bearer ${deploymentEnv('API_KEY')}`
527
+ * }
507
528
  * }))
529
+ *
530
+ * // With conditions only
531
+ * router.rewrite('/admin/(.*)', 'https://admin.example.com/$1', {
532
+ * has: [{ type: 'header', key: 'x-admin-token' }]
533
+ * })
508
534
  * @internal Can return Route with transforms internally
509
535
  */
510
- rewrite(source: string, destination: string, optionsOrCallback?: {
536
+ rewrite<T extends string>(source: T, destination: string): Rewrite | Route;
537
+ rewrite<T extends string>(source: T, destination: string, callback: (params: PathParams<T>) => {
511
538
  has?: Condition[];
512
539
  missing?: Condition[];
513
540
  requestHeaders?: Record<string, string | string[]>;
514
541
  responseHeaders?: Record<string, string | string[]>;
515
542
  requestQuery?: Record<string, string | string[]>;
516
- } | ((params: Record<string, string> & {
517
- env: any;
518
- }) => {
543
+ }): Rewrite | Route;
544
+ rewrite<T extends string>(source: T, destination: string, options: ({
519
545
  has?: Condition[];
520
546
  missing?: Condition[];
521
547
  requestHeaders?: Record<string, string | string[]>;
522
548
  responseHeaders?: Record<string, string | string[]>;
523
549
  requestQuery?: Record<string, string | string[]>;
524
- })): Rewrite | Route;
550
+ }) & Record<never, never>): Rewrite | Route;
525
551
  /**
526
552
  * Creates a redirect rule. Returns either a Redirect object (simple case) or Route with transforms.
527
553
  *
@@ -529,28 +555,44 @@ export declare class Router {
529
555
  * // Simple redirect
530
556
  * router.redirect('/old-path', '/new-path', { permanent: true })
531
557
  *
532
- * // With transforms
533
- * router.redirect('/users/:userId', '/new-users/$1', ({userId, env}) => ({
558
+ * // With transforms but no path params
559
+ * router.redirect('/old', '/new', {
534
560
  * permanent: true,
535
- * requestHeaders: { 'x-user-id': userId }
561
+ * requestHeaders: {
562
+ * 'x-api-key': deploymentEnv('API_KEY')
563
+ * }
564
+ * })
565
+ *
566
+ * // With type-safe path params
567
+ * router.redirect('/users/:userId', '/new-users/$1', ({ userId }) => ({
568
+ * permanent: true,
569
+ * requestHeaders: {
570
+ * 'x-user-id': userId,
571
+ * 'x-api-key': deploymentEnv('API_KEY')
572
+ * }
536
573
  * }))
574
+ *
575
+ * // With conditions only
576
+ * router.redirect('/dashboard/(.*)', '/login', {
577
+ * missing: [{ type: 'cookie', key: 'auth-token' }]
578
+ * })
537
579
  * @internal Can return Route with transforms internally
538
580
  */
539
- redirect(source: string, destination: string, optionsOrCallback?: {
581
+ redirect<T extends string>(source: T, destination: string): Redirect | Route;
582
+ redirect<T extends string>(source: T, destination: string, callback: (params: PathParams<T>) => {
540
583
  permanent?: boolean;
541
584
  statusCode?: number;
542
585
  has?: Condition[];
543
586
  missing?: Condition[];
544
587
  requestHeaders?: Record<string, string | string[]>;
545
- } | ((params: Record<string, string> & {
546
- env: any;
547
- }) => {
588
+ }): Redirect | Route;
589
+ redirect<T extends string>(source: T, destination: string, options: {
548
590
  permanent?: boolean;
549
591
  statusCode?: number;
550
592
  has?: Condition[];
551
593
  missing?: Condition[];
552
594
  requestHeaders?: Record<string, string | string[]>;
553
- })): Redirect | Route;
595
+ }): Redirect | Route;
554
596
  /**
555
597
  * Creates a header rule matching the vercel.json schema.
556
598
  * @example
@@ -647,3 +689,4 @@ export declare function createRoutes(): Router;
647
689
  * routes.redirect('/old', '/new');
648
690
  */
649
691
  export declare const routes: Router;
692
+ export {};
package/dist/router.js CHANGED
@@ -1,31 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.routes = exports.createRoutes = exports.Router = exports.runtimeEnv = exports.param = void 0;
3
+ exports.routes = exports.createRoutes = exports.Router = exports.deploymentEnv = void 0;
4
4
  const pretty_cache_header_1 = require("pretty-cache-header");
5
5
  const validation_1 = require("./utils/validation");
6
6
  /**
7
- * Helper function to reference a path parameter in transforms.
8
- * Path parameters are extracted from the route pattern (e.g., :userId).
7
+ * Helper function to reference a Vercel project environment variable.
8
+ * These are placeholders that get resolved at request time by Vercel's routing layer.
9
+ * They are set per-deployment and don't change until you redeploy.
9
10
  *
10
11
  * @example
11
- * param('userId') // Returns '$userId'
12
+ * // Usage in rewrites with type-safe path params:
13
+ * routes.rewrite('/users/:userId', 'https://api.example.com/$1', ({ userId }) => ({
14
+ * requestHeaders: {
15
+ * 'x-user-id': userId,
16
+ * 'authorization': `Bearer ${deploymentEnv('API_KEY')}`
17
+ * }
18
+ * }))
12
19
  */
13
- function param(name) {
20
+ function deploymentEnv(name) {
14
21
  return `$${name}`;
15
22
  }
16
- exports.param = param;
17
- /**
18
- * Helper function to reference a runtime environment variable in transforms.
19
- * These are environment variables that get resolved at request time by Vercel's routing layer,
20
- * not at build time.
21
- *
22
- * @example
23
- * runtimeEnv('BEARER_TOKEN') // Returns '$BEARER_TOKEN'
24
- */
25
- function runtimeEnv(name) {
26
- return `$${name}`;
27
- }
28
- exports.runtimeEnv = runtimeEnv;
23
+ exports.deploymentEnv = deploymentEnv;
29
24
  /**
30
25
  * Extract environment variable names from a string or array of strings
31
26
  * Returns env var names without the $ prefix, excluding path parameters
@@ -77,50 +72,15 @@ class Router {
77
72
  }
78
73
  return params;
79
74
  }
80
- /**
81
- * Creates a Proxy object that tracks environment variable accesses.
82
- * Returns both the proxy and a set of accessed environment variable names.
83
- */
84
- createEnvProxy() {
85
- const accessedVars = new Set();
86
- const proxy = new Proxy({}, {
87
- get(_target, prop) {
88
- if (typeof prop === 'string') {
89
- accessedVars.add(prop);
90
- return `$${prop}`;
91
- }
92
- return undefined;
93
- }
94
- });
95
- return { proxy, accessedVars };
96
- }
97
- /**
98
- * Creates a rewrite rule. Returns either a Rewrite object (simple case) or Route with transforms.
99
- *
100
- * @example
101
- * // Simple rewrite
102
- * router.rewrite('/api/(.*)', 'https://old-on-prem.com/$1')
103
- *
104
- * // With transforms
105
- * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({
106
- * requestHeaders: { 'x-user-id': userId }
107
- * }))
108
- * @internal Can return Route with transforms internally
109
- */
110
75
  rewrite(source, destination, optionsOrCallback) {
111
76
  this.validateSourcePattern(source);
112
77
  let options;
113
- // Handle callback syntax
114
78
  if (typeof optionsOrCallback === 'function') {
115
79
  const pathParams = this.extractPathParams(source);
116
- const { proxy: envProxy } = this.createEnvProxy();
117
- // Create params object with path parameters as $paramName
118
80
  const paramsObj = {};
119
81
  for (const param of pathParams) {
120
82
  paramsObj[param] = `$${param}`;
121
83
  }
122
- paramsObj.env = envProxy;
123
- // Call the callback to get options
124
84
  options = optionsOrCallback(paramsObj);
125
85
  }
126
86
  else {
@@ -183,13 +143,34 @@ class Router {
183
143
  dest: destination,
184
144
  transforms,
185
145
  };
146
+ if (has)
147
+ route.has = has;
148
+ if (missing)
149
+ route.missing = missing;
150
+ // Extract env vars from destination
151
+ const destEnvVars = extractEnvVars(destination, pathParams);
152
+ if (destEnvVars.length > 0) {
153
+ route.env = destEnvVars;
154
+ }
155
+ return route;
156
+ }
157
+ // Simple rewrite without transforms - check if destination has env vars
158
+ const pathParams = this.extractPathParams(source);
159
+ const destEnvVars = extractEnvVars(destination, pathParams);
160
+ if (destEnvVars.length > 0) {
161
+ // Need Route format to include env field
162
+ const route = {
163
+ src: source,
164
+ dest: destination,
165
+ env: destEnvVars,
166
+ };
186
167
  if (has)
187
168
  route.has = has;
188
169
  if (missing)
189
170
  route.missing = missing;
190
171
  return route;
191
172
  }
192
- // Simple rewrite without transforms
173
+ // Simple rewrite without transforms or env vars
193
174
  const rewrite = {
194
175
  source,
195
176
  destination,
@@ -200,34 +181,15 @@ class Router {
200
181
  rewrite.missing = missing;
201
182
  return rewrite;
202
183
  }
203
- /**
204
- * Creates a redirect rule. Returns either a Redirect object (simple case) or Route with transforms.
205
- *
206
- * @example
207
- * // Simple redirect
208
- * router.redirect('/old-path', '/new-path', { permanent: true })
209
- *
210
- * // With transforms
211
- * router.redirect('/users/:userId', '/new-users/$1', ({userId, env}) => ({
212
- * permanent: true,
213
- * requestHeaders: { 'x-user-id': userId }
214
- * }))
215
- * @internal Can return Route with transforms internally
216
- */
217
184
  redirect(source, destination, optionsOrCallback) {
218
185
  this.validateSourcePattern(source);
219
186
  let options;
220
- // Handle callback syntax
221
187
  if (typeof optionsOrCallback === 'function') {
222
188
  const pathParams = this.extractPathParams(source);
223
- const { proxy: envProxy } = this.createEnvProxy();
224
- // Create params object with path parameters as $paramName
225
189
  const paramsObj = {};
226
190
  for (const param of pathParams) {
227
191
  paramsObj[param] = `$${param}`;
228
192
  }
229
- paramsObj.env = envProxy;
230
- // Call the callback to get options
231
193
  options = optionsOrCallback(paramsObj);
232
194
  }
233
195
  else {
@@ -259,13 +221,36 @@ class Router {
259
221
  status: statusCode || (permanent ? 308 : 307),
260
222
  transforms,
261
223
  };
224
+ if (has)
225
+ route.has = has;
226
+ if (missing)
227
+ route.missing = missing;
228
+ // Extract env vars from destination
229
+ const destEnvVars = extractEnvVars(destination, pathParams);
230
+ if (destEnvVars.length > 0) {
231
+ route.env = destEnvVars;
232
+ }
233
+ return route;
234
+ }
235
+ // Simple redirect without transforms - check if destination has env vars
236
+ const pathParams = this.extractPathParams(source);
237
+ const destEnvVars = extractEnvVars(destination, pathParams);
238
+ if (destEnvVars.length > 0) {
239
+ // Need Route format to include env field
240
+ const route = {
241
+ src: source,
242
+ dest: destination,
243
+ redirect: true,
244
+ status: statusCode || (permanent ? 308 : 307),
245
+ env: destEnvVars,
246
+ };
262
247
  if (has)
263
248
  route.has = has;
264
249
  if (missing)
265
250
  route.missing = missing;
266
251
  return route;
267
252
  }
268
- // Simple redirect without transforms
253
+ // Simple redirect without transforms or env vars
269
254
  const redirect = {
270
255
  source,
271
256
  destination,
package/dist/types.d.ts CHANGED
@@ -149,7 +149,7 @@ export interface Condition {
149
149
  }
150
150
  /**
151
151
  * Redirect matching vercel.json schema
152
- * Returned by router.redirect()
152
+ * Returned by routes.redirect()
153
153
  */
154
154
  export interface Redirect {
155
155
  source: string;
@@ -161,7 +161,7 @@ export interface Redirect {
161
161
  }
162
162
  /**
163
163
  * Rewrite matching vercel.json schema
164
- * Returned by router.rewrite()
164
+ * Returned by routes.rewrite()
165
165
  */
166
166
  export interface Rewrite {
167
167
  source: string;
@@ -171,7 +171,7 @@ export interface Rewrite {
171
171
  }
172
172
  /**
173
173
  * Header rule matching vercel.json schema
174
- * Returned by router.header() and router.cacheControl()
174
+ * Returned by routes.header() and routes.cacheControl()
175
175
  */
176
176
  export interface HeaderRule {
177
177
  source: string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Type declarations for @vercel/config
3
+ *
4
+ * Usage:
5
+ * /// <reference types="@vercel/config/v1/types" />
6
+ */
7
+ export type { VercelConfig, Framework, FunctionConfig, CronJob, GitDeploymentConfig, GitConfig, GithubConfig, ImageConfig, Header, Condition, Redirect, Rewrite, HeaderRule, RouteType, WildcardDomain, BuildConfig, BuildItem } from "../types";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Type declarations for @vercel/config
4
+ *
5
+ * Usage:
6
+ * /// <reference types="@vercel/config/v1/types" />
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/config",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "A TypeScript SDK for programmatically configuring Vercel projects",
5
5
  "bugs": {
6
6
  "url": "https://github.com/vercel/config/issues"
@@ -17,11 +17,17 @@
17
17
  "*": {
18
18
  "v1": [
19
19
  "dist/v1/index.d.ts"
20
+ ],
21
+ "v1/types": [
22
+ "dist/v1/types.d.ts"
20
23
  ]
21
24
  }
22
25
  },
23
26
  "exports": {
24
- "./v1": "./dist/v1/index.js"
27
+ "./v1": "./dist/v1/index.js",
28
+ "./v1/types": {
29
+ "types": "./dist/v1/types.d.ts"
30
+ }
25
31
  },
26
32
  "bin": {
27
33
  "@vercel/config": "./dist/cli.js"