@@ -62,8 +62,13 @@ export class InputResolver {
6262 // Resolve block references
6363 let resolvedValue = this . resolveBlockReferences ( value , context , block )
6464
65+ // Check if this is an API key field
66+ const isApiKey = key . toLowerCase ( ) . includes ( 'apikey' ) ||
67+ key . toLowerCase ( ) . includes ( 'secret' ) ||
68+ key . toLowerCase ( ) . includes ( 'token' )
69+
6570 // Resolve environment variables
66- resolvedValue = this . resolveEnvVariables ( resolvedValue )
71+ resolvedValue = this . resolveEnvVariables ( resolvedValue , isApiKey )
6772
6873 // Convert JSON strings to objects if possible
6974 try {
@@ -239,40 +244,89 @@ export class InputResolver {
239244 return resolvedValue
240245 }
241246
247+ /**
248+ * Determines if a string contains a properly formatted environment variable reference.
249+ * Valid references are either:
250+ * 1. A standalone env var (entire string is just {{ENV_VAR}})
251+ * 2. An explicit env var with clear boundaries (usually within a URL or similar)
252+ *
253+ * @param value - The string to check
254+ * @returns Whether this contains a properly formatted env var reference
255+ */
256+ private containsProperEnvVarReference ( value : string ) : boolean {
257+ if ( ! value || typeof value !== 'string' ) return false
258+
259+ // Case 1: String is just a single environment variable
260+ if ( value . trim ( ) . match ( / ^ \{ \{ [ ^ { } ] + \} \} $ / ) ) {
261+ return true
262+ }
263+
264+ // Case 2: Check for environment variables in specific contexts
265+ // For example, in URLs, bearer tokens, etc.
266+ const properContextPatterns = [
267+ // Auth header patterns
268+ / B e a r e r \s + \{ \{ [ ^ { } ] + \} \} / i,
269+ / A u t h o r i z a t i o n : \s + B e a r e r \s + \{ \{ [ ^ { } ] + \} \} / i,
270+ / A u t h o r i z a t i o n : \s + \{ \{ [ ^ { } ] + \} \} / i,
271+
272+ // API key in URL patterns
273+ / [ ? & ] a p i [ _ - ] ? k e y = \{ \{ [ ^ { } ] + \} \} / i,
274+ / [ ? & ] k e y = \{ \{ [ ^ { } ] + \} \} / i,
275+ / [ ? & ] t o k e n = \{ \{ [ ^ { } ] + \} \} / i,
276+
277+ // API key in header patterns
278+ / X - A P I - K e y : \s + \{ \{ [ ^ { } ] + \} \} / i,
279+ / a p i [ _ - ] ? k e y : \s + \{ \{ [ ^ { } ] + \} \} / i
280+ ]
281+
282+ return properContextPatterns . some ( pattern => pattern . test ( value ) )
283+ }
284+
242285 /**
243286 * Resolves environment variables in any value ({{ENV_VAR}}).
287+ * Only processes environment variables in apiKey fields or when explicitly needed.
244288 *
245289 * @param value - Value that may contain environment variable references
290+ * @param isApiKey - Whether this is an API key field (requires special env var handling)
246291 * @returns Value with environment variables resolved
247292 * @throws Error if referenced environment variable is not found
248293 */
249- resolveEnvVariables ( value : any ) : any {
294+ resolveEnvVariables ( value : any , isApiKey : boolean = false ) : any {
250295 if ( typeof value === 'string' ) {
251- const envMatches = value . match ( / \{ \{ ( [ ^ } ] + ) \} \} / g)
252- if ( envMatches ) {
253- let resolvedValue = value
254- for ( const match of envMatches ) {
255- const envKey = match . slice ( 2 , - 2 )
256- const envValue = this . environmentVariables [ envKey ]
257-
258- if ( envValue === undefined ) {
259- throw new Error ( `Environment variable "${ envKey } " was not found.` )
260- }
296+ // Only process environment variables if:
297+ // 1. This is an API key field
298+ // 2. String is a complete environment variable reference ({{ENV_VAR}})
299+ // 3. String contains environment variable references in proper contexts (auth headers, URLs)
300+ const isExplicitEnvVar = value . trim ( ) . startsWith ( '{{' ) && value . trim ( ) . endsWith ( '}}' )
301+ const hasProperEnvVarReferences = this . containsProperEnvVarReference ( value )
302+
303+ if ( isApiKey || isExplicitEnvVar || hasProperEnvVarReferences ) {
304+ const envMatches = value . match ( / \{ \{ ( [ ^ } ] + ) \} \} / g)
305+ if ( envMatches ) {
306+ let resolvedValue = value
307+ for ( const match of envMatches ) {
308+ const envKey = match . slice ( 2 , - 2 )
309+ const envValue = this . environmentVariables [ envKey ]
310+
311+ if ( envValue === undefined ) {
312+ throw new Error ( `Environment variable "${ envKey } " was not found.` )
313+ }
261314
262- resolvedValue = resolvedValue . replace ( match , envValue )
315+ resolvedValue = resolvedValue . replace ( match , envValue )
316+ }
317+ return resolvedValue
263318 }
264- return resolvedValue
265319 }
266320 return value
267321 }
268322
269323 if ( Array . isArray ( value ) ) {
270- return value . map ( ( item ) => this . resolveEnvVariables ( item ) )
324+ return value . map ( ( item ) => this . resolveEnvVariables ( item , isApiKey ) )
271325 }
272326
273327 if ( value && typeof value === 'object' ) {
274328 return Object . entries ( value ) . reduce (
275- ( acc , [ k , v ] ) => ( { ...acc , [ k ] : this . resolveEnvVariables ( v ) } ) ,
329+ ( acc , [ k , v ] ) => ( { ...acc , [ k ] : this . resolveEnvVariables ( v , k . toLowerCase ( ) === 'apikey' ) } ) ,
276330 { }
277331 )
278332 }
@@ -303,8 +357,12 @@ export class InputResolver {
303357 if ( typeof value === 'string' ) {
304358 // First resolve block references
305359 const resolvedReferences = this . resolveBlockReferences ( value , context , currentBlock )
306- // Then resolve environment variables
307- return this . resolveEnvVariables ( resolvedReferences )
360+
361+ // Check if this is an API key field
362+ const isApiKey = this . isApiKeyField ( currentBlock , value )
363+
364+ // Then resolve environment variables with the API key flag
365+ return this . resolveEnvVariables ( resolvedReferences , isApiKey )
308366 }
309367
310368 // Handle arrays
@@ -316,6 +374,7 @@ export class InputResolver {
316374 if ( typeof value === 'object' ) {
317375 const result : Record < string , any > = { }
318376 for ( const [ k , v ] of Object . entries ( value ) ) {
377+ const isApiKey = k . toLowerCase ( ) === 'apikey'
319378 result [ k ] = this . resolveNestedStructure ( v , context , currentBlock )
320379 }
321380 return result
@@ -325,6 +384,38 @@ export class InputResolver {
325384 return value
326385 }
327386
387+ /**
388+ * Determines if a given field in a block is an API key field.
389+ *
390+ * @param block - Block containing the field
391+ * @param value - Value to check
392+ * @returns Whether this appears to be an API key field
393+ */
394+ private isApiKeyField ( block : SerializedBlock , value : string ) : boolean {
395+ // Check if the block is an API or agent block (which typically have API keys)
396+ const blockType = block . metadata ?. id
397+ if ( blockType !== 'api' && blockType !== 'agent' ) {
398+ return false
399+ }
400+
401+ // Look for the value in the block params
402+ for ( const [ key , paramValue ] of Object . entries ( block . config . params ) ) {
403+ if ( paramValue === value ) {
404+ // Check if key name suggests it's an API key
405+ const normalizedKey = key . toLowerCase ( ) . replace ( / [ _ \- \s ] / g, '' )
406+ return (
407+ normalizedKey === 'apikey' ||
408+ normalizedKey . includes ( 'apikey' ) ||
409+ normalizedKey . includes ( 'secretkey' ) ||
410+ normalizedKey . includes ( 'accesskey' ) ||
411+ normalizedKey . includes ( 'token' )
412+ )
413+ }
414+ }
415+
416+ return false
417+ }
418+
328419 /**
329420 * Formats a value for use in condition blocks.
330421 * Handles strings, null, undefined, and objects appropriately.
0 commit comments