@vercel/config
Advanced tools
+32
-3
@@ -31,4 +31,19 @@ #!/usr/bin/env node | ||
| /** | ||
| * Read the user's vercel.ts file (or fallback to router.config.ts for backwards compatibility) | ||
| * Named exports that should NOT be auto-converted to config | ||
| * (these are route-based features that compile into the routes array, or internal module properties) | ||
| */ | ||
| const ROUTE_BASED_EXPORTS = new Set([ | ||
| 'default', | ||
| 'routes', | ||
| 'redirects', | ||
| 'rewrites', | ||
| 'headers', | ||
| 'crons', | ||
| 'env', | ||
| 'cacheControl', | ||
| '__esModule' // ES module metadata | ||
| ]); | ||
| /** | ||
| * Read the user's vercel.ts file and collect both default export and export const declarations | ||
| */ | ||
| async function configureRouter() { | ||
@@ -40,4 +55,18 @@ var _a; | ||
| const configPath = (0, fs_2.existsSync)(vercelTsPath) ? vercelTsPath : routerConfigPath; | ||
| const routerConfig = (await (_a = configPath, Promise.resolve().then(() => __importStar(require(_a))))).default; | ||
| return routerConfig; | ||
| // Import the entire module to get both default and named exports | ||
| const module = await (_a = configPath, Promise.resolve().then(() => __importStar(require(_a)))); | ||
| // Start with the default export (router.getConfig()) | ||
| const routerConfig = module.default || {}; | ||
| // Auto-collect all export const declarations (except route-based ones) | ||
| const exportedConstants = {}; | ||
| for (const [key, value] of Object.entries(module)) { | ||
| if (!ROUTE_BASED_EXPORTS.has(key)) { | ||
| exportedConstants[key] = value; | ||
| } | ||
| } | ||
| // Merge: export const declarations take precedence over default export | ||
| return { | ||
| ...routerConfig, | ||
| ...exportedConstants | ||
| }; | ||
| } | ||
@@ -44,0 +73,0 @@ /** |
+86
-5
@@ -218,8 +218,8 @@ /** | ||
| * Headers to set/modify on the incoming request. | ||
| * Use param() for path parameters and runtimeEnv() for environment variables. | ||
| * Sets the key and value if missing. | ||
| * | ||
| * @example | ||
| * requestHeaders: { | ||
| * 'x-user-id': param('userId'), | ||
| * 'authorization': `Bearer ${runtimeEnv('API_TOKEN')}` | ||
| * 'x-user-id': userId, | ||
| * 'authorization': `Bearer ${env.API_TOKEN}` | ||
| * } | ||
@@ -230,7 +230,7 @@ */ | ||
| * Headers to set/modify on the outgoing response. | ||
| * Use param() for path parameters and runtimeEnv() for environment variables. | ||
| * Sets the key and value if missing. | ||
| * | ||
| * @example | ||
| * responseHeaders: { | ||
| * 'x-post-id': param('postId') | ||
| * 'x-post-id': postId | ||
| * } | ||
@@ -241,2 +241,3 @@ */ | ||
| * Query parameters to set/modify on the request. | ||
| * Sets the key and value if missing. | ||
| * | ||
@@ -249,2 +250,56 @@ * @example | ||
| requestQuery?: Record<string, string | string[]>; | ||
| /** | ||
| * Headers to append to the incoming request. | ||
| * Appends args to the value of the key, and will set if missing. | ||
| * | ||
| * @example | ||
| * appendRequestHeaders: { | ||
| * 'x-custom': 'value' | ||
| * } | ||
| */ | ||
| appendRequestHeaders?: Record<string, string | string[]>; | ||
| /** | ||
| * Headers to append to the outgoing response. | ||
| * Appends args to the value of the key, and will set if missing. | ||
| * | ||
| * @example | ||
| * appendResponseHeaders: { | ||
| * 'x-custom': 'value' | ||
| * } | ||
| */ | ||
| appendResponseHeaders?: Record<string, string | string[]>; | ||
| /** | ||
| * Query parameters to append to the request. | ||
| * Appends args to the value of the key, and will set if missing. | ||
| * | ||
| * @example | ||
| * appendRequestQuery: { | ||
| * 'tag': 'value' | ||
| * } | ||
| */ | ||
| appendRequestQuery?: Record<string, string | string[]>; | ||
| /** | ||
| * Headers to delete from the incoming request. | ||
| * Deletes the key entirely if args is not provided; otherwise, it will delete the value of args from the matching key. | ||
| * | ||
| * @example | ||
| * deleteRequestHeaders: ['x-remove-this', 'x-remove-that'] | ||
| */ | ||
| deleteRequestHeaders?: string[]; | ||
| /** | ||
| * Headers to delete from the outgoing response. | ||
| * Deletes the key entirely if args is not provided; otherwise, it will delete the value of args from the matching key. | ||
| * | ||
| * @example | ||
| * deleteResponseHeaders: ['x-powered-by'] | ||
| */ | ||
| deleteResponseHeaders?: string[]; | ||
| /** | ||
| * Query parameters to delete from the request. | ||
| * Deletes the key entirely if args is not provided; otherwise, it will delete the value of args from the matching key. | ||
| * | ||
| * @example | ||
| * deleteRequestQuery: ['debug', 'trace'] | ||
| */ | ||
| deleteRequestQuery?: string[]; | ||
| } | ||
@@ -436,2 +491,4 @@ /** | ||
| * Internal helper to convert TransformOptions to Transform array | ||
| * @param options Transform options to convert | ||
| * @param trackedEnvVars Optional set of environment variables that were accessed via the env proxy | ||
| */ | ||
@@ -468,2 +525,8 @@ private transformOptionsToTransforms; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| appendRequestHeaders?: Record<string, string | string[]>; | ||
| appendResponseHeaders?: Record<string, string | string[]>; | ||
| appendRequestQuery?: Record<string, string | string[]>; | ||
| deleteRequestHeaders?: string[]; | ||
| deleteResponseHeaders?: string[]; | ||
| deleteRequestQuery?: string[]; | ||
| } | ((params: Record<string, string> & { | ||
@@ -477,2 +540,8 @@ env: any; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| appendRequestHeaders?: Record<string, string | string[]>; | ||
| appendResponseHeaders?: Record<string, string | string[]>; | ||
| appendRequestQuery?: Record<string, string | string[]>; | ||
| deleteRequestHeaders?: string[]; | ||
| deleteResponseHeaders?: string[]; | ||
| deleteRequestQuery?: string[]; | ||
| })): this; | ||
@@ -519,2 +588,8 @@ /** | ||
| requestQuery?: Record<string, string | string[]>; | ||
| appendRequestHeaders?: Record<string, string | string[]>; | ||
| appendResponseHeaders?: Record<string, string | string[]>; | ||
| appendRequestQuery?: Record<string, string | string[]>; | ||
| deleteRequestHeaders?: string[]; | ||
| deleteResponseHeaders?: string[]; | ||
| deleteRequestQuery?: string[]; | ||
| } | ((params: Record<string, string> & { | ||
@@ -530,2 +605,8 @@ env: any; | ||
| requestQuery?: Record<string, string | string[]>; | ||
| appendRequestHeaders?: Record<string, string | string[]>; | ||
| appendResponseHeaders?: Record<string, string | string[]>; | ||
| appendRequestQuery?: Record<string, string | string[]>; | ||
| deleteRequestHeaders?: string[]; | ||
| deleteResponseHeaders?: string[]; | ||
| deleteRequestQuery?: string[]; | ||
| })): this; | ||
@@ -532,0 +613,0 @@ /** |
+121
-15
@@ -134,9 +134,22 @@ "use strict"; | ||
| * Internal helper to convert TransformOptions to Transform array | ||
| * @param options Transform options to convert | ||
| * @param trackedEnvVars Optional set of environment variables that were accessed via the env proxy | ||
| */ | ||
| transformOptionsToTransforms(options) { | ||
| transformOptionsToTransforms(options, trackedEnvVars) { | ||
| const transforms = []; | ||
| // Convert requestHeaders | ||
| // Helper to get env vars for a value | ||
| const getEnvVars = (value) => { | ||
| if (trackedEnvVars) { | ||
| return Array.from(trackedEnvVars).filter(envVar => { | ||
| const valueStr = Array.isArray(value) ? value.join(' ') : value; | ||
| return valueStr.includes(`$${envVar}`); | ||
| }); | ||
| } | ||
| return this.extractEnvVars(value); | ||
| }; | ||
| // SET operations | ||
| // Convert requestHeaders (set) | ||
| if (options.requestHeaders) { | ||
| for (const [key, value] of Object.entries(options.requestHeaders)) { | ||
| const envVars = this.extractEnvVars(value); | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
@@ -151,6 +164,6 @@ type: 'request.headers', | ||
| } | ||
| // Convert responseHeaders | ||
| // Convert responseHeaders (set) | ||
| if (options.responseHeaders) { | ||
| for (const [key, value] of Object.entries(options.responseHeaders)) { | ||
| const envVars = this.extractEnvVars(value); | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
@@ -165,6 +178,6 @@ type: 'response.headers', | ||
| } | ||
| // Convert requestQuery | ||
| // Convert requestQuery (set) | ||
| if (options.requestQuery) { | ||
| for (const [key, value] of Object.entries(options.requestQuery)) { | ||
| const envVars = this.extractEnvVars(value); | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
@@ -179,2 +192,73 @@ type: 'request.query', | ||
| } | ||
| // APPEND operations | ||
| // Convert appendRequestHeaders | ||
| if (options.appendRequestHeaders) { | ||
| for (const [key, value] of Object.entries(options.appendRequestHeaders)) { | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
| type: 'request.headers', | ||
| op: 'append', | ||
| target: { key }, | ||
| args: value, | ||
| ...(envVars.length > 0 && { env: envVars }), | ||
| }); | ||
| } | ||
| } | ||
| // Convert appendResponseHeaders | ||
| if (options.appendResponseHeaders) { | ||
| for (const [key, value] of Object.entries(options.appendResponseHeaders)) { | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
| type: 'response.headers', | ||
| op: 'append', | ||
| target: { key }, | ||
| args: value, | ||
| ...(envVars.length > 0 && { env: envVars }), | ||
| }); | ||
| } | ||
| } | ||
| // Convert appendRequestQuery | ||
| if (options.appendRequestQuery) { | ||
| for (const [key, value] of Object.entries(options.appendRequestQuery)) { | ||
| const envVars = getEnvVars(value); | ||
| transforms.push({ | ||
| type: 'request.query', | ||
| op: 'append', | ||
| target: { key }, | ||
| args: value, | ||
| ...(envVars.length > 0 && { env: envVars }), | ||
| }); | ||
| } | ||
| } | ||
| // DELETE operations | ||
| // Convert deleteRequestHeaders | ||
| if (options.deleteRequestHeaders) { | ||
| for (const key of options.deleteRequestHeaders) { | ||
| transforms.push({ | ||
| type: 'request.headers', | ||
| op: 'delete', | ||
| target: { key }, | ||
| }); | ||
| } | ||
| } | ||
| // Convert deleteResponseHeaders | ||
| if (options.deleteResponseHeaders) { | ||
| for (const key of options.deleteResponseHeaders) { | ||
| transforms.push({ | ||
| type: 'response.headers', | ||
| op: 'delete', | ||
| target: { key }, | ||
| }); | ||
| } | ||
| } | ||
| // Convert deleteRequestQuery | ||
| if (options.deleteRequestQuery) { | ||
| for (const key of options.deleteRequestQuery) { | ||
| transforms.push({ | ||
| type: 'request.query', | ||
| op: 'delete', | ||
| target: { key }, | ||
| }); | ||
| } | ||
| } | ||
| return transforms; | ||
@@ -209,6 +293,8 @@ } | ||
| let options; | ||
| let trackedEnvVars; | ||
| // Handle callback syntax | ||
| if (typeof optionsOrCallback === 'function') { | ||
| const pathParams = this.extractPathParams(source); | ||
| const { proxy: envProxy } = this.createEnvProxy(); | ||
| const { proxy: envProxy, accessedVars } = this.createEnvProxy(); | ||
| trackedEnvVars = accessedVars; | ||
| // Create params object with path parameters as $paramName | ||
@@ -227,3 +313,3 @@ const paramsObj = {}; | ||
| // Extract transform options | ||
| const { requestHeaders, responseHeaders, requestQuery, has, missing } = options || {}; | ||
| const { requestHeaders, responseHeaders, requestQuery, appendRequestHeaders, appendResponseHeaders, appendRequestQuery, deleteRequestHeaders, deleteResponseHeaders, deleteRequestQuery, has, missing } = options || {}; | ||
| const transformOpts = { | ||
@@ -233,6 +319,15 @@ requestHeaders, | ||
| requestQuery, | ||
| appendRequestHeaders, | ||
| appendResponseHeaders, | ||
| appendRequestQuery, | ||
| deleteRequestHeaders, | ||
| deleteResponseHeaders, | ||
| deleteRequestQuery, | ||
| }; | ||
| // Convert to transforms if any transform options provided | ||
| const transforms = requestHeaders || responseHeaders || requestQuery | ||
| ? this.transformOptionsToTransforms(transformOpts) | ||
| const hasTransforms = requestHeaders || responseHeaders || requestQuery || | ||
| appendRequestHeaders || appendResponseHeaders || appendRequestQuery || | ||
| deleteRequestHeaders || deleteResponseHeaders || deleteRequestQuery; | ||
| const transforms = hasTransforms | ||
| ? this.transformOptionsToTransforms(transformOpts, trackedEnvVars) | ||
| : undefined; | ||
@@ -306,6 +401,8 @@ this.rewriteRules.push({ | ||
| let options; | ||
| let trackedEnvVars; | ||
| // Handle callback syntax | ||
| if (typeof optionsOrCallback === 'function') { | ||
| const pathParams = this.extractPathParams(source); | ||
| const { proxy: envProxy } = this.createEnvProxy(); | ||
| const { proxy: envProxy, accessedVars } = this.createEnvProxy(); | ||
| trackedEnvVars = accessedVars; | ||
| // Create params object with path parameters as $paramName | ||
@@ -324,5 +421,8 @@ const paramsObj = {}; | ||
| // Extract transform options | ||
| const { requestHeaders, responseHeaders, requestQuery, permanent, statusCode, has, missing, } = options || {}; | ||
| const { requestHeaders, responseHeaders, requestQuery, appendRequestHeaders, appendResponseHeaders, appendRequestQuery, deleteRequestHeaders, deleteResponseHeaders, deleteRequestQuery, permanent, statusCode, has, missing, } = options || {}; | ||
| // If transforms are provided, create a route instead of a redirect | ||
| if (requestHeaders || responseHeaders || requestQuery) { | ||
| const hasTransforms = requestHeaders || responseHeaders || requestQuery || | ||
| appendRequestHeaders || appendResponseHeaders || appendRequestQuery || | ||
| deleteRequestHeaders || deleteResponseHeaders || deleteRequestQuery; | ||
| if (hasTransforms) { | ||
| const transformOpts = { | ||
@@ -332,4 +432,10 @@ requestHeaders, | ||
| requestQuery, | ||
| appendRequestHeaders, | ||
| appendResponseHeaders, | ||
| appendRequestQuery, | ||
| deleteRequestHeaders, | ||
| deleteResponseHeaders, | ||
| deleteRequestQuery, | ||
| }; | ||
| const transforms = this.transformOptionsToTransforms(transformOpts); | ||
| const transforms = this.transformOptionsToTransforms(transformOpts, trackedEnvVars); | ||
| this.routeRules.push({ | ||
@@ -336,0 +442,0 @@ src: source, |
+1
-1
| { | ||
| "name": "@vercel/config", | ||
| "version": "0.0.10", | ||
| "version": "0.0.12", | ||
| "description": "A TypeScript SDK for programmatically generating Vercel configuration files", | ||
@@ -5,0 +5,0 @@ "bugs": { |
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
66785
14.79%1738
14.19%