-
Notifications
You must be signed in to change notification settings - Fork 0
Email bypass: enable all boolean Remote Config flags for @mobilitydata.org users #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -85,6 +85,14 @@ npx firebase use {project_name_or_alias} | |||||||||||||||||||||
| npx firebase hosting:channel:deploy {channel_name} | ||||||||||||||||||||||
| ``` | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Firebase Remote Configs | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Firebase remoet configs help us toggle new features on and off. Due to the nature of static pages, there are some nuances. For static pages, the remote configs are called and set at build time and will be the same for the remainder of the static page's cache. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| When remote configs change (they rarily do), it is recommended to redploy the app as that will trigger a new cache for all pages, that will include the updated remote configs | ||||||||||||||||||||||
|
||||||||||||||||||||||
| When remote configs change (they rarily do), it is recommended to redploy the app as that will trigger a new cache for all pages, that will include the updated remote configs | |
| When remote configs change (they rarely do), it is recommended to redploy the app as that will trigger a new cache for all pages, that will include the updated remote configs |
Copilot
AI
Apr 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new README section states remote config is “called and set at build time” for static pages, but this PR also introduces server-side caching/revalidation (unstable_cache + revalidateTag) which updates values without a redeploy for dynamic/ISR renders. Consider clarifying that the “build time” limitation only applies to fully static routes, while server-rendered routes will revalidate per the cache settings.
| Firebase remoet configs help us toggle new features on and off. Due to the nature of static pages, there are some nuances. For static pages, the remote configs are called and set at build time and will be the same for the remainder of the static page's cache. | |
| When remote configs change (they rarily do), it is recommended to redploy the app as that will trigger a new cache for all pages, that will include the updated remote configs | |
| What this also means is that client components will be able to access the firebase remote configs using the Context but server components will have to fetch them each time. This isn't a big deal as the firebase remote configs are cached (for 1 hour on the server) | |
| Firebase remote configs help us toggle new features on and off. Due to the nature of static pages, there are some nuances. For fully static pages, the remote configs are fetched and set at build time and will remain the same for the lifetime of that static page cache. | |
| When remote configs change (they rarely do), redeploying the app is recommended for fully static pages because it triggers a new build/cache that includes the updated remote config values. However, this build-time limitation does not apply to server-rendered or revalidated routes: those routes use the server-side cached remote config values and will pick up updates based on the configured cache revalidation behavior, without requiring a full redeploy. | |
| In practice, client components can access the Firebase remote configs through Context, while server components read them on the server. Those server-side values are cached (for example, for up to 1 hour on the server), so they are not refetched on every request unless the cache is revalidated. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,18 @@ | ||
| 'use client'; | ||
|
|
||
| import React, { createContext, type ReactNode, useContext } from 'react'; | ||
| import React, { | ||
| createContext, | ||
| useState, | ||
| useEffect, | ||
| type ReactNode, | ||
| useContext, | ||
| } from 'react'; | ||
| import { | ||
| defaultRemoteConfigValues, | ||
| matchesFeatureFlagBypass, | ||
| type RemoteConfigValues, | ||
| } from '../interface/RemoteConfig'; | ||
| import { useAuthSession } from '../components/AuthSessionProvider'; | ||
|
|
||
| const RemoteConfigContext = createContext<{ | ||
| config: RemoteConfigValues; | ||
|
|
@@ -17,16 +25,41 @@ interface RemoteConfigProviderProps { | |
| config: RemoteConfigValues; | ||
| } | ||
|
|
||
| function applyAdminBypass(config: RemoteConfigValues): RemoteConfigValues { | ||
| const overridden = { ...config }; | ||
| for (const key of Object.keys(overridden) as Array< | ||
| keyof RemoteConfigValues | ||
| >) { | ||
| if (typeof overridden[key] === 'boolean') { | ||
| (overridden as Record<string, unknown>)[key] = true; | ||
| } | ||
| } | ||
| return overridden; | ||
| } | ||
|
Comment on lines
+28
to
+38
|
||
|
|
||
| /** | ||
| * Client-side Remote Config provider that hydrates server-fetched config into React Context. | ||
| * This provider does NOT fetch config - it receives pre-fetched values from the server. | ||
| * Applies admin bypass for @mobilitydata.org users after client-side auth resolves, | ||
| * which ensures correct flags even on statically generated pages. | ||
| */ | ||
| export const RemoteConfigProvider = ({ | ||
| children, | ||
| config, | ||
| }: RemoteConfigProviderProps): React.ReactElement => { | ||
| const { email, isAuthReady } = useAuthSession(); | ||
| const [effectiveConfig, setEffectiveConfig] = useState(config); | ||
|
|
||
| useEffect(() => { | ||
| if (!isAuthReady) return; | ||
| setEffectiveConfig( | ||
| matchesFeatureFlagBypass(email, config.featureFlagBypass) | ||
| ? applyAdminBypass(config) | ||
| : config, | ||
| ); | ||
| }, [email, isAuthReady, config]); | ||
|
|
||
| return ( | ||
| <RemoteConfigContext.Provider value={{ config }}> | ||
| <RemoteConfigContext.Provider value={{ config: effectiveConfig }}> | ||
| {children} | ||
| </RemoteConfigContext.Provider> | ||
| ); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.