@vercel/config
Advanced tools
+85
-11
@@ -356,2 +356,6 @@ /** | ||
| /** | ||
| * Path to a JSON file containing bulk redirect rules. | ||
| */ | ||
| bulkRedirectsPath?: string; | ||
| /** | ||
| * Array of cron definitions for scheduled invocations. | ||
@@ -382,5 +386,42 @@ */ | ||
| private trailingSlashConfig; | ||
| private bulkRedirectsPathConfig; | ||
| private buildCommandConfig; | ||
| private installCommandConfig; | ||
| /** | ||
| * Property setter for cleanUrls configuration. | ||
| */ | ||
| set cleanUrls(value: boolean | undefined); | ||
| /** | ||
| * Property getter for cleanUrls configuration. | ||
| */ | ||
| get cleanUrls(): boolean | undefined; | ||
| /** | ||
| * Property setter for trailingSlash configuration. | ||
| */ | ||
| set trailingSlash(value: boolean | undefined); | ||
| /** | ||
| * Property getter for trailingSlash configuration. | ||
| */ | ||
| get trailingSlash(): boolean | undefined; | ||
| /** | ||
| * Property setter for bulkRedirectsPath configuration. | ||
| */ | ||
| set bulkRedirectsPath(value: string | undefined); | ||
| /** | ||
| * Property getter for bulkRedirectsPath configuration. | ||
| */ | ||
| get bulkRedirectsPath(): string | undefined; | ||
| /** | ||
| * Helper to extract path parameter names from a source pattern. | ||
| * Path parameters are identified by :paramName syntax. | ||
| * @example | ||
| * extractPathParams('/users/:userId/posts/:postId') // Returns ['userId', 'postId'] | ||
| */ | ||
| private extractPathParams; | ||
| /** | ||
| * Creates a Proxy object that tracks environment variable accesses. | ||
| * Returns both the proxy and a set of accessed environment variable names. | ||
| */ | ||
| private createEnvProxy; | ||
| /** | ||
| * Helper to extract environment variable names from a string or string array. | ||
@@ -400,16 +441,21 @@ * Environment variables are identified by the pattern $VAR_NAME where VAR_NAME | ||
| * @example | ||
| * // This will automatically enable caching for the rewrite | ||
| * import { createRouter, param, runtimeEnv } from '@vercel/router-sdk'; | ||
| * const router = createRouter(); | ||
| * // Simple rewrite | ||
| * router.rewrite('/api/(.*)', 'https://old-on-prem.com/$1') | ||
| * | ||
| * // With transforms | ||
| * // With transforms using callback | ||
| * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({ | ||
| * requestHeaders: { | ||
| * 'x-user-id': userId, | ||
| * 'authorization': `Bearer ${env.API_TOKEN}` | ||
| * } | ||
| * })); | ||
| * | ||
| * // With transforms using object (legacy) | ||
| * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', { | ||
| * requestHeaders: { | ||
| * 'x-user-id': param('userId'), | ||
| * 'authorization': `Bearer ${runtimeEnv('API_TOKEN')}` | ||
| * 'x-user-id': param('userId') | ||
| * } | ||
| * }); | ||
| */ | ||
| rewrite(source: string, destination: string, options?: { | ||
| rewrite(source: string, destination: string, optionsOrCallback?: { | ||
| has?: Condition[]; | ||
@@ -420,3 +466,11 @@ missing?: Condition[]; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| }): this; | ||
| } | ((params: Record<string, string> & { | ||
| env: any; | ||
| }) => { | ||
| has?: Condition[]; | ||
| missing?: Condition[]; | ||
| requestHeaders?: Record<string, string | string[]>; | ||
| responseHeaders?: Record<string, string | string[]>; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| })): this; | ||
| /** | ||
@@ -434,5 +488,15 @@ * Loads rewrite rules asynchronously and appends them. | ||
| * @example | ||
| * // Simple redirect | ||
| * router.redirect('/old-path', '/new-path', { permanent: true }) | ||
| * | ||
| * // With transforms | ||
| * // With transforms using callback | ||
| * router.redirect('/users/:userId', '/new-users/$1', ({userId, env}) => ({ | ||
| * permanent: true, | ||
| * requestHeaders: { | ||
| * 'x-user-id': userId, | ||
| * 'x-api-key': env.API_KEY | ||
| * } | ||
| * })) | ||
| * | ||
| * // With transforms using object (legacy) | ||
| * router.redirect('/users/:userId', '/new-users/$1', { | ||
@@ -445,3 +509,3 @@ * permanent: true, | ||
| */ | ||
| redirect(source: string, destination: string, options?: { | ||
| redirect(source: string, destination: string, optionsOrCallback?: { | ||
| permanent?: boolean; | ||
@@ -454,3 +518,13 @@ statusCode?: number; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| }): this; | ||
| } | ((params: Record<string, string> & { | ||
| env: any; | ||
| }) => { | ||
| permanent?: boolean; | ||
| statusCode?: number; | ||
| has?: Condition[]; | ||
| missing?: Condition[]; | ||
| requestHeaders?: Record<string, string | string[]>; | ||
| responseHeaders?: Record<string, string | string[]>; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| })): this; | ||
| /** | ||
@@ -457,0 +531,0 @@ * Loads redirect rules asynchronously and appends them. |
+134
-11
@@ -43,2 +43,3 @@ "use strict"; | ||
| this.trailingSlashConfig = undefined; | ||
| this.bulkRedirectsPathConfig = undefined; | ||
| this.buildCommandConfig = undefined; | ||
@@ -48,2 +49,69 @@ this.installCommandConfig = undefined; | ||
| /** | ||
| * Property setter for cleanUrls configuration. | ||
| */ | ||
| set cleanUrls(value) { | ||
| this.cleanUrlsConfig = value; | ||
| } | ||
| /** | ||
| * Property getter for cleanUrls configuration. | ||
| */ | ||
| get cleanUrls() { | ||
| return this.cleanUrlsConfig; | ||
| } | ||
| /** | ||
| * Property setter for trailingSlash configuration. | ||
| */ | ||
| set trailingSlash(value) { | ||
| this.trailingSlashConfig = value; | ||
| } | ||
| /** | ||
| * Property getter for trailingSlash configuration. | ||
| */ | ||
| get trailingSlash() { | ||
| return this.trailingSlashConfig; | ||
| } | ||
| /** | ||
| * Property setter for bulkRedirectsPath configuration. | ||
| */ | ||
| set bulkRedirectsPath(value) { | ||
| this.bulkRedirectsPathConfig = value; | ||
| } | ||
| /** | ||
| * Property getter for bulkRedirectsPath configuration. | ||
| */ | ||
| get bulkRedirectsPath() { | ||
| return this.bulkRedirectsPathConfig; | ||
| } | ||
| /** | ||
| * Helper to extract path parameter names from a source pattern. | ||
| * Path parameters are identified by :paramName syntax. | ||
| * @example | ||
| * extractPathParams('/users/:userId/posts/:postId') // Returns ['userId', 'postId'] | ||
| */ | ||
| extractPathParams(source) { | ||
| const params = []; | ||
| const matches = source.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)/g); | ||
| for (const match of matches) { | ||
| params.push(match[1]); | ||
| } | ||
| return params; | ||
| } | ||
| /** | ||
| * Creates a Proxy object that tracks environment variable accesses. | ||
| * Returns both the proxy and a set of accessed environment variable names. | ||
| */ | ||
| createEnvProxy() { | ||
| const accessedVars = new Set(); | ||
| const proxy = new Proxy({}, { | ||
| get(_target, prop) { | ||
| if (typeof prop === 'string') { | ||
| accessedVars.add(prop); | ||
| return `$${prop}`; | ||
| } | ||
| return undefined; | ||
| } | ||
| }); | ||
| return { proxy, accessedVars }; | ||
| } | ||
| /** | ||
| * Helper to extract environment variable names from a string or string array. | ||
@@ -117,18 +185,40 @@ * Environment variables are identified by the pattern $VAR_NAME where VAR_NAME | ||
| * @example | ||
| * // This will automatically enable caching for the rewrite | ||
| * import { createRouter, param, runtimeEnv } from '@vercel/router-sdk'; | ||
| * const router = createRouter(); | ||
| * // Simple rewrite | ||
| * router.rewrite('/api/(.*)', 'https://old-on-prem.com/$1') | ||
| * | ||
| * // With transforms | ||
| * // With transforms using callback | ||
| * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({ | ||
| * requestHeaders: { | ||
| * 'x-user-id': userId, | ||
| * 'authorization': `Bearer ${env.API_TOKEN}` | ||
| * } | ||
| * })); | ||
| * | ||
| * // With transforms using object (legacy) | ||
| * router.rewrite('/users/:userId', 'https://api.example.com/users/$1', { | ||
| * requestHeaders: { | ||
| * 'x-user-id': param('userId'), | ||
| * 'authorization': `Bearer ${runtimeEnv('API_TOKEN')}` | ||
| * 'x-user-id': param('userId') | ||
| * } | ||
| * }); | ||
| */ | ||
| rewrite(source, destination, options) { | ||
| rewrite(source, destination, optionsOrCallback) { | ||
| this.validateSourcePattern(source); | ||
| (0, validation_1.validateCaptureGroupReferences)(source, destination); | ||
| let options; | ||
| // Handle callback syntax | ||
| if (typeof optionsOrCallback === 'function') { | ||
| const pathParams = this.extractPathParams(source); | ||
| const { proxy: envProxy } = this.createEnvProxy(); | ||
| // Create params object with path parameters as $paramName | ||
| const paramsObj = {}; | ||
| for (const param of pathParams) { | ||
| paramsObj[param] = `$${param}`; | ||
| } | ||
| paramsObj.env = envProxy; | ||
| // Call the callback to get options | ||
| options = optionsOrCallback(paramsObj); | ||
| } | ||
| else { | ||
| options = optionsOrCallback; | ||
| } | ||
| // Extract transform options | ||
@@ -188,5 +278,15 @@ const { requestHeaders, responseHeaders, requestQuery, has, missing } = options || {}; | ||
| * @example | ||
| * // Simple redirect | ||
| * router.redirect('/old-path', '/new-path', { permanent: true }) | ||
| * | ||
| * // With transforms | ||
| * // With transforms using callback | ||
| * router.redirect('/users/:userId', '/new-users/$1', ({userId, env}) => ({ | ||
| * permanent: true, | ||
| * requestHeaders: { | ||
| * 'x-user-id': userId, | ||
| * 'x-api-key': env.API_KEY | ||
| * } | ||
| * })) | ||
| * | ||
| * // With transforms using object (legacy) | ||
| * router.redirect('/users/:userId', '/new-users/$1', { | ||
@@ -199,5 +299,22 @@ * permanent: true, | ||
| */ | ||
| redirect(source, destination, options) { | ||
| redirect(source, destination, optionsOrCallback) { | ||
| this.validateSourcePattern(source); | ||
| (0, validation_1.validateCaptureGroupReferences)(source, destination); | ||
| let options; | ||
| // Handle callback syntax | ||
| if (typeof optionsOrCallback === 'function') { | ||
| const pathParams = this.extractPathParams(source); | ||
| const { proxy: envProxy } = this.createEnvProxy(); | ||
| // Create params object with path parameters as $paramName | ||
| const paramsObj = {}; | ||
| for (const param of pathParams) { | ||
| paramsObj[param] = `$${param}`; | ||
| } | ||
| paramsObj.env = envProxy; | ||
| // Call the callback to get options | ||
| options = optionsOrCallback(paramsObj); | ||
| } | ||
| else { | ||
| options = optionsOrCallback; | ||
| } | ||
| // Extract transform options | ||
@@ -388,3 +505,6 @@ const { requestHeaders, responseHeaders, requestQuery, permanent, statusCode, has, missing, } = options || {}; | ||
| }; | ||
| // Only include buildCommand/installCommand if they're explicitly set | ||
| // Only include optional fields if they're explicitly set | ||
| if (this.bulkRedirectsPathConfig !== undefined) { | ||
| config.bulkRedirectsPath = this.bulkRedirectsPathConfig; | ||
| } | ||
| if (this.buildCommandConfig !== undefined) { | ||
@@ -407,3 +527,6 @@ config.buildCommand = this.buildCommandConfig; | ||
| }; | ||
| // Only include buildCommand/installCommand if they're explicitly set | ||
| // Only include optional fields if they're explicitly set | ||
| if (this.bulkRedirectsPathConfig !== undefined) { | ||
| config.bulkRedirectsPath = this.bulkRedirectsPathConfig; | ||
| } | ||
| if (this.buildCommandConfig !== undefined) { | ||
@@ -410,0 +533,0 @@ config.buildCommand = this.buildCommandConfig; |
+1
-1
| { | ||
| "name": "@vercel/config", | ||
| "version": "0.0.9", | ||
| "version": "0.0.10", | ||
| "description": "A TypeScript SDK for programmatically generating Vercel configuration files", | ||
@@ -5,0 +5,0 @@ "bugs": { |
+139
-26
@@ -1,46 +0,159 @@ | ||
| # Vercel Router SDK | ||
| # @vercel/config | ||
| This is a prototype of what a Router SDK could look like. | ||
| TypeScript SDK for defining Vercel configuration programmatically. | ||
| ## Installation | ||
| ```bash | ||
| npm install @vercel/config | ||
| ``` | ||
| ## Usage | ||
| 1. Install the package: | ||
| `npm install @vercel/router` | ||
| Create a `vercel.ts` file in your project root: | ||
| 2. Create a router configuration file (e.g., `router.config.ts`): | ||
| ```typescript | ||
| import { createRouter } from "@vercel/router"; | ||
| import { createRouter } from '@vercel/config'; | ||
| const router = createRouter(); | ||
| router | ||
| .rewrite("/api/(.*)", "/api/$1") | ||
| .redirect("/old-docs", "/docs", { permanent: true }) | ||
| .cacheControl("/static/(.*)", { | ||
| public: true, | ||
| maxAge: "1week", | ||
| immutable: true | ||
| }) | ||
| .setCleanUrls(true); | ||
| // Basic rewrite | ||
| router.rewrite('/api/(.*)', 'https://backend.com/$1'); | ||
| // Rewrite with transforms | ||
| router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({ | ||
| requestHeaders: { | ||
| 'x-user-id': userId, | ||
| 'authorization': `Bearer ${env.API_TOKEN}` | ||
| } | ||
| })); | ||
| // Redirects | ||
| router.redirect('/old-docs', '/docs', { permanent: true }); | ||
| // Cache control | ||
| router.cacheControl('/static/(.*)', { | ||
| public: true, | ||
| maxAge: '1week', | ||
| immutable: true | ||
| }); | ||
| // Global settings | ||
| router.cleanUrls = true; | ||
| router.trailingSlash = true; | ||
| // Bulk redirects | ||
| router.bulkRedirectsPath = './bulkRedirectsDemo.json'; | ||
| // Cron jobs | ||
| router.cron('/api/cleanup', '0 0 * * *'); | ||
| export default router.getConfig(); | ||
| ``` | ||
| 3. Add the generate-config script to your package.json: | ||
| ## Automatic Compilation | ||
| ```json | ||
| { | ||
| "scripts": { | ||
| "generate-config": "@vercel/router" | ||
| Your `vercel.ts` file is automatically compiled when you run: | ||
| ```bash | ||
| vercel build # For local builds | ||
| vercel dev # For local development | ||
| vercel deploy # For deployment | ||
| ``` | ||
| The Vercel CLI automatically compiles `vercel.ts` to `.vercel/vercel.json` before building or deploying. | ||
| ## API Reference | ||
| ### `createRouter()` | ||
| Creates a new router instance. | ||
| ### `router.rewrite(source, destination, options?)` | ||
| Add a rewrite rule. Options can be an object or a callback function that receives path parameters and environment variables. | ||
| ```typescript | ||
| // With callback for transforms | ||
| router.rewrite('/users/:userId', 'https://api.example.com/users/$1', ({userId, env}) => ({ | ||
| requestHeaders: { | ||
| 'x-user-id': userId, | ||
| 'authorization': `Bearer ${env.API_TOKEN}` | ||
| }, | ||
| responseHeaders: { | ||
| 'x-powered-by': 'My API' | ||
| }, | ||
| requestQuery: { | ||
| 'version': '2.0' | ||
| } | ||
| } | ||
| })); | ||
| // Simple rewrite without transforms | ||
| router.rewrite('/api/(.*)', 'https://backend.com/$1'); | ||
| ``` | ||
| 4. Run the script to generate your `vercel.json`: | ||
| ### `router.redirect(source, destination, options?)` | ||
| ```bash | ||
| npm run generate-config | ||
| Add a redirect rule. Options include `permanent` and `statusCode`. | ||
| ```typescript | ||
| router.redirect('/old-page', '/new-page', { permanent: true }); | ||
| router.redirect('/temp', '/elsewhere', { statusCode: 302 }); | ||
| ``` | ||
| This will generate a `vercel.json` file in your project root with all your routing configurations. | ||
| ### `router.header(source, headers, options?)` | ||
| Add custom headers for a path pattern. | ||
| ```typescript | ||
| router.header('/api/(.*)', [ | ||
| { key: 'X-Custom-Header', value: 'value' } | ||
| ]); | ||
| ``` | ||
| ### `router.cacheControl(source, options)` | ||
| Set cache control headers. Options include `public`, `private`, `maxAge`, `sMaxAge`, `immutable`, etc. | ||
| ```typescript | ||
| router.cacheControl('/static/(.*)', { | ||
| public: true, | ||
| maxAge: '1week', | ||
| immutable: true | ||
| }); | ||
| ``` | ||
| ### `router.cleanUrls` | ||
| Set whether to enable clean URLs (removes file extensions). | ||
| ```typescript | ||
| router.cleanUrls = true; | ||
| ``` | ||
| ### `router.trailingSlash` | ||
| Set whether to normalize paths to include trailing slashes. | ||
| ```typescript | ||
| router.trailingSlash = true; | ||
| ``` | ||
| ### `router.bulkRedirectsPath` | ||
| Set the path to a bulk redirects JSON file. | ||
| ```typescript | ||
| router.bulkRedirectsPath = './bulkRedirectsDemo.json'; | ||
| ``` | ||
| ## Important Notes | ||
| - **One config file only**: You cannot have both `vercel.ts` and `vercel.json`. The build will fail if both exist. | ||
| - **Automatic gitignore**: The generated `.vercel/vercel.json` file is automatically ignored by git (in the `.vercel/` directory). | ||
| - **No manual compilation needed**: The Vercel CLI handles compilation automatically - no need to run a separate command. | ||
| ## Learn More | ||
| - [Vercel Configuration Documentation](https://vercel.com/docs/projects/project-configuration) | ||
| - [Routing Documentation](https://vercel.com/docs/edge-network/routing) |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
58178
19.18%1522
14.87%160
240.43%11
22.22%