From fa2e78a8b6cb211e74c410817b148d05ed15d945 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:22:55 -0600 Subject: [PATCH 1/4] Revert emulator overlay --- common/api-review/util.api.md | 3 - packages/auth/src/core/auth/emulator.ts | 48 +----- packages/database/src/api/Database.ts | 4 +- packages/firestore/src/lite-api/database.ts | 4 +- packages/functions/src/service.ts | 7 +- packages/storage/src/service.ts | 4 +- packages/util/src/emulator.ts | 178 -------------------- 7 files changed, 6 insertions(+), 242 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 4ac51fda550..96695e78d73 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -487,9 +487,6 @@ export interface Subscribe { // @public (undocumented) export type Unsubscribe = () => void; -// @public -export function updateEmulatorBanner(name: string, isRunningEmulator: boolean): void; - // Warning: (ae-missing-release-tag) "validateArgCount" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 15da907286f..36b7a44e853 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -18,12 +18,7 @@ import { Auth } from '../../model/public_types'; import { AuthErrorCode } from '../errors'; import { _assert } from '../util/assert'; import { _castAuth } from './auth_impl'; -import { - deepEqual, - isCloudWorkstation, - pingServer, - updateEmulatorBanner -} from '@firebase/util'; +import { deepEqual, isCloudWorkstation, pingServer } from '@firebase/util'; /** * Changes the {@link Auth} instance to communicate with the Firebase Auth Emulator, instead of production @@ -102,12 +97,9 @@ export function connectAuthEmulator( authInternal.emulatorConfig = emulatorConfig; authInternal.settings.appVerificationDisabledForTesting = true; - // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { + // Workaround to get cookies in Firebase Studio void pingServer(`${protocol}//${host}${portStr}`); - updateEmulatorBanner('Auth', true); - } else if (!disableWarnings) { - emitEmulatorWarning(); } } @@ -146,39 +138,3 @@ function parsePort(portStr: string): number | null { } return port; } - -function emitEmulatorWarning(): void { - function attachBanner(): void { - const el = document.createElement('p'); - const sty = el.style; - el.innerText = - 'Running in emulator mode. Do not use with production credentials.'; - sty.position = 'fixed'; - sty.width = '100%'; - sty.backgroundColor = '#ffffff'; - sty.border = '.1em solid #000000'; - sty.color = '#b50000'; - sty.bottom = '0px'; - sty.left = '0px'; - sty.margin = '0px'; - sty.zIndex = '10000'; - sty.textAlign = 'center'; - el.classList.add('firebase-emulator-warning'); - document.body.appendChild(el); - } - - if (typeof console !== 'undefined' && typeof console.info === 'function') { - console.info( - 'WARNING: You are using the Auth Emulator,' + - ' which is intended for local testing only. Do not use with' + - ' production credentials.' - ); - } - if (typeof window !== 'undefined' && typeof document !== 'undefined') { - if (document.readyState === 'loading') { - window.addEventListener('DOMContentLoaded', attachBanner); - } else { - attachBanner(); - } - } -} diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 338255be46f..515e278b5c5 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -31,8 +31,7 @@ import { EmulatorMockTokenOptions, getDefaultEmulatorHostnameAndPort, isCloudWorkstation, - pingServer, - updateEmulatorBanner + pingServer } from '@firebase/util'; import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider'; @@ -394,7 +393,6 @@ export function connectDatabaseEmulator( // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { void pingServer(host); - updateEmulatorBanner('Database', true); } // Modify the repo to apply emulator settings diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 6af324e4ba4..8e7fdb27e90 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -28,8 +28,7 @@ import { EmulatorMockTokenOptions, getDefaultEmulatorHostnameAndPort, isCloudWorkstation, - pingServer, - updateEmulatorBanner + pingServer } from '@firebase/util'; import { @@ -337,7 +336,6 @@ export function connectFirestoreEmulator( const newHostSetting = `${host}:${port}`; if (useSsl) { void pingServer(`https://${newHostSetting}`); - updateEmulatorBanner('Firestore', true); } if (settings.host !== DEFAULT_HOST && settings.host !== newHostSetting) { logWarn( diff --git a/packages/functions/src/service.ts b/packages/functions/src/service.ts index 6e2eddda3a2..6a0ddeaa8d3 100644 --- a/packages/functions/src/service.ts +++ b/packages/functions/src/service.ts @@ -30,11 +30,7 @@ import { Provider } from '@firebase/component'; import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; import { MessagingInternalComponentName } from '@firebase/messaging-interop-types'; import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; -import { - isCloudWorkstation, - pingServer, - updateEmulatorBanner -} from '@firebase/util'; +import { isCloudWorkstation, pingServer } from '@firebase/util'; export const DEFAULT_REGION = 'us-central1'; @@ -186,7 +182,6 @@ export function connectFunctionsEmulator( // Workaround to get cookies in Firebase Studio if (useSsl) { void pingServer(functionsInstance.emulatorOrigin + '/backends'); - updateEmulatorBanner('Functions', true); } } diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index a4252c77870..7e2090ccd2e 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -46,8 +46,7 @@ import { createMockUserToken, EmulatorMockTokenOptions, isCloudWorkstation, - pingServer, - updateEmulatorBanner + pingServer } from '@firebase/util'; import { Connection, ConnectionType } from './implementation/connection'; @@ -151,7 +150,6 @@ export function connectStorageEmulator( // Workaround to get cookies in Firebase Studio if (useSsl) { void pingServer(`https://${storage.host}/b`); - updateEmulatorBanner('Storage', true); } storage._isUsingEmulator = true; storage._protocol = useSsl ? 'https' : 'http'; diff --git a/packages/util/src/emulator.ts b/packages/util/src/emulator.ts index 1c4d4ae7a7d..2850b5be378 100644 --- a/packages/util/src/emulator.ts +++ b/packages/util/src/emulator.ts @@ -16,7 +16,6 @@ */ import { base64urlEncodeWithoutPadding } from './crypt'; -import { isCloudWorkstation } from './url'; // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. /* eslint-disable camelcase */ @@ -141,180 +140,3 @@ export function createMockUserToken( signature ].join('.'); } - -interface EmulatorStatusMap { - [name: string]: boolean; -} -const emulatorStatus: EmulatorStatusMap = {}; - -interface EmulatorSummary { - prod: string[]; - emulator: string[]; -} - -// Checks whether any products are running on an emulator -function getEmulatorSummary(): EmulatorSummary { - const summary: EmulatorSummary = { - prod: [], - emulator: [] - }; - for (const key of Object.keys(emulatorStatus)) { - if (emulatorStatus[key]) { - summary.emulator.push(key); - } else { - summary.prod.push(key); - } - } - return summary; -} - -function getOrCreateEl(id: string): { created: boolean; element: HTMLElement } { - let parentDiv = document.getElementById(id); - let created = false; - if (!parentDiv) { - parentDiv = document.createElement('div'); - parentDiv.setAttribute('id', id); - created = true; - } - return { created, element: parentDiv }; -} - -let previouslyDismissed = false; -/** - * Updates Emulator Banner. Primarily used for Firebase Studio - * @param name - * @param isRunningEmulator - * @public - */ -export function updateEmulatorBanner( - name: string, - isRunningEmulator: boolean -): void { - if ( - typeof window === 'undefined' || - typeof document === 'undefined' || - !isCloudWorkstation(window.location.host) || - emulatorStatus[name] === isRunningEmulator || - emulatorStatus[name] || // If already set to use emulator, can't go back to prod. - previouslyDismissed - ) { - return; - } - - emulatorStatus[name] = isRunningEmulator; - - function prefixedId(id: string): string { - return `__firebase__banner__${id}`; - } - const bannerId = '__firebase__banner'; - const summary = getEmulatorSummary(); - const showError = summary.prod.length > 0; - - function tearDown(): void { - const element = document.getElementById(bannerId); - if (element) { - element.remove(); - } - } - - function setupBannerStyles(bannerEl: HTMLElement): void { - bannerEl.style.display = 'flex'; - bannerEl.style.background = '#7faaf0'; - bannerEl.style.position = 'fixed'; - bannerEl.style.bottom = '5px'; - bannerEl.style.left = '5px'; - bannerEl.style.padding = '.5em'; - bannerEl.style.borderRadius = '5px'; - bannerEl.style.alignItems = 'center'; - } - - function setupIconStyles(prependIcon: SVGElement, iconId: string): void { - prependIcon.setAttribute('width', '24'); - prependIcon.setAttribute('id', iconId); - prependIcon.setAttribute('height', '24'); - prependIcon.setAttribute('viewBox', '0 0 24 24'); - prependIcon.setAttribute('fill', 'none'); - prependIcon.style.marginLeft = '-6px'; - } - - function setupCloseBtn(): HTMLSpanElement { - const closeBtn = document.createElement('span'); - closeBtn.style.cursor = 'pointer'; - closeBtn.style.marginLeft = '16px'; - closeBtn.style.fontSize = '24px'; - closeBtn.innerHTML = ' ×'; - closeBtn.onclick = () => { - previouslyDismissed = true; - tearDown(); - }; - return closeBtn; - } - - function setupLinkStyles( - learnMoreLink: HTMLAnchorElement, - learnMoreId: string - ): void { - learnMoreLink.setAttribute('id', learnMoreId); - learnMoreLink.innerText = 'Learn more'; - learnMoreLink.href = - 'https://firebase.google.com/docs/studio/preview-apps#preview-backend'; - learnMoreLink.setAttribute('target', '__blank'); - learnMoreLink.style.paddingLeft = '5px'; - learnMoreLink.style.textDecoration = 'underline'; - } - - function setupDom(): void { - const banner = getOrCreateEl(bannerId); - const firebaseTextId = prefixedId('text'); - const firebaseText: HTMLSpanElement = - document.getElementById(firebaseTextId) || document.createElement('span'); - const learnMoreId = prefixedId('learnmore'); - const learnMoreLink: HTMLAnchorElement = - (document.getElementById(learnMoreId) as HTMLAnchorElement) || - document.createElement('a'); - const prependIconId = prefixedId('preprendIcon'); - const prependIcon: SVGElement = - (document.getElementById( - prependIconId - ) as HTMLOrSVGElement as SVGElement) || - document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - if (banner.created) { - // update styles - const bannerEl = banner.element; - setupBannerStyles(bannerEl); - setupLinkStyles(learnMoreLink, learnMoreId); - const closeBtn = setupCloseBtn(); - setupIconStyles(prependIcon, prependIconId); - bannerEl.append(prependIcon, firebaseText, learnMoreLink, closeBtn); - document.body.appendChild(bannerEl); - } - - if (showError) { - firebaseText.innerText = `Preview backend disconnected.`; - prependIcon.innerHTML = ` - - - - - - -`; - } else { - prependIcon.innerHTML = ` - - - - - - -`; - firebaseText.innerText = 'Preview backend running in this workspace.'; - } - firebaseText.setAttribute('id', firebaseTextId); - } - if (document.readyState === 'loading') { - window.addEventListener('DOMContentLoaded', setupDom); - } else { - setupDom(); - } -} From 9cc11560822223e6356355cb19f7f6920b717d52 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:30:20 -0600 Subject: [PATCH 2/4] Re-add emitEmulatorWarning that was not part of the emulator overlay --- packages/auth/src/core/auth/emulator.ts | 40 ++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 36b7a44e853..303444aaa98 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -83,7 +83,7 @@ export function connectAuthEmulator( // once Auth has started to make network requests. _assert( deepEqual(emulator, authInternal.config.emulator) && - deepEqual(emulatorConfig, authInternal.emulatorConfig), + deepEqual(emulatorConfig, authInternal.emulatorConfig), authInternal, AuthErrorCode.EMULATOR_CONFIG_FAILED ); @@ -100,6 +100,8 @@ export function connectAuthEmulator( if (isCloudWorkstation(host)) { // Workaround to get cookies in Firebase Studio void pingServer(`${protocol}//${host}${portStr}`); + } else if (!disableWarnings) { + emitEmulatorWarning(); } } @@ -138,3 +140,39 @@ function parsePort(portStr: string): number | null { } return port; } + +function emitEmulatorWarning(): void { + function attachBanner(): void { + const el = document.createElement('p'); + const sty = el.style; + el.innerText = + 'Running in emulator mode. Do not use with production credentials.'; + sty.position = 'fixed'; + sty.width = '100%'; + sty.backgroundColor = '#ffffff'; + sty.border = '.1em solid #000000'; + sty.color = '#b50000'; + sty.bottom = '0px'; + sty.left = '0px'; + sty.margin = '0px'; + sty.zIndex = '10000'; + sty.textAlign = 'center'; + el.classList.add('firebase-emulator-warning'); + document.body.appendChild(el); + } + + if (typeof console !== 'undefined' && typeof console.info === 'function') { + console.info( + 'WARNING: You are using the Auth Emulator,' + + ' which is intended for local testing only. Do not use with' + + ' production credentials.' + ); + } + if (typeof window !== 'undefined' && typeof document !== 'undefined') { + if (document.readyState === 'loading') { + window.addEventListener('DOMContentLoaded', attachBanner); + } else { + attachBanner(); + } + } +} From 73cdf8a2553385580a624b1c888e0249fef3ccac Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:32:26 -0600 Subject: [PATCH 3/4] formatting --- packages/auth/src/core/auth/emulator.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/auth/src/core/auth/emulator.ts b/packages/auth/src/core/auth/emulator.ts index 303444aaa98..95345269553 100644 --- a/packages/auth/src/core/auth/emulator.ts +++ b/packages/auth/src/core/auth/emulator.ts @@ -83,7 +83,7 @@ export function connectAuthEmulator( // once Auth has started to make network requests. _assert( deepEqual(emulator, authInternal.config.emulator) && - deepEqual(emulatorConfig, authInternal.emulatorConfig), + deepEqual(emulatorConfig, authInternal.emulatorConfig), authInternal, AuthErrorCode.EMULATOR_CONFIG_FAILED ); @@ -164,8 +164,8 @@ function emitEmulatorWarning(): void { if (typeof console !== 'undefined' && typeof console.info === 'function') { console.info( 'WARNING: You are using the Auth Emulator,' + - ' which is intended for local testing only. Do not use with' + - ' production credentials.' + ' which is intended for local testing only. Do not use with' + + ' production credentials.' ); } if (typeof window !== 'undefined' && typeof document !== 'undefined') { From 3c823fa2d64b90fe0325ce92150eddf68f8235cc Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:59:03 -0600 Subject: [PATCH 4/4] remove other references to updateEmulatorBanner --- packages/data-connect/src/api/DataConnect.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/data-connect/src/api/DataConnect.ts b/packages/data-connect/src/api/DataConnect.ts index b7311363784..c25a09039ac 100644 --- a/packages/data-connect/src/api/DataConnect.ts +++ b/packages/data-connect/src/api/DataConnect.ts @@ -24,11 +24,7 @@ import { import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; import { Provider } from '@firebase/component'; -import { - isCloudWorkstation, - pingServer, - updateEmulatorBanner -} from '@firebase/util'; +import { isCloudWorkstation, pingServer } from '@firebase/util'; import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider'; import { Code, DataConnectError } from '../core/error'; @@ -245,7 +241,6 @@ export function connectDataConnectEmulator( // Workaround to get cookies in Firebase Studio if (isCloudWorkstation(host)) { void pingServer(`https://${host}${port ? `:${port}` : ''}`); - updateEmulatorBanner('Data Connect', true); } dc.enableEmulator({ host, port, sslEnabled }); }