From 2ea58e7be29dfea33e50d89751d0ecf2df6e2831 Mon Sep 17 00:00:00 2001 From: abrook Date: Tue, 18 Nov 2025 11:08:40 -0500 Subject: [PATCH 1/5] Create overridable constants file --- packages/telemetry/package.json | 1 + packages/telemetry/rollup.config.js | 56 ++++++++++++++----- packages/telemetry/src/api.ts | 8 +-- .../telemetry/src/constants/auto-constants.ts | 1 + packages/telemetry/src/helpers.ts | 12 ++++ 5 files changed, 59 insertions(+), 19 deletions(-) create mode 100644 packages/telemetry/src/constants/auto-constants.ts create mode 100644 packages/telemetry/src/helpers.ts diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index 155acb0c223..fce4d95d5f4 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -112,6 +112,7 @@ "@firebase/app": "0.14.6", "@opentelemetry/sdk-trace-web": "2.1.0", "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "6.0.2", "@testing-library/dom": "10.4.1", "@testing-library/react": "16.3.0", "@types/react": "19.1.13", diff --git a/packages/telemetry/rollup.config.js b/packages/telemetry/rollup.config.js index 5ffe3844148..5c184421704 100644 --- a/packages/telemetry/rollup.config.js +++ b/packages/telemetry/rollup.config.js @@ -17,16 +17,30 @@ import json from '@rollup/plugin-json'; import copy from 'rollup-plugin-copy'; +import replacePlugin from '@rollup/plugin-replace'; import typescriptPlugin from 'rollup-plugin-typescript2'; import typescript from 'typescript'; import pkg from './package.json'; import { emitModulePackageFile } from '../../scripts/build/rollup_emit_module_package_file'; -const deps = Object.keys( - Object.assign({}, pkg.peerDependencies, pkg.dependencies) -); +const deps = [ + ...Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)), + './constants/auto-constants', +]; + +function replaceSource(path) { + return replacePlugin({ + './src/constants/auto-constants': `'${path}'`, + '../constants/auto-constants': `'${path}'`, + delimiters: ["'", "'"], + preventAssignment: true + }); +} -const buildPlugins = [typescriptPlugin({ typescript }), json()]; +const buildPlugins = [ + typescriptPlugin({ typescript }), + json(), +]; const browserBuilds = [ { @@ -36,7 +50,7 @@ const browserBuilds = [ format: 'es', sourcemap: true }, - plugins: buildPlugins, + plugins: [...buildPlugins, replaceSource('./auto-constants.js')], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, { @@ -46,7 +60,7 @@ const browserBuilds = [ format: 'cjs', sourcemap: true }, - plugins: buildPlugins, + plugins: [...buildPlugins, replaceSource('./auto-constants.js')], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } ]; @@ -59,7 +73,7 @@ const nodeBuilds = [ format: 'cjs', sourcemap: true }, - plugins: buildPlugins, + plugins: [...buildPlugins, replaceSource('./auto-constants.js')], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, { @@ -69,7 +83,7 @@ const nodeBuilds = [ format: 'es', sourcemap: true }, - plugins: [...buildPlugins, emitModulePackageFile()], + plugins: [...buildPlugins, emitModulePackageFile(), replaceSource('../auto-constants.js')], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } ]; @@ -100,7 +114,8 @@ const reactBuilds = [ dest: 'dist' } ] - }) + }), + replaceSource('../auto-constants.js') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, @@ -117,7 +132,8 @@ const reactBuilds = [ typescript, tsconfig: 'tsconfig.react.json' }), - json() + json(), + replaceSource('../auto-constants.js') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } @@ -148,7 +164,8 @@ const angularBuilds = [ dest: 'dist' } ] - }) + }), + replaceSource('../auto-constants.js') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, @@ -164,15 +181,28 @@ const angularBuilds = [ typescript, tsconfig: 'tsconfig.angular.json' }), - json() + json(), + replaceSource('../auto-constants.js') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } ]; +const autoinitBuild = [ + { + input: './src/constants/auto-constants.ts', + output: { + file: './dist/auto-constants.js', + format: 'cjs' + }, + plugins: buildPlugins + }, +]; + export default [ ...browserBuilds, ...nodeBuilds, ...reactBuilds, - ...angularBuilds + ...angularBuilds, + ...autoinitBuild ]; diff --git a/packages/telemetry/src/api.ts b/packages/telemetry/src/api.ts index f1f16896d8b..b0e227a38fe 100644 --- a/packages/telemetry/src/api.ts +++ b/packages/telemetry/src/api.ts @@ -26,6 +26,7 @@ import { Provider } from '@firebase/component'; import { AnyValueMap, SeverityNumber } from '@opentelemetry/api-logs'; import { trace } from '@opentelemetry/api'; import { TelemetryService } from './service'; +import { getAppVersion } from './helpers'; declare module '@firebase/component' { interface NameServiceMapping { @@ -97,12 +98,7 @@ export function captureError( } // Add app version metadata - let appVersion = 'unset'; - // TODO: implement app version fallback logic - if ((telemetry as TelemetryService).options?.appVersion) { - appVersion = (telemetry as TelemetryService).options!.appVersion!; - } - customAttributes[LOG_ENTRY_ATTRIBUTE_KEYS.APP_VERSION] = appVersion; + customAttributes['app.version'] = getAppVersion(telemetry); // Add session ID metadata if ( diff --git a/packages/telemetry/src/constants/auto-constants.ts b/packages/telemetry/src/constants/auto-constants.ts new file mode 100644 index 00000000000..088536584b0 --- /dev/null +++ b/packages/telemetry/src/constants/auto-constants.ts @@ -0,0 +1 @@ +export const AUTO_APP_VERSION = ''; diff --git a/packages/telemetry/src/helpers.ts b/packages/telemetry/src/helpers.ts new file mode 100644 index 00000000000..6d158d13fae --- /dev/null +++ b/packages/telemetry/src/helpers.ts @@ -0,0 +1,12 @@ +import * as constants from './constants/auto-constants'; +import { Telemetry } from './public-types'; +import { TelemetryService } from './service'; + +export function getAppVersion(telemetry: Telemetry): string { + if ((telemetry as TelemetryService).options?.appVersion) { + return (telemetry as TelemetryService).options!.appVersion!; + } else if (constants.AUTO_APP_VERSION) { + return constants.AUTO_APP_VERSION; + } + return 'unset'; +} \ No newline at end of file From 0313cc217bc38e3dde0d243f51638d4835572586 Mon Sep 17 00:00:00 2001 From: abrook Date: Thu, 20 Nov 2025 10:06:13 -0500 Subject: [PATCH 2/5] Switch auto constants to object for extensibility --- packages/telemetry/rollup.config.js | 15 ++++++------ packages/telemetry/src/api.test.ts | 15 ++++++++++++ .../telemetry/src/constants/auto-constants.ts | 20 +++++++++++++++- packages/telemetry/src/helpers.ts | 23 ++++++++++++++++--- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/packages/telemetry/rollup.config.js b/packages/telemetry/rollup.config.js index 5c184421704..18b0b85f6b5 100644 --- a/packages/telemetry/rollup.config.js +++ b/packages/telemetry/rollup.config.js @@ -25,7 +25,7 @@ import { emitModulePackageFile } from '../../scripts/build/rollup_emit_module_pa const deps = [ ...Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)), - './constants/auto-constants', + './constants/auto-constants' ]; function replaceSource(path) { @@ -37,10 +37,7 @@ function replaceSource(path) { }); } -const buildPlugins = [ - typescriptPlugin({ typescript }), - json(), -]; +const buildPlugins = [typescriptPlugin({ typescript }), json()]; const browserBuilds = [ { @@ -83,7 +80,11 @@ const nodeBuilds = [ format: 'es', sourcemap: true }, - plugins: [...buildPlugins, emitModulePackageFile(), replaceSource('../auto-constants.js')], + plugins: [ + ...buildPlugins, + emitModulePackageFile(), + replaceSource('../auto-constants.js') + ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } ]; @@ -196,7 +197,7 @@ const autoinitBuild = [ format: 'cjs' }, plugins: buildPlugins - }, + } ]; export default [ diff --git a/packages/telemetry/src/api.test.ts b/packages/telemetry/src/api.test.ts index b954987b696..db4ac5540a5 100644 --- a/packages/telemetry/src/api.test.ts +++ b/packages/telemetry/src/api.test.ts @@ -42,6 +42,7 @@ import { import { TelemetryService } from './service'; import { registerTelemetry } from './register'; import { _FirebaseInstallationsInternal } from '@firebase/installations'; +import { AUTO_CONSTANTS } from './constants/auto-constants'; const PROJECT_ID = 'my-project'; const APP_ID = 'my-appid'; @@ -278,6 +279,7 @@ describe('Top level API', () => { }); it('should use explicit app version when provided', () => { + AUTO_CONSTANTS.appVersion = '1.2.3'; // Unused const telemetry = new TelemetryService( fakeTelemetry.app, fakeTelemetry.loggerProvider @@ -296,6 +298,19 @@ describe('Top level API', () => { }); }); + it('should use auto constants if available', () => { + AUTO_CONSTANTS.appVersion = '1.2.3'; + + captureError(fakeTelemetry, 'a string error'); + + expect(emittedLogs.length).to.equal(1); + const log = emittedLogs[0]; + expect(log.attributes).to.deep.equal({ + [LOG_ENTRY_ATTRIBUTE_KEYS.APP_VERSION]: '1.2.3', + [LOG_ENTRY_ATTRIBUTE_KEYS.SESSION_ID]: MOCK_SESSION_ID + }); + }); + describe('Session Metadata', () => { it('should generate and store a new session ID if none exists', () => { captureError(fakeTelemetry, 'error'); diff --git a/packages/telemetry/src/constants/auto-constants.ts b/packages/telemetry/src/constants/auto-constants.ts index 088536584b0..608d5cbac2b 100644 --- a/packages/telemetry/src/constants/auto-constants.ts +++ b/packages/telemetry/src/constants/auto-constants.ts @@ -1 +1,19 @@ -export const AUTO_APP_VERSION = ''; +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const AUTO_CONSTANTS: any = {}; diff --git a/packages/telemetry/src/helpers.ts b/packages/telemetry/src/helpers.ts index 6d158d13fae..9ffb584d371 100644 --- a/packages/telemetry/src/helpers.ts +++ b/packages/telemetry/src/helpers.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import * as constants from './constants/auto-constants'; import { Telemetry } from './public-types'; import { TelemetryService } from './service'; @@ -5,8 +22,8 @@ import { TelemetryService } from './service'; export function getAppVersion(telemetry: Telemetry): string { if ((telemetry as TelemetryService).options?.appVersion) { return (telemetry as TelemetryService).options!.appVersion!; - } else if (constants.AUTO_APP_VERSION) { - return constants.AUTO_APP_VERSION; + } else if (constants.AUTO_CONSTANTS?.appVersion) { + return constants.AUTO_CONSTANTS.appVersion; } return 'unset'; -} \ No newline at end of file +} From d2e52bb7e78019fe2f4aded32916ca0ca8f0bbc1 Mon Sep 17 00:00:00 2001 From: abrook Date: Thu, 20 Nov 2025 10:43:45 -0500 Subject: [PATCH 3/5] Refactor --- packages/telemetry/rollup.config.js | 8 +++--- packages/telemetry/src/api.test.ts | 2 +- packages/telemetry/src/api.ts | 25 ++++--------------- .../src/{constants => }/auto-constants.ts | 0 packages/telemetry/src/helpers.ts | 21 +++++++++++++++- 5 files changed, 30 insertions(+), 26 deletions(-) rename packages/telemetry/src/{constants => }/auto-constants.ts (100%) diff --git a/packages/telemetry/rollup.config.js b/packages/telemetry/rollup.config.js index 18b0b85f6b5..d010e0a37e3 100644 --- a/packages/telemetry/rollup.config.js +++ b/packages/telemetry/rollup.config.js @@ -25,13 +25,13 @@ import { emitModulePackageFile } from '../../scripts/build/rollup_emit_module_pa const deps = [ ...Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)), - './constants/auto-constants' + './auto-constants' ]; function replaceSource(path) { return replacePlugin({ - './src/constants/auto-constants': `'${path}'`, - '../constants/auto-constants': `'${path}'`, + './src/auto-constants': `'${path}'`, + '../auto-constants': `'${path}'`, delimiters: ["'", "'"], preventAssignment: true }); @@ -191,7 +191,7 @@ const angularBuilds = [ const autoinitBuild = [ { - input: './src/constants/auto-constants.ts', + input: './src/auto-constants.ts', output: { file: './dist/auto-constants.js', format: 'cjs' diff --git a/packages/telemetry/src/api.test.ts b/packages/telemetry/src/api.test.ts index db4ac5540a5..e953da94d39 100644 --- a/packages/telemetry/src/api.test.ts +++ b/packages/telemetry/src/api.test.ts @@ -42,7 +42,7 @@ import { import { TelemetryService } from './service'; import { registerTelemetry } from './register'; import { _FirebaseInstallationsInternal } from '@firebase/installations'; -import { AUTO_CONSTANTS } from './constants/auto-constants'; +import { AUTO_CONSTANTS } from './auto-constants'; const PROJECT_ID = 'my-project'; const APP_ID = 'my-appid'; diff --git a/packages/telemetry/src/api.ts b/packages/telemetry/src/api.ts index b0e227a38fe..e65039d5b5f 100644 --- a/packages/telemetry/src/api.ts +++ b/packages/telemetry/src/api.ts @@ -16,17 +16,13 @@ */ import { _getProvider, FirebaseApp, getApp } from '@firebase/app'; -import { - LOG_ENTRY_ATTRIBUTE_KEYS, - TELEMETRY_SESSION_ID_KEY, - TELEMETRY_TYPE -} from './constants'; +import { LOG_ENTRY_ATTRIBUTE_KEYS, TELEMETRY_TYPE } from './constants'; import { Telemetry, TelemetryOptions } from './public-types'; import { Provider } from '@firebase/component'; import { AnyValueMap, SeverityNumber } from '@opentelemetry/api-logs'; import { trace } from '@opentelemetry/api'; import { TelemetryService } from './service'; -import { getAppVersion } from './helpers'; +import { getAppVersion, getSessionId } from './helpers'; declare module '@firebase/component' { interface NameServiceMapping { @@ -101,20 +97,9 @@ export function captureError( customAttributes['app.version'] = getAppVersion(telemetry); // Add session ID metadata - if ( - typeof sessionStorage !== 'undefined' && - typeof crypto?.randomUUID === 'function' - ) { - try { - let sessionId = sessionStorage.getItem(TELEMETRY_SESSION_ID_KEY); - if (!sessionId) { - sessionId = crypto.randomUUID(); - sessionStorage.setItem(TELEMETRY_SESSION_ID_KEY, sessionId); - } - customAttributes[LOG_ENTRY_ATTRIBUTE_KEYS.SESSION_ID] = sessionId; - } catch (e) { - // Ignore errors accessing sessionStorage (e.g. security restrictions) - } + const sessionId = getSessionId(); + if (sessionId) { + customAttributes[LOG_ENTRY_ATTRIBUTE_KEYS.SESSION_ID] = sessionId; } if (error instanceof Error) { diff --git a/packages/telemetry/src/constants/auto-constants.ts b/packages/telemetry/src/auto-constants.ts similarity index 100% rename from packages/telemetry/src/constants/auto-constants.ts rename to packages/telemetry/src/auto-constants.ts diff --git a/packages/telemetry/src/helpers.ts b/packages/telemetry/src/helpers.ts index 9ffb584d371..64593816d19 100644 --- a/packages/telemetry/src/helpers.ts +++ b/packages/telemetry/src/helpers.ts @@ -15,7 +15,8 @@ * limitations under the License. */ -import * as constants from './constants/auto-constants'; +import * as constants from './auto-constants'; +import { TELEMETRY_SESSION_ID_KEY } from './constants'; import { Telemetry } from './public-types'; import { TelemetryService } from './service'; @@ -27,3 +28,21 @@ export function getAppVersion(telemetry: Telemetry): string { } return 'unset'; } + +export function getSessionId(): string | undefined { + if ( + typeof sessionStorage !== 'undefined' && + typeof crypto?.randomUUID === 'function' + ) { + try { + let sessionId = sessionStorage.getItem(TELEMETRY_SESSION_ID_KEY); + if (!sessionId) { + sessionId = crypto.randomUUID(); + sessionStorage.setItem(TELEMETRY_SESSION_ID_KEY, sessionId); + } + return sessionId; + } catch (e) { + // Ignore errors accessing sessionStorage (e.g. security restrictions) + } + } +} From 2b8cbd2223afafcaf1417ba6a4467bff6177c218 Mon Sep 17 00:00:00 2001 From: abrook Date: Thu, 20 Nov 2025 10:49:25 -0500 Subject: [PATCH 4/5] Add doc comment --- packages/telemetry/src/auto-constants.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/telemetry/src/auto-constants.ts b/packages/telemetry/src/auto-constants.ts index 608d5cbac2b..daff9b0d5d1 100644 --- a/packages/telemetry/src/auto-constants.ts +++ b/packages/telemetry/src/auto-constants.ts @@ -15,5 +15,10 @@ * limitations under the License. */ +/** + * A map of constants intended to be optionally overwritten during the application build process. + * The supported keys are: + * - appVersion: string indicating the version of source code being deployed (eg. git commit hash) + */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export const AUTO_CONSTANTS: any = {}; From ad7a709b981211afa96f541bc65ae8ddfc064e0b Mon Sep 17 00:00:00 2001 From: abrook Date: Thu, 20 Nov 2025 13:30:09 -0500 Subject: [PATCH 5/5] add es build --- packages/telemetry/rollup.config.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/telemetry/rollup.config.js b/packages/telemetry/rollup.config.js index d010e0a37e3..5408855d192 100644 --- a/packages/telemetry/rollup.config.js +++ b/packages/telemetry/rollup.config.js @@ -47,7 +47,7 @@ const browserBuilds = [ format: 'es', sourcemap: true }, - plugins: [...buildPlugins, replaceSource('./auto-constants.js')], + plugins: [...buildPlugins, replaceSource('./auto-constants.mjs')], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, { @@ -83,7 +83,7 @@ const nodeBuilds = [ plugins: [ ...buildPlugins, emitModulePackageFile(), - replaceSource('../auto-constants.js') + replaceSource('../auto-constants.mjs') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) } @@ -116,7 +116,7 @@ const reactBuilds = [ } ] }), - replaceSource('../auto-constants.js') + replaceSource('../auto-constants.mjs') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, @@ -166,7 +166,7 @@ const angularBuilds = [ } ] }), - replaceSource('../auto-constants.js') + replaceSource('../auto-constants.mjs') ], external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) }, @@ -197,6 +197,14 @@ const autoinitBuild = [ format: 'cjs' }, plugins: buildPlugins + }, + { + input: './src/auto-constants.ts', + output: { + file: './dist/auto-constants.mjs', + format: 'es' + }, + plugins: buildPlugins } ];