diff --git a/package-lock.json b/package-lock.json index 46b2c0eab..7170c728b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,7 @@ "express": "^4.21.2", "minimist": "^1.2.8", "on-finished": "^2.3.0", - "read-package-up": "^11.0.0", - "semver": "^7.7.1" + "read-package-up": "^11.0.0" }, "bin": { "functions-framework": "build/src/main.js", @@ -29,7 +28,6 @@ "@types/mocha": "^10.0.0", "@types/node": "^22.13.14", "@types/on-finished": "2.3.5", - "@types/semver": "^7.7.0", "@types/sinon": "^17.0.4", "@types/supertest": "6.0.3", "gts": "6.0.2", diff --git a/package.json b/package.json index c947db932..be6782c73 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "express": "^4.21.2", "minimist": "^1.2.8", "on-finished": "^2.3.0", - "read-package-up": "^11.0.0", - "semver": "^7.7.1" + "read-package-up": "^11.0.0" }, "scripts": { "test": "mocha build/test --recursive", @@ -58,7 +57,6 @@ "@types/mocha": "^10.0.0", "@types/node": "^22.13.14", "@types/on-finished": "2.3.5", - "@types/semver": "^7.7.0", "@types/sinon": "^17.0.4", "@types/supertest": "6.0.3", "gts": "6.0.2", diff --git a/src/async_local_storage.ts b/src/async_local_storage.ts index 8d0095b34..4a29fba66 100644 --- a/src/async_local_storage.ts +++ b/src/async_local_storage.ts @@ -1,7 +1,5 @@ -import * as semver from 'semver'; import {Request, Response} from './functions'; import {NextFunction} from 'express'; -import {requiredNodeJsVersionForLogExecutionID} from './options'; import type {AsyncLocalStorage} from 'node:async_hooks'; export interface ExecutionContext { @@ -16,13 +14,6 @@ export async function asyncLocalStorageMiddleware( res: Response, next: NextFunction, ) { - if ( - semver.lt(process.versions.node, requiredNodeJsVersionForLogExecutionID) - ) { - // Skip for unsupported Node.js version. - next(); - return; - } if (!asyncLocalStorage) { const asyncHooks = await import('node:async_hooks'); asyncLocalStorage = new asyncHooks.AsyncLocalStorage(); diff --git a/src/loader.ts b/src/loader.ts index d88d43cc3..7dc3d87fe 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -19,7 +19,6 @@ */ import * as path from 'path'; -import * as semver from 'semver'; import {pathToFileURL} from 'url'; import {HandlerFunction} from './functions'; import {SignatureType} from './types'; @@ -31,6 +30,11 @@ import {getRegisteredFunction} from './function_registry'; // Exported for testing. export const MIN_NODE_VERSION_ESMODULES = '13.2.0'; +export const esModuleSupported = (() => { + const [major, minor] = process.versions.node.split('.', 2).map(Number); + return major > 13 || (major === 13 && minor >= 2); +})(); + /** * Determines whether the given module is an ES module. * @@ -104,7 +108,7 @@ export async function getUserFunction( let functionModule; const esModule = await isEsModule(functionModulePath); if (esModule) { - if (semver.lt(process.version, MIN_NODE_VERSION_ESMODULES)) { + if (esModuleSupported === false) { console.error( `Cannot load ES Module on Node.js ${process.version}. ` + `Please upgrade to Node.js v${MIN_NODE_VERSION_ESMODULES} and up.`, diff --git a/src/options.ts b/src/options.ts index 6adb5532a..b8c63cb8e 100644 --- a/src/options.ts +++ b/src/options.ts @@ -13,7 +13,6 @@ // limitations under the License. import * as minimist from 'minimist'; -import * as semver from 'semver'; import {resolve} from 'path'; import {SignatureType, isValidSignatureType} from './types'; @@ -141,24 +140,23 @@ const IgnoredRoutesOption = new ConfigurableOption( ); export const requiredNodeJsVersionForLogExecutionID = '13.0.0'; + +export const logExecutionIdSupported = + Number(process.versions.node.split('.', 1)[0]) >= 13; + const ExecutionIdOption = new ConfigurableOption( 'log-execution-id', 'LOG_EXECUTION_ID', false, x => { - const nodeVersion = process.versions.node; - const isVersionSatisfied = semver.gte( - nodeVersion, - requiredNodeJsVersionForLogExecutionID, - ); const isTrue = (typeof x === 'boolean' && x) || (typeof x === 'string' && x.toLowerCase() === 'true'); - if (isTrue && !isVersionSatisfied) { + if (isTrue && !logExecutionIdSupported) { console.warn( `Execution id is only supported with Node.js versions ${requiredNodeJsVersionForLogExecutionID} and above. Your - current version is ${nodeVersion}. Please upgrade.`, + current version is ${process.versions.node}. Please upgrade.`, ); console.warn('Proceeding with execution id support disabled...'); return false; diff --git a/src/server.ts b/src/server.ts index cdca107b7..65066023d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -25,7 +25,7 @@ import {timeoutMiddleware} from './middleware/timeout'; import {wrapUserFunction} from './function_wrappers'; import {asyncLocalStorageMiddleware} from './async_local_storage'; import {executionContextMiddleware} from './execution_context'; -import {FrameworkOptions} from './options'; +import {FrameworkOptions, logExecutionIdSupported} from './options'; /** * Creates and configures an Express application and returns an HTTP server @@ -106,8 +106,11 @@ export function getServer( // Get execution context. app.use(executionContextMiddleware); + // Store execution context to async local storge. - app.use(asyncLocalStorageMiddleware); + if (logExecutionIdSupported) { + app.use(asyncLocalStorageMiddleware); + } if ( options.signatureType === 'event' || diff --git a/test/async_local_storage.ts b/test/async_local_storage.ts index a10a08c43..1fd6ea4ca 100644 --- a/test/async_local_storage.ts +++ b/test/async_local_storage.ts @@ -6,9 +6,9 @@ import { import {Request, Response} from '../src/functions'; import {NextFunction} from 'express'; import * as assert from 'assert'; -import * as semver from 'semver'; +import {logExecutionIdSupported} from '../src/options'; -const runOrSkip = semver.lt(process.versions.node, '13.0.0') ? it.skip : it; +const runOrSkip = logExecutionIdSupported ? it.skip : it; describe('asyncLocalStorageMiddleware', () => { runOrSkip('async local storage', async () => { diff --git a/test/loader.ts b/test/loader.ts index 272ab29ef..dd0b093fe 100644 --- a/test/loader.ts +++ b/test/loader.ts @@ -14,7 +14,6 @@ import * as assert from 'assert'; import * as express from 'express'; -import * as semver from 'semver'; import * as functions from '../src/functions'; import * as loader from '../src/loader'; import * as FunctionRegistry from '../src/function_registry'; @@ -80,7 +79,7 @@ describe('loading function', () => { ); return loadedFunction?.userFunction as functions.HttpFunction; }; - if (semver.lt(process.version, loader.MIN_NODE_VERSION_ESMODULES)) { + if (loader.esModuleSupported === false) { it(`should fail to load function in an ES module ${test.name}`, async () => { void assert.rejects(loadFn); }); diff --git a/test/options.ts b/test/options.ts index ece78a43a..069e78d6f 100644 --- a/test/options.ts +++ b/test/options.ts @@ -13,12 +13,11 @@ // limitations under the License. import * as assert from 'assert'; -import * as semver from 'semver'; import {resolve} from 'path'; import { parseOptions, FrameworkOptions, - requiredNodeJsVersionForLogExecutionID, + logExecutionIdSupported, } from '../src/options'; describe('parseOptions', () => { @@ -202,9 +201,7 @@ describe('parseOptions', () => { executionIdTestData.forEach(testCase => { it(testCase.name, () => { const options = parseOptions(testCase.cliOpts, testCase.envVars); - if ( - semver.lt(process.versions.node, requiredNodeJsVersionForLogExecutionID) - ) { + if (logExecutionIdSupported === false) { assert.strictEqual(options.enableExecutionId, false); } else { assert.strictEqual(options.enableExecutionId, true);