Skip to content

feat: discover Firebase Emulator from FIRESTORE_EMULATOR_HOST env vars - #12

Open
dan-nyanko wants to merge 4 commits into
Flowdesktech:masterfrom
dan-nyanko:feat/emulator-env-discovery
Open

feat: discover Firebase Emulator from FIRESTORE_EMULATOR_HOST env vars#12
dan-nyanko wants to merge 4 commits into
Flowdesktech:masterfrom
dan-nyanko:feat/emulator-env-discovery

Conversation

@dan-nyanko

@dan-nyanko dan-nyanko commented Aug 24, 2026

Copy link
Copy Markdown

Summary

FireStudio now discovers a locally running emulator via the standard Emulator Suite environment variables (FIRESTORE_EMULATOR_HOST, FIREBASE_AUTH_EMULATOR_HOST, FIREBASE_STORAGE_EMULATOR_HOST), in addition to the existing hub-locator-file scan. This makes discovery work even when the Emulator Hub (port 4400) is not running — e.g. firebase emulators:start --only firestore, or the gcloud Firestore emulator.

It also derives the project ID from FIRESTORE_EMULATOR_PROJECT / GCLOUD_PROJECT, and normalizes localhost (and wildcard bind addresses) to 127.0.0.1 so clients connect reliably over IPv4.

Problem

Previously, emulator discovery only read the hub locator file hub-<projectId>.json from os.tmpdir(), which is only written when the Emulator Hub is up. Consequences:

  • When a user starts just Firestore (--only firestore, or the gcloud Firestore emulator), the hub file is absent and FIRESTORE_EMULATOR_HOST was never picked up — FireStudio reported no running emulator.
  • The discovered project ID fell back to the generic demo-project, so even when connected, requests targeted the wrong project and returned no data.
  • Hosts like localhost resolve to IPv6 ::1 for gRPC clients and can hang/fail to connect; only 127.0.0.1 connects reliably.

Fix

In electron/controllers/emulatorController.js:

  • scanEnv() — discovers emulators from the standard env vars (authoritative signal of a running emulator) and maps them to a normalized emulator descriptor.
  • parseHostPort() / normalizeHost() — parses host:port and rewrites localhost and wildcard bind addresses (0.0.0.0, ::, [::], ::1) to 127.0.0.1, since clients can't reliably connect to a wildcard/::1 address as a destination.
  • readProjectIdGuess() — best-effort project ID: checks FIRESTORE_EMULATOR_PROJECT / GCLOUD_PROJECT, then .firebaserc (walking up from cwd), falling back to Firebase's conventional demo-project placeholder.
  • scanRunningEmulators() — merges the hub-file scan and scanEnv(), de-duplicating by Firestore host:port so one running emulator isn't reported twice. Exported for reuse.
  • The emulators:scanHub IPC handler now calls scanRunningEmulators().

Testing / verification

  • Confirmed a Firestore-only emulator (FIRESTORE_EMULATOR_HOST / FIRESTORE_EMULATOR_PROJECT) is discovered with the correct project ID and connects over 127.0.0.1, and its collections appear in FireStudio.
  • pnpm run lint, pnpm run format:check, pnpm run typecheck → all pass (controller is plain JS; formatted by prettier).

Notes

  • Env-var discovery is additive — the existing hub-file scan still runs, and results are merged.
  • This branch also includes the localStorage test-shim fix (from fix/tests-localstorage-polyfill) so CI tests pass on runtimes where jsdom doesn't expose localStorage.

jsdom does not reliably expose localStorage across runtimes (e.g. Node 26's
experimental built-in shadows it), causing projectsPersistence/projectsSlice
tests to fail with 'localStorage is undefined'. Add a minimal in-memory shim
guarded by typeof check so it only applies when absent, keeping behavior
identical on environments where jsdom already provides it.
The existing scan only reads the Emulator Hub locator file, which is absent when the emulator is started without the Hub (e.g. firebase emulators:start --only firestore). Add discovery via FIRESTORE_EMULATOR_HOST, FIREBASE_AUTH_EMULATOR_HOST and FIREBASE_STORAGE_EMULATOR_HOST, merged with the hub scan and de-duplicated by Firestore host:port.
…OUD_PROJECT

readProjectIdGuess previously only consulted .firebaserc and fell back to the
generic 'demo-project'. When connecting to a gcloud Firestore emulator (started
with --project <id>), the discovered project id now honors FIRESTORE_EMULATOR_PROJECT
or GCLOUD_PROJECT so it matches the emulator's actual project and returns data.
gRPC clients resolve 'localhost' to IPv6 ::1 and can hang/fail to connect to
the emulator. Rewrite 'localhost' (and wildcard bind addresses) to 127.0.0.1
in normalizeHost so discovered emulator hosts connect reliably over IPv4.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant