refactor: clarify wrapV2 unsupported function errors#315
Conversation
There was a problem hiding this comment.
Code Review
This pull request improves the error message thrown when wrapping unsupported functions in wrapV2 by dynamically resolving the firebase-functions peer dependency version from package.json. Feedback on these changes suggests safeguarding the hasRun utility to prevent runtime TypeErrors on truthy primitives, and replacing dynamic require calls with static ones to ensure compatibility with bundlers and static analysis tools.
| function hasRun<T extends CloudEvent<unknown>>( | ||
| cf: CloudFunction<T> | CallableFunction<any, any> | ||
| ): cf is CloudFunction<T> { | ||
| return !!cf && 'run' in cf && !!cf.run; | ||
| } |
There was a problem hiding this comment.
The hasRun function uses the in operator ('run' in cf) after checking !!cf. However, if cf is a truthy primitive (such as a string or a number), the in operator will throw a TypeError: Cannot use 'in' operator to search for 'run' in .... This bypasses the custom, helpful error message.
We should guard the check by ensuring cf is either an object or a function before using the in operator.
function hasRun<T extends CloudEvent<unknown>>(
cf: CloudFunction<T> | CallableFunction<any, any>
): cf is CloudFunction<T> {
return (
cf !== null &&
(typeof cf === 'object' || typeof cf === 'function') &&
'run' in cf &&
!!cf.run
);
}| const PACKAGE_JSON_PATHS = ['../package.json', '../../package.json']; | ||
|
|
||
| export function getFirebaseFunctionsPeerDependency() { | ||
| for (const packageJsonPath of PACKAGE_JSON_PATHS) { | ||
| try { | ||
| const firebaseFunctionsVersion = | ||
| require(packageJsonPath).peerDependencies?.['firebase-functions']; | ||
| if (firebaseFunctionsVersion) { | ||
| return firebaseFunctionsVersion; | ||
| } | ||
| } catch (err) {} | ||
| } | ||
| return 'a supported version'; | ||
| } |
There was a problem hiding this comment.
Using dynamic require(packageJsonPath) with a variable path can cause issues with static analysis tools, bundlers (like Webpack, Rollup, or esbuild), and monorepo tooling, which often fail to resolve or bundle dynamic requires.
Instead, we can use static require calls wrapped in individual try-catch blocks. This is fully compatible with bundlers and achieves the same fallback behavior without needing a dynamic array of paths.
export function getFirebaseFunctionsPeerDependency() {
try {
return require('../package.json').peerDependencies?.['firebase-functions'];
} catch (err) {
try {
return require('../../package.json').peerDependencies?.['firebase-functions'];
} catch (err2) {
return 'a supported version';
}
}
}
Summary
Resolves #164
Clarifies unsupported
wrapV2function errors and removes the stale README compatibility note.Problems
firebase-functionsminimum version.wrapV2unsupported-function error hard-coded an old version floor..runcan mean the input is not a V2 CloudFunction or was created with an unsupportedfirebase-functionsversion.Solutions
firebase-functionspeer range frompackage.json.wrapV2validation to throw a more actionable error that includes the dynamic peer range.wrapV2inputs.Validation
env -u GOOGLE_APPLICATION_CREDENTIALS npm test