diff --git a/package-lock.json b/package-lock.json index 5f69b14e..e8ad8eb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,7 @@ "express": "^4.16.4", "minimist": "^1.2.7", "on-finished": "^2.3.0", - "read-pkg-up": "^7.0.1", - "semver": "^7.3.5" + "read-pkg-up": "^7.0.1" }, "bin": { "functions-framework": "build/src/main.js", @@ -3660,6 +3659,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -4894,6 +4894,7 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -5702,7 +5703,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yargs": { "version": "16.2.0", @@ -8482,6 +8484,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -9349,6 +9352,7 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -9968,7 +9972,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index 052dae81..9242d33e 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "express": "^4.16.4", "minimist": "^1.2.7", "on-finished": "^2.3.0", - "read-pkg-up": "^7.0.1", - "semver": "^7.3.5" + "read-pkg-up": "^7.0.1" }, "scripts": { "test": "mocha build/test --recursive", diff --git a/src/async_local_storage.ts b/src/async_local_storage.ts index 25cd64db..201561ab 100644 --- a/src/async_local_storage.ts +++ b/src/async_local_storage.ts @@ -1,7 +1,6 @@ -import * as semver from 'semver'; import {Request, Response} from './functions'; import {NextFunction} from 'express'; -import {requiredNodeJsVersionForLogExecutionID} from './options'; +import {satisfiedRequiredNodeJsVersionForLogExecutionID} from './options'; import type {AsyncLocalStorage} from 'node:async_hooks'; export interface ExecutionContext { @@ -17,28 +16,27 @@ export async function asyncLocalStorageMiddleware( res: Response, next: NextFunction ) { - if ( - semver.lt(process.versions.node, requiredNodeJsVersionForLogExecutionID) - ) { + if (satisfiedRequiredNodeJsVersionForLogExecutionID) { + if (!asyncLocalStorage) { + const asyncHooks = await import('node:async_hooks'); + asyncLocalStorage = new asyncHooks.AsyncLocalStorage(); + } + + asyncLocalStorage.run( + { + executionId: req.executionId, + traceId: req.traceId, + spanId: req.spanId, + }, + () => { + next(); + } + ); + } else { // Skip for unsupported Node.js version. next(); return; } - if (!asyncLocalStorage) { - const asyncHooks = await import('node:async_hooks'); - asyncLocalStorage = new asyncHooks.AsyncLocalStorage(); - } - - asyncLocalStorage.run( - { - executionId: req.executionId, - traceId: req.traceId, - spanId: req.spanId, - }, - () => { - next(); - } - ); } export function getCurrentContext(): ExecutionContext | undefined { diff --git a/src/loader.ts b/src/loader.ts index 894bfce8..cdb28d21 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -19,7 +19,6 @@ */ import * as path from 'path'; -import * as semver from 'semver'; import * as readPkgUp from 'read-pkg-up'; import {pathToFileURL} from 'url'; import {HandlerFunction} from './functions'; @@ -31,6 +30,12 @@ import {getRegisteredFunction} from './function_registry'; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility // Exported for testing. export const MIN_NODE_VERSION_ESMODULES = '13.2.0'; +export const satisfiedMinNodeVersionESModules = (function ( + nodeVersion = process.versions.node +): boolean { + const [major, minor] = nodeVersion.slice(1).split('.', 2).map(Number); + return major > 13 || (major === 13 && minor >= 2); +})(); /** * Determines whether the given module is an ES module. @@ -104,7 +109,7 @@ export async function getUserFunction( let functionModule; const esModule = await isEsModule(functionModulePath); if (esModule) { - if (semver.lt(process.version, MIN_NODE_VERSION_ESMODULES)) { + if (!satisfiedMinNodeVersionESModules) { 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 96de71c8..6b1ad2df 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'; @@ -132,20 +131,23 @@ const TimeoutOption = new ConfigurableOption( ); export const requiredNodeJsVersionForLogExecutionID = '13.0.0'; +export const satisfiedRequiredNodeJsVersionForLogExecutionID = (function ( + nodeVersion = process.versions.node +) { + const [major] = nodeVersion.split('.', 1).map(Number); + return major >= 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 && !satisfiedRequiredNodeJsVersionForLogExecutionID) { console.warn( `Execution id is only supported with Node.js versions ${requiredNodeJsVersionForLogExecutionID} and above. Your diff --git a/test/loader.ts b/test/loader.ts index 1fd2968b..771ff732 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,16 +79,16 @@ describe('loading function', () => { ); return loadedFunction?.userFunction as functions.HttpFunction; }; - if (semver.lt(process.version, loader.MIN_NODE_VERSION_ESMODULES)) { - it(`should fail to load function in an ES module ${test.name}`, async () => { - assert.rejects(loadFn); - }); - } else { + if (loader.satisfiedMinNodeVersionESModules) { it(`should load function in an ES module ${test.name}`, async () => { const loadedFunction = await loadFn(); const returned = loadedFunction(express.request, express.response); assert.strictEqual(returned, 'PASS'); }); + } else { + it(`should fail to load function in an ES module ${test.name}`, async () => { + assert.rejects(loadFn); + }); } } diff --git a/test/options.ts b/test/options.ts index bf1619d0..0944e3da 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, + satisfiedRequiredNodeJsVersionForLogExecutionID, } from '../src/options'; describe('parseOptions', () => { @@ -194,13 +193,10 @@ describe('parseOptions', () => { executionIdTestData.forEach(testCase => { it(testCase.name, () => { const options = parseOptions(testCase.cliOpts, testCase.envVars); - if ( - semver.lt(process.versions.node, requiredNodeJsVersionForLogExecutionID) - ) { - assert.strictEqual(options.enableExecutionId, false); - } else { - assert.strictEqual(options.enableExecutionId, true); - } + assert.strictEqual( + options.enableExecutionId, + satisfiedRequiredNodeJsVersionForLogExecutionID + ); }); });